Exemplo n.º 1
0
        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>());
            }
        }
Exemplo n.º 2
0
        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>());
            }
        }
Exemplo n.º 3
0
        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);
        }
Exemplo n.º 6
0
        public string Normalize(string language)
        {
            if (string.IsNullOrWhiteSpace(language))
            {
                return(language);
            }

            var culture = _localizationManager?.FindLanguageInfo(language.AsSpan());

            return(culture != null
                ? culture.ThreeLetterISOLanguageName
                : language);
        }
Exemplo n.º 7
0
        /// <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);
                }
            }
        }
Exemplo n.º 8
0
        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>());
        }
Exemplo n.º 9
0
        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 });
        }
Exemplo n.º 10
0
        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());
        }
Exemplo n.º 11
0
        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
                    });
                }
            }
        }
Exemplo n.º 12
0
        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);
        }