コード例 #1
0
        private async Task <SubtitleResponse> GetSubtitlesInternal(string id,
                                                                   SubtitleOptions options,
                                                                   CancellationToken cancellationToken)
        {
            if (string.IsNullOrWhiteSpace(id))
            {
                throw new ArgumentNullException("id");
            }

            if (_dailyDownloadCount >= MaxDownloadsPerDay &&
                !options.IsOpenSubtitleVipAccount)
            {
                throw new InvalidOperationException("Open Subtitle's daily download limit has been exceeded. Please try again tomorrow.");
            }

            var idParts = id.Split(new[] { '-' }, 3);

            var format   = idParts[0];
            var language = idParts[1];
            var ossId    = idParts[2];

            var downloadsList = new[] { int.Parse(ossId, _usCulture) };

            await Login(cancellationToken).ConfigureAwait(false);

            var resultDownLoad = await OpenSubtitles.DownloadSubtitlesAsync(downloadsList, cancellationToken).ConfigureAwait(false);

            if (!(resultDownLoad is MethodResponseSubtitleDownload))
            {
                throw new ApplicationException("Invalid response type");
            }

            var results = ((MethodResponseSubtitleDownload)resultDownLoad).Results;

            if (results.Count == 0)
            {
                var msg = string.Format("Subtitle with Id {0} was not found. Name: {1}. Status: {2}. Message: {3}",
                                        ossId,
                                        resultDownLoad.Name ?? string.Empty,
                                        resultDownLoad.Message ?? string.Empty,
                                        resultDownLoad.Status ?? string.Empty);

                throw new ResourceNotFoundException(msg);
            }

            var data = Convert.FromBase64String(results.First().Data);

            return(new SubtitleResponse
            {
                Format = format,
                Language = language,

                Stream = new MemoryStream(Utilities.Decompress(new MemoryStream(data)))
            });
        }
コード例 #2
0
        public OpenSubtitleDownloader(ILogManager logManager, IHttpClient httpClient, IServerConfigurationManager config, IEncryptionManager encryption, IJsonSerializer json)
        {
            _logger     = logManager.GetLogger(GetType().Name);
            _httpClient = httpClient;
            _config     = config;
            _encryption = encryption;
            _json       = json;

            _config.NamedConfigurationUpdating += _config_NamedConfigurationUpdating;

            Utilities.HttpClient = httpClient;
            OpenSubtitles.SetUserAgent("mediabrowser.tv");
        }
コード例 #3
0
        public OpenSubtitleDownloader(ILoggerFactory loggerFactory, IHttpClient httpClient, IServerConfigurationManager config, IJsonSerializer json, IFileSystem fileSystem)
        {
            _logger     = loggerFactory.CreateLogger(GetType().Name);
            _httpClient = httpClient;
            _config     = config;
            _json       = json;
            _fileSystem = fileSystem;

            _config.NamedConfigurationUpdating += _config_NamedConfigurationUpdating;

            Utilities.HttpClient = httpClient;
            OpenSubtitles.SetUserAgent("jellyfin");
        }
コード例 #4
0
        public OpenSubtitleDownloader(ILogManager logManager, IHttpClient httpClient, IServerConfigurationManager config, IEncryptionManager encryption, IJsonSerializer json)
        {
            _logger     = logManager.GetLogger(GetType().Name);
            _httpClient = httpClient;
            _config     = config;
            _encryption = encryption;
            _json       = json;

            _config.NamedConfigurationUpdating += _config_NamedConfigurationUpdating;

            // Reset the count every 24 hours
            _dailyTimer = new Timer(state => _dailyDownloadCount = 0, null, TimeSpan.FromHours(24), TimeSpan.FromHours(24));

            Utilities.HttpClient = httpClient;
            OpenSubtitles.SetUserAgent("mediabrowser.tv");
        }
コード例 #5
0
        public async Task <IEnumerable <NameIdPair> > GetSupportedLanguages(CancellationToken cancellationToken)
        {
            await Login(cancellationToken).ConfigureAwait(false);

            var result = OpenSubtitles.GetSubLanguages("en");

            if (!(result is MethodResponseGetSubLanguages))
            {
                _logger.Error("Invalid response type");
                return(new List <NameIdPair>());
            }

            var results = ((MethodResponseGetSubLanguages)result).Languages;

            return(results.Select(i => new NameIdPair
            {
                Name = i.LanguageName,
                Id = i.SubLanguageID
            }));
        }
コード例 #6
0
        private async Task Login(CancellationToken cancellationToken)
        {
            if ((DateTime.UtcNow - _lastLogin).TotalSeconds < 60)
            {
                return;
            }

            var options = GetOptions();

            var user     = options.OpenSubtitlesUsername ?? string.Empty;
            var password = DecryptPassword(options.OpenSubtitlesPasswordHash);

            var loginResponse = await OpenSubtitles.LogInAsync(user, password, "en", cancellationToken).ConfigureAwait(false);

            if (!(loginResponse is MethodResponseLogIn))
            {
                throw new Exception("Authentication to OpenSubtitles failed.");
            }

            _lastLogin = DateTime.UtcNow;
        }
コード例 #7
0
        public async Task <IEnumerable <RemoteSubtitleInfo> > Search(SubtitleSearchRequest request, CancellationToken cancellationToken)
        {
            var  imdbIdText = request.GetProviderId(MetadataProviders.Imdb);
            long imdbId     = 0;

            switch (request.ContentType)
            {
            case VideoContentType.Episode:
                if (!request.IndexNumber.HasValue || !request.ParentIndexNumber.HasValue || string.IsNullOrEmpty(request.SeriesName))
                {
                    _logger.Debug("Episode information missing");
                    return(new List <RemoteSubtitleInfo>());
                }
                break;

            case VideoContentType.Movie:
                if (string.IsNullOrEmpty(request.Name))
                {
                    _logger.Debug("Movie name missing");
                    return(new List <RemoteSubtitleInfo>());
                }
                if (string.IsNullOrWhiteSpace(imdbIdText) || !long.TryParse(imdbIdText.TrimStart('t'), NumberStyles.Any, _usCulture, out imdbId))
                {
                    _logger.Debug("Imdb id missing");
                    return(new List <RemoteSubtitleInfo>());
                }
                break;
            }

            if (string.IsNullOrEmpty(request.MediaPath))
            {
                _logger.Debug("Path Missing");
                return(new List <RemoteSubtitleInfo>());
            }

            await Login(cancellationToken).ConfigureAwait(false);

            var subLanguageId            = NormalizeLanguage(request.Language);
            var hash                     = Utilities.ComputeHash(request.MediaPath);
            var fileInfo                 = new FileInfo(request.MediaPath);
            var movieByteSize            = fileInfo.Length;
            var searchImdbId             = request.ContentType == VideoContentType.Movie ? imdbId.ToString(_usCulture) : "";
            var subtitleSearchParameters = request.ContentType == VideoContentType.Episode
                ? new List <SubtitleSearchParameters> {
                new SubtitleSearchParameters(subLanguageId,
                                             query: request.SeriesName,
                                             season: request.ParentIndexNumber.Value.ToString(_usCulture),
                                             episode: request.IndexNumber.Value.ToString(_usCulture))
            }
                : new List <SubtitleSearchParameters> {
                new SubtitleSearchParameters(subLanguageId, imdbid: searchImdbId),
                new SubtitleSearchParameters(subLanguageId, query: request.Name, imdbid: searchImdbId)
            };
            var parms = new List <SubtitleSearchParameters> {
                new SubtitleSearchParameters(subLanguageId,
                                             movieHash: hash,
                                             movieByteSize: movieByteSize,
                                             imdbid: searchImdbId),
            };

            parms.AddRange(subtitleSearchParameters);
            var result = await OpenSubtitles.SearchSubtitlesAsync(parms.ToArray(), cancellationToken).ConfigureAwait(false);

            if (!(result is MethodResponseSubtitleSearch))
            {
                _logger.Error("Invalid response type");
                return(new List <RemoteSubtitleInfo>());
            }

            Predicate <SubtitleSearchResult> mediaFilter =
                x =>
                request.ContentType == VideoContentType.Episode
                        ? !string.IsNullOrEmpty(x.SeriesSeason) && !string.IsNullOrEmpty(x.SeriesEpisode) &&
                int.Parse(x.SeriesSeason, _usCulture) == request.ParentIndexNumber &&
                int.Parse(x.SeriesEpisode, _usCulture) == request.IndexNumber
                        : !string.IsNullOrEmpty(x.IDMovieImdb) && long.Parse(x.IDMovieImdb, _usCulture) == imdbId;

            var results = ((MethodResponseSubtitleSearch)result).Results;

            // Avoid implicitly captured closure
            var hasCopy = hash;

            return(results.Where(x => x.SubBad == "0" && mediaFilter(x) && (!request.IsPerfectMatch || string.Equals(x.MovieHash, hash, StringComparison.OrdinalIgnoreCase)))
                   .OrderBy(x => (string.Equals(x.MovieHash, hash, StringComparison.OrdinalIgnoreCase) ? 0 : 1))
                   .ThenBy(x => Math.Abs(long.Parse(x.MovieByteSize, _usCulture) - movieByteSize))
                   .ThenByDescending(x => int.Parse(x.SubDownloadsCnt, _usCulture))
                   .ThenByDescending(x => double.Parse(x.SubRating, _usCulture))
                   .Select(i => new RemoteSubtitleInfo
            {
                Author = i.UserNickName,
                Comment = i.SubAuthorComment,
                CommunityRating = float.Parse(i.SubRating, _usCulture),
                DownloadCount = int.Parse(i.SubDownloadsCnt, _usCulture),
                Format = i.SubFormat,
                ProviderName = Name,
                ThreeLetterISOLanguageName = i.SubLanguageID,

                Id = i.SubFormat + "-" + i.SubLanguageID + "-" + i.IDSubtitleFile,

                Name = i.SubFileName,
                DateCreated = DateTime.Parse(i.SubAddDate, _usCulture),
                IsHashMatch = i.MovieHash == hasCopy
            }).Where(i => !string.Equals(i.Format, "sub", StringComparison.OrdinalIgnoreCase) && !string.Equals(i.Format, "idx", StringComparison.OrdinalIgnoreCase)));
        }
コード例 #8
0
        private async Task <SubtitleResponse> GetSubtitlesInternal(string id,
                                                                   SubtitleOptions options,
                                                                   CancellationToken cancellationToken)
        {
            if (string.IsNullOrWhiteSpace(id))
            {
                throw new ArgumentNullException("id");
            }

            var idParts = id.Split(new[] { '-' }, 3);

            var format   = idParts[0];
            var language = idParts[1];
            var ossId    = idParts[2];

            var downloadsList = new[] { int.Parse(ossId, _usCulture) };

            await Login(cancellationToken).ConfigureAwait(false);

            if ((DateTime.UtcNow - _lastRateLimitException).TotalHours < 1)
            {
                throw new ApplicationException("OpenSubtitles rate limit reached");
            }

            var resultDownLoad = await OpenSubtitles.DownloadSubtitlesAsync(downloadsList, cancellationToken).ConfigureAwait(false);

            if ((resultDownLoad.Status ?? string.Empty).IndexOf("407", StringComparison.OrdinalIgnoreCase) != -1)
            {
                _lastRateLimitException = DateTime.UtcNow;
                throw new ApplicationException("OpenSubtitles rate limit reached");
            }

            if (!(resultDownLoad is MethodResponseSubtitleDownload))
            {
                throw new ApplicationException("Invalid response type");
            }

            var results = ((MethodResponseSubtitleDownload)resultDownLoad).Results;

            _lastRateLimitException = DateTime.MinValue;

            if (results.Count == 0)
            {
                var msg = string.Format("Subtitle with Id {0} was not found. Name: {1}. Status: {2}. Message: {3}",
                                        ossId,
                                        resultDownLoad.Name ?? string.Empty,
                                        resultDownLoad.Status ?? string.Empty,
                                        resultDownLoad.Message ?? string.Empty);

                throw new ResourceNotFoundException(msg);
            }

            var data = Convert.FromBase64String(results.First().Data);

            return(new SubtitleResponse
            {
                Format = format,
                Language = language,

                Stream = new MemoryStream(Utilities.Decompress(new MemoryStream(data)))
            });
        }
コード例 #9
0
        public async Task <ItemUpdateType> GetSubtitle(Episode item, CancellationToken cancellationToken)
        {
            _logger.Debug("Start with: " + item.Name);
            if (!Supports(item))
            {
                _logger.Debug("Not Supported");
                return(ItemUpdateType.None);
            }
            _logger.Debug("Supported");

            if (!item.IndexNumber.HasValue || !item.ParentIndexNumber.HasValue)
            {
                _logger.Debug("Information Missing");
                return(ItemUpdateType.None);
            }
            if (string.IsNullOrEmpty(item.Path))
            {
                _logger.Debug("Path Missing");
                return(ItemUpdateType.None);
            }
            OpenSubtitles.SetUserAgent("OS Test User Agent");
            var loginResponse = OpenSubtitles.LogIn("", "", "en");

            if (!(loginResponse is MethodResponseLogIn))
            {
                _logger.Debug("Login error");
                return(ItemUpdateType.None);
            }
            var user = _userManager.Users.Where(u =>
            {
                var subtitleUser = UserHelper.GetUser(u);

                return(subtitleUser != null && subtitleUser.SubtitleLocations != null &&
                       subtitleUser.SubtitleLocations.Length > 0);
            }).Select(UserHelper.GetUser).First();
            var subLanguageId = user.SubtitleLanguage;

            _logger.Debug("User language: " + subLanguageId);
            var hash          = Utilities.ComputeHash(item.Path);
            var fileInfo      = new FileInfo(item.Path);
            var movieByteSize = fileInfo.Length;

            _logger.Debug(string.Format("{0} - {1} - {2}", subLanguageId, hash, movieByteSize));
            _logger.Debug(string.Format("{0} - {1} - {2} - {3}", subLanguageId, item.SeriesName, item.ParentIndexNumber.Value.ToString(), item.IndexNumber.Value.ToString()));

            var parms = new List <SubtitleSearchParameters> {
                new SubtitleSearchParameters(subLanguageId, hash, movieByteSize),
                new SubtitleSearchParameters(subLanguageId, item.SeriesName, item.ParentIndexNumber.Value.ToString(), item.IndexNumber.Value.ToString()),
            };
            var result = OpenSubtitles.SearchSubtitles(parms.ToArray());

            if (!(result is MethodResponseSubtitleSearch))
            {
                _logger.Debug("invalid response type");
                return(ItemUpdateType.None);
            }
            var downloadedSubtitles = new List <Subtitle>(Plugin.Instance.PluginConfiguration.DownloadedSubtitles);
            var results             = ((MethodResponseSubtitleSearch)result).Results;
            var bestResult          = results.Where(x => x.SubBad == "0" && int.Parse(x.SeriesSeason) == item.ParentIndexNumber && int.Parse(x.SeriesEpisode) == item.IndexNumber)
                                      .Where(x => downloadedSubtitles.All(y => y.IdSubtitle != x.IDSubtitle))
                                      .OrderBy(x => x.MovieHash == hash)
                                      .ThenBy(x => Math.Abs(long.Parse(x.MovieByteSize) - movieByteSize))
                                      .ThenByDescending(x => int.Parse(x.SubDownloadsCnt))
                                      .ThenByDescending(x => double.Parse(x.SubRating))
                                      .ToList();

            if (!bestResult.Any())
            {
                _logger.Debug("No Subtitles");
                return(ItemUpdateType.None);
            }
            _logger.Debug("Found " + bestResult.Count + " subtitles.");

            var subtitle      = bestResult.First();
            var downloadsList = new[] { int.Parse(subtitle.IDSubtitleFile) };

            var resultDownLoad = OpenSubtitles.DownloadSubtitles(downloadsList);

            if (!(resultDownLoad is MethodResponseSubtitleDownload))
            {
                _logger.Debug("invalid response type");
                return(ItemUpdateType.None);
            }
            if (!((MethodResponseSubtitleDownload)resultDownLoad).Results.Any())
            {
                _logger.Debug("No Subtitle Downloads");
                return(ItemUpdateType.None);
            }
            var res    = ((MethodResponseSubtitleDownload)resultDownLoad).Results.First();
            var data   = Convert.FromBase64String(res.Data);
            var target = Utilities.Decompress(new MemoryStream(data));
            // now save the subtitle
            var fileName = Path.Combine(fileInfo.DirectoryName, string.Format("{0}.{1}.srt", Path.GetFileNameWithoutExtension(fileInfo.Name), subtitle.SubLanguageID));

            Stream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write);

            stream.Write(target, 0, target.Length);
            stream.Close();
            _logger.Debug("Subtitles downloaded: " + subtitle.SubFileName);
            var configuration = Plugin.Instance.Configuration;

            downloadedSubtitles.Add(new Subtitle {
                IdSubtitle = subtitle.IDSubtitle, Date = DateTime.Now, SubtitleFileName = subtitle.SubFileName
            });
            configuration.DownloadedSubtitles = downloadedSubtitles.ToArray();
            Plugin.Instance.UpdateConfiguration(configuration);
            return(ItemUpdateType.MetadataEdit);
        }