public async Task <IEnumerable <RemoteSubtitleInfo> > Search(SubtitleSearchRequest request, CancellationToken cancellationToken) { var language = _localizationManager.FindLanguageInfo(request.Language); if (language == null || !string.Equals(language.TwoLetterISOLanguageName, "PL", StringComparison.OrdinalIgnoreCase)) { return(Array.Empty <RemoteSubtitleInfo>()); } var mediaPath = request.MediaPath; _logger.LogInformation($"Reading {mediaPath}"); var hash = await NapiCore.GetHash(request.MediaPath, cancellationToken, _fileSystem); _logger.LogInformation($"Computed hash {hash} of {mediaPath} for NapiSub"); var requestMessage = NapiCore.CreateRequest(hash, language.TwoLetterISOLanguageName); try { using (var response = await _httpClient.SendAsync(requestMessage).ConfigureAwait(false)) { var xml = await response.Content.ReadAsStringAsync().ConfigureAwait(false); var status = XmlParser.GetStatusFromXml(xml); _logger.LogInformation($"Response status: {status}"); if (status != null && status == "success") { _logger.LogInformation("Subtitles found by NapiSub"); return(new List <RemoteSubtitleInfo> { new RemoteSubtitleInfo { IsHashMatch = true, ProviderName = Name, Id = hash, Name = "A subtitle matched by hash", ThreeLetterISOLanguageName = language.ThreeLetterISOLanguageName, Format = "srt" } }); } _logger.LogInformation("No subtitles found by NapiSub"); return(new List <RemoteSubtitleInfo>()); } } catch (Exception) { return(new List <RemoteSubtitleInfo>()); } }
public async Task <IEnumerable <RemoteSubtitleInfo> > Search(SubtitleSearchRequest request, CancellationToken cancellationToken) { var language = _localizationManager.FindLanguageInfo(request.Language.AsSpan()); if (language == null || !string.Equals(language.TwoLetterISOLanguageName, "PL", StringComparison.OrdinalIgnoreCase)) { return(Array.Empty <RemoteSubtitleInfo>()); } var hash = await NapiCore.GetHash(request.MediaPath, cancellationToken, _fileSystem, _logger).ConfigureAwait(false); var opts = NapiCore.CreateRequest(hash, language.TwoLetterISOLanguageName); try { using (var response = await _httpClient.Post(opts).ConfigureAwait(false)) { using (var reader = new StreamReader(response.Content)) { var xml = await reader.ReadToEndAsync().ConfigureAwait(false); var status = XmlParser.GetStatusFromXml(xml); if (status != null && status == "success") { _logger.Info("Subtitles found by NapiSub"); return(new List <RemoteSubtitleInfo> { new RemoteSubtitleInfo { IsHashMatch = true, ProviderName = Name, Id = hash, Name = "A subtitle matched by hash", ThreeLetterISOLanguageName = language.ThreeLetterISOLanguageName, Format = "srt" } }); } } _logger.Info("No subtitles found by NapiSub"); return(new List <RemoteSubtitleInfo>()); } } catch (HttpException ex) { if (!ex.StatusCode.HasValue || ex.StatusCode.Value != HttpStatusCode.NotFound) { throw; } _logger.Debug("ERROR"); return(new List <RemoteSubtitleInfo>()); } }
public async Task <IEnumerable <RemoteSubtitleInfo> > Search(SubtitleSearchRequest request, CancellationToken cancellationToken) { var lang = _localizationManager.FindLanguageInfo(request.Language.AsSpan()); if (request.IsForced.HasValue || request.IsPerfectMatch || GetLanguageId(lang) == null) { return(Array.Empty <RemoteSubtitleInfo>()); } if (await Login()) { BaseItem item = _libraryManager.FindByPath(request.MediaPath, false); var legendatvIds = FindIds(request, item, cancellationToken); var searchTasks = new List <Task <IEnumerable <RemoteSubtitleInfo> > >(); Action <string> addSearchTask; switch (request.ContentType) { // Series Episode case VideoContentType.Episode: { addSearchTask = (id) => { searchTasks.Add(Search(item.Id, cancellationToken, itemId: id, lang: lang, query: $"S{request.ParentIndexNumber:D02}E{request.IndexNumber:D02}")); searchTasks.Add(Search(item.Id, cancellationToken, itemId: id, lang: lang, query: $"{request.ParentIndexNumber:D02}x{request.IndexNumber:D02}")); }; break; } // Movie default: case VideoContentType.Movie: { addSearchTask = (id) => { searchTasks.Add(Search(item.Id, cancellationToken, lang: lang, itemId: id)); }; break; } } foreach (var id in legendatvIds) { addSearchTask(id); } await Task.WhenAll(searchTasks); return(searchTasks.SelectMany(t => t.Result)); } else { return(Array.Empty <RemoteSubtitleInfo>()); } }
private string NormalizeLanguage(string language) { if (string.IsNullOrWhiteSpace(language)) { var culture = _localizationManager?.FindLanguageInfo(language.AsSpan()); if (culture != null) { return(culture.ThreeLetterISOLanguageName); } } return(language); }
private string NormalizeLanguage(string language) { if (language != null) { var culture = _localizationManager.FindLanguageInfo(language); if (culture != null) { return(culture.ThreeLetterISOLanguageName); } } return(language); }
public string Normalize(string language) { if (string.IsNullOrWhiteSpace(language)) { return(language); } var culture = _localizationManager?.FindLanguageInfo(language.AsSpan()); return(culture != null ? culture.ThreeLetterISOLanguageName : language); }
/// <summary> /// Returns the audio streams found in the external audio files for the given video. /// </summary> /// <param name="video">The video to get the external audio streams from.</param> /// <param name="startIndex">The stream index to start adding audio streams at.</param> /// <param name="directoryService">The directory service to search for files.</param> /// <param name="clearCache">True if the directory service cache should be cleared before searching.</param> /// <param name="cancellationToken">The cancellation token to cancel operation.</param> /// <returns>A list of external audio streams.</returns> public async IAsyncEnumerable <MediaStream> GetExternalAudioStreams( Video video, int startIndex, IDirectoryService directoryService, bool clearCache, [EnumeratorCancellation] CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (!video.IsFileProtocol) { yield break; } IEnumerable <string> paths = GetExternalAudioFiles(video, directoryService, clearCache); foreach (string path in paths) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path); Model.MediaInfo.MediaInfo mediaInfo = await GetMediaInfo(path, cancellationToken).ConfigureAwait(false); foreach (MediaStream mediaStream in mediaInfo.MediaStreams) { mediaStream.Index = startIndex++; mediaStream.Type = MediaStreamType.Audio; mediaStream.IsExternal = true; mediaStream.Path = path; mediaStream.IsDefault = false; mediaStream.Title = null; if (string.IsNullOrEmpty(mediaStream.Language)) { // Try to translate to three character code // Be flexible and check against both the full and three character versions var language = StringExtensions.RightPart(fileNameWithoutExtension, '.').ToString(); if (language != fileNameWithoutExtension) { var culture = _localizationManager.FindLanguageInfo(language); language = culture == null ? language : culture.ThreeLetterISOLanguageName; mediaStream.Language = language; } } yield return(mediaStream); } } }
private string[] NormalizeLanguage(string language) { if (language != null) { var culture = _localizationManager.FindLanguageInfo(language); if (culture != null) { return(culture.ThreeLetterISOLanguageNames); } return(new string[] { language }); } return(Array.Empty <string>()); }
private IReadOnlyList <string> NormalizeLanguage(string language) { if (string.IsNullOrEmpty(language)) { return(Array.Empty <string>()); } var culture = _localizationManager.FindLanguageInfo(language); if (culture != null) { return(culture.ThreeLetterISOLanguageNames); } return(new string[] { language }); }
public async Task <RemoteSubtitleInfo[]> SearchSubtitles(SubtitleSearchRequest request, CancellationToken cancellationToken) { if (request.Language != null) { var culture = _localization.FindLanguageInfo(request.Language); if (culture != null) { request.TwoLetterISOLanguageName = culture.TwoLetterISOLanguageName; } } var contentType = request.ContentType; var providers = _subtitleProviders .Where(i => i.SupportedMediaTypes.Contains(contentType) && !request.DisabledSubtitleFetchers.Contains(i.Name, StringComparison.OrdinalIgnoreCase)) .OrderBy(i => { var index = request.SubtitleFetcherOrder.ToList().IndexOf(i.Name); return(index == -1 ? int.MaxValue : index); }) .ToArray(); // If not searching all, search one at a time until something is found if (!request.SearchAllProviders) { foreach (var provider in providers) { try { var searchResults = await provider.Search(request, cancellationToken).ConfigureAwait(false); var list = searchResults.ToArray(); if (list.Length > 0) { Normalize(list); return(list); } } catch (Exception ex) { _logger.LogError(ex, "Error downloading subtitles from {Provider}", provider.Name); } } return(Array.Empty <RemoteSubtitleInfo>()); } var tasks = providers.Select(async i => { try { var searchResults = await i.Search(request, cancellationToken).ConfigureAwait(false); var list = searchResults.ToArray(); Normalize(list); return(list); } catch (Exception ex) { _logger.LogError(ex, "Error downloading subtitles from {0}", i.Name); return(Array.Empty <RemoteSubtitleInfo>()); } }); var results = await Task.WhenAll(tasks).ConfigureAwait(false); return(results.SelectMany(i => i).ToArray()); }
public void AddExternalSubtitleStreams(List <MediaStream> streams, string videoPath, int startIndex, string[] files) { var videoFileNameWithoutExtension = _fileSystem.GetFileNameWithoutExtension(videoPath); videoFileNameWithoutExtension = NormalizeFilenameForSubtitleComparison(videoFileNameWithoutExtension); foreach (var fullName in files) { var extension = Path.GetExtension(fullName); if (!SubtitleExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)) { continue; } var fileNameWithoutExtension = _fileSystem.GetFileNameWithoutExtension(fullName); fileNameWithoutExtension = NormalizeFilenameForSubtitleComparison(fileNameWithoutExtension); if (!string.Equals(videoFileNameWithoutExtension, fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase) && !fileNameWithoutExtension.StartsWith(videoFileNameWithoutExtension + ".", StringComparison.OrdinalIgnoreCase)) { continue; } var codec = Path.GetExtension(fullName).ToLower().TrimStart('.'); if (string.Equals(codec, "txt", StringComparison.OrdinalIgnoreCase)) { codec = "srt"; } // If the subtitle file matches the video file name if (string.Equals(videoFileNameWithoutExtension, fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase)) { streams.Add(new MediaStream { Index = startIndex++, Type = MediaStreamType.Subtitle, IsExternal = true, Path = fullName, Codec = codec }); } else if (fileNameWithoutExtension.StartsWith(videoFileNameWithoutExtension + ".", StringComparison.OrdinalIgnoreCase)) { var isForced = fullName.IndexOf(".forced.", StringComparison.OrdinalIgnoreCase) != -1 || fullName.IndexOf(".foreign.", StringComparison.OrdinalIgnoreCase) != -1; var isDefault = fullName.IndexOf(".default.", StringComparison.OrdinalIgnoreCase) != -1; // Support xbmc naming conventions - 300.spanish.srt var language = fileNameWithoutExtension .Replace(".forced", string.Empty, StringComparison.OrdinalIgnoreCase) .Replace(".foreign", string.Empty, StringComparison.OrdinalIgnoreCase) .Replace(".default", string.Empty, StringComparison.OrdinalIgnoreCase) .Split('.') .LastOrDefault(); // Try to translate to three character code // Be flexible and check against both the full and three character versions var culture = _localization.FindLanguageInfo(language); if (culture != null) { language = culture.ThreeLetterISOLanguageName; } streams.Add(new MediaStream { Index = startIndex++, Type = MediaStreamType.Subtitle, IsExternal = true, Path = fullName, Codec = codec, Language = language, IsForced = isForced, IsDefault = isDefault }); } } }
public static SearchInfo GetSearchInfo( SubtitleSearchRequest request, ILocalizationManager localize, ILibraryManager lib, string episode_format = "", string season_format = "", Dictionary <string, string> inconsistentTvs = null, Dictionary <string, string> inconsistentMovies = null ) { var res = new SearchInfo(); res.VideoType = request.ContentType; #if EMBY res.LanguageInfo = localize.FindLanguageInfo(request.Language.AsSpan()); #else res.LanguageInfo = localize.FindLanguageInfo(request.Language); #endif res.Lang = res.LanguageInfo.TwoLetterISOLanguageName.ToLower(); BaseItem libItem = lib.FindByPath(request.MediaPath, false); if (libItem == null) { return(res); } if (res.VideoType == VideoContentType.Movie) { Movie mv = libItem as Movie; MediaStream media = mv.GetDefaultVideoStream(); if (media != null) { res.VideoFps = media.AverageFrameRate; } res.SearchText = !String.IsNullOrEmpty(mv.OriginalTitle) ? mv.OriginalTitle : mv.Name; if (inconsistentMovies != null) { res.SearchText = inconsistentMovies.Aggregate(res.SearchText, (current, value) => Regex.Replace(current, Regex.Escape(value.Key), value.Value, RegexOptions.IgnoreCase)); } mv.ProviderIds.TryGetValue("Imdb", out res.ImdbId); res.TitleMovie = res.SearchText; res.MvInfo = Parser.Movie.ParsePath(mv.Path); if (res.MvInfo != null && res.MvInfo.Year == 0) { res.MvInfo.Year = request.ProductionYear ?? 0; } } else if (res.VideoType == VideoContentType.Episode && !String.IsNullOrEmpty(episode_format)) { res.SeasonNumber = request.ParentIndexNumber; res.EpisodeNumber = request.IndexNumber; Episode ep = libItem as Episode; MediaStream media = ep.GetDefaultVideoStream(); if (media != null) { res.VideoFps = media.AverageFrameRate; } string title = !String.IsNullOrEmpty(ep.Series.OriginalTitle) ? ep.Series.OriginalTitle : ep.Series.Name; if (inconsistentTvs != null) { title = inconsistentTvs.Aggregate(title, (current, value) => Regex.Replace(current, Regex.Escape(value.Key), value.Value, RegexOptions.IgnoreCase)); } // episode format {0} - series name, {1} - season, {2} - episode if (res.SeasonNumber != null && res.EpisodeNumber != null) { res.SearchText = String.Format(episode_format, title, res.SeasonNumber, res.EpisodeNumber); } // season format {0} - series name, {1} - season if (res.SeasonNumber != null) { res.SearchSeason = String.Format(season_format, title, res.SeasonNumber); } string titleEp = !String.IsNullOrEmpty(ep.OriginalTitle) ? ep.OriginalTitle : ep.Name; if (titleEp.ContainsIgnoreCase(title)) { res.SearchEpByName = titleEp; } else { res.SearchEpByName = String.Format("{0} {1}", title, titleEp); } ep.Series.ProviderIds.TryGetValue("Imdb", out res.ImdbId); ep.ProviderIds.TryGetValue("Imdb", out res.ImdbIdEpisode); res.TitleSeries = title; res.TitleMovie = res.SearchEpByName; res.EpInfo = Parser.Episode.ParsePath(ep.Path); if (res.EpInfo != null && res.EpInfo.SeriesTitleInfo.Year == 0) { res.EpInfo.SeriesTitleInfo.Year = request.ProductionYear ?? 0; } } res.SearchText = res.SearchText.Replace(':', ' ').Replace(" ", " "); res.SearchEpByName = res.SearchEpByName.Replace(':', ' ').Replace(" ", " "); var regexImdbId = new Regex(@"tt(\d+)"); if (!String.IsNullOrWhiteSpace(res.ImdbId)) { var match = regexImdbId.Match(res.ImdbId); if (match.Success && match.Groups.Count > 1) { res.ImdbIdInt = int.Parse(match.Groups[1].ToString()); } } if (!String.IsNullOrWhiteSpace(res.ImdbIdEpisode)) { var match = regexImdbId.Match(res.ImdbIdEpisode); if (match.Success && match.Groups.Count > 1) { res.ImdbIdEpisodeInt = int.Parse(match.Groups[1].ToString()); } } res.Year = request.ProductionYear; return(res); }