diff --git a/src/Jackett.Common/Definitions/anilibria.yml b/src/Jackett.Common/Definitions/anilibria.yml new file mode 100644 index 000000000..075eba1b4 --- /dev/null +++ b/src/Jackett.Common/Definitions/anilibria.yml @@ -0,0 +1,85 @@ +--- +id: anilibria +name: AniLibria +description: "AniLibria is a Public torrent tracker for anime, voiced on russian by AniLibria team" +language: ru-RU +type: public +encoding: UTF-8 +links: + - https://www.anilibria.tv/ + +caps: + categorymappings: + - {id: 1, cat: TV/Anime, desc: Anime} + + modes: + search: [q] + tv-search: [q, season, ep] + +settings: [] + +search: + paths: + # https://github.com/anilibria/docs/blob/master/api_v2.md + - path: "https://api.anilibria.tv/v2/{{ if .Keywords }}searchTitles?filter=names,poster.url,code,torrents.list,season.year&limit=100&search={{ .Keywords }}{{ else }}getUpdates?filter=names,poster.url,code,torrents.list,season.year&limit=100{{ end }}" + response: + type: json + attribute: torrents.list + multiple: true + + keywordsfilters: + # strip season and ep + - name: re_replace + args: ["(?i)(?:[SE]?\\d{1,4}){1,2}$", ""] + + rows: + selector: $ + + fields: + category: + text: 1 + title_ru: + selector: ..names.ru + title_en: + selector: ..names.en + title_alternative: + selector: ..names.alternative + optional: true + year: + selector: ..season.year + quality: + selector: quality.string + series: + selector: series.string + title: + text: "{{ .Result.title_ru }} / {{ .Result.title_en }}{{ if .Result.title_alternative }} / {{ .Result.title_alternative }}{{ else }}{{ end }} [{{ .Result.quality }}] - {{ .Result.series }}" + code: + selector: ..code + details: + text: "{{ .Config.sitelink }}release/{{ .Result.code }}.html" + download: + selector: url + filters: + - name: prepend + args: "{{ .Config.sitelink }}" + poster: + selector: ..poster.url + filters: + - name: prepend + args: "https://static.anilibria.tv/" + seeders: + selector: seeders + leechers: + selector: leechers + grabs: + selector: downloads + date: + # unix + selector: uploaded_timestamp + size: + selector: total_size + downloadvolumefactor: + text: 0 + uploadvolumefactor: + text: 1 +# json api v2 diff --git a/src/Jackett.Common/Indexers/AniLibria.cs b/src/Jackett.Common/Indexers/AniLibria.cs deleted file mode 100644 index d055d31f9..000000000 --- a/src/Jackett.Common/Indexers/AniLibria.cs +++ /dev/null @@ -1,146 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Net; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using Jackett.Common.Models; -using Jackett.Common.Models.IndexerConfig.Bespoke; -using Jackett.Common.Services.Interfaces; -using Jackett.Common.Utils; -using Newtonsoft.Json.Linq; -using NLog; - -namespace Jackett.Common.Indexers -{ - [ExcludeFromCodeCoverage] - public class AniLibria : BaseWebIndexer - { - private static readonly Regex _EpisodeRegex = new Regex(@"(?:[SsEe]?\d{1,4}){1,2}$"); - - public AniLibria(IIndexerConfigurationService configService, Utils.Clients.WebClient wc, Logger l, IProtectionService ps, ICacheService cs) - : base(id: "AniLibria", - name: "AniLibria", - description: "AniLibria is a Public torrent tracker for anime, voiced on russian by AniLibria team", - link: "https://www.anilibria.tv/", - caps: new TorznabCapabilities - { - TvSearchParams = new List - { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep - } - }, - configService: configService, - client: wc, - logger: l, - p: ps, - cacheService: cs, - configData: new ConfigurationDataAniLibria()) - { - Encoding = Encoding.UTF8; - Language = "ru-RU"; - Type = "public"; - - // Configure the category mappings - AddCategoryMapping(1, TorznabCatType.TVAnime, "Anime"); - } - - private ConfigurationDataAniLibria Configuration => (ConfigurationDataAniLibria)configData; - - public override async Task ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - var releases = await PerformQuery(new TorznabQuery()); - - await ConfigureIfOK(string.Empty, releases.Any(), () => - throw new Exception("Could not find releases from this URL")); - - return IndexerConfigurationStatus.Completed; - } - - // If the search string is empty use the latest releases - protected override async Task> PerformQuery(TorznabQuery query) - => query.IsTest || string.IsNullOrWhiteSpace(query.SearchTerm) - ? await FetchNewReleases() - : await PerformSearch(query); - - private async Task> PerformSearch(TorznabQuery query) - { - var title = _EpisodeRegex.Replace(query.SearchTerm, string.Empty).TrimEnd(); - var queryParameters = new NameValueCollection - { - { "filter", "names,poster.url,code,torrents.list,season.year" }, - { "limit", "100" } - }; - var response = await RequestWithCookiesAndRetryAsync(Configuration.ApiLink.Value + "/searchTitles?" + queryParameters.GetQueryString() + "&search=" + Uri.EscapeDataString(title)); - if (response.Status != HttpStatusCode.OK) - throw new WebException($"AniLibria search returned unexpected result. Expected 200 OK but got {response.Status}.", WebExceptionStatus.ProtocolError); - - var results = ParseApiResults(response.ContentString); - return results.Where(release => query.MatchQueryStringAND(release.Title, null, title)); - ; - } - - private async Task> FetchNewReleases() - { - var queryParameters = new NameValueCollection - { - { "limit", "100" }, - { "filter", "names,poster.url,code,torrents.list,season.year" } - }; - var response = await RequestWithCookiesAndRetryAsync(Configuration.ApiLink.Value + "/getUpdates?" + queryParameters.GetQueryString()); - if (response.Status != HttpStatusCode.OK) - throw new WebException($"AniLibria search returned unexpected result. Expected 200 OK but got {response.Status}.", WebExceptionStatus.ProtocolError); - - return ParseApiResults(response.ContentString); - } - - private string composeTitle(dynamic json) - { - var title = json.names.ru; - title += " / " + json.names.en; - if (json.alternative is string) - title += " / " + json.names.alternative; - title += " " + json.season.year; - return title; - } - - private List ParseApiResults(string json) - { - var releases = new List(); - foreach (dynamic r in JArray.Parse(json)) - { - var baseRelease = new ReleaseInfo - { - Title = composeTitle(r), - Poster = new Uri(Configuration.StaticLink.Value + r.poster.url), - Details = new Uri(SiteLink + "/release/" + r.code + ".html"), - DownloadVolumeFactor = 0, - UploadVolumeFactor = 1, - Category = new[] - { - TorznabCatType.TVAnime.ID - } - }; - foreach (var t in r.torrents.list) - { - var release = (ReleaseInfo)baseRelease.Clone(); - release.Title += " [" + t.quality["string"] + "] - " + t.series["string"]; - release.Size = t.total_size; - release.Seeders = t.seeders; - release.Peers = t.leechers + t.seeders; - release.Grabs = t.downloads; - release.Link = new Uri(SiteLink + t.url); - release.Guid = new Uri(SiteLink + t.url); - release.PublishDate = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(Convert.ToDouble(t.uploaded_timestamp)).ToLocalTime(); - releases.Add(release); - } - } - - return releases; - } - } -} diff --git a/src/Jackett.Common/Models/IndexerConfig/Bespoke/ConfigurationDataAniLibria.cs b/src/Jackett.Common/Models/IndexerConfig/Bespoke/ConfigurationDataAniLibria.cs deleted file mode 100644 index 477eb1a71..000000000 --- a/src/Jackett.Common/Models/IndexerConfig/Bespoke/ConfigurationDataAniLibria.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Diagnostics.CodeAnalysis; - -namespace Jackett.Common.Models.IndexerConfig.Bespoke -{ - [ExcludeFromCodeCoverage] - internal class ConfigurationDataAniLibria : ConfigurationData - { - public StringConfigurationItem ApiLink { get; private set; } - public StringConfigurationItem StaticLink { get; private set; } - - public ConfigurationDataAniLibria() : base() - { - ApiLink = new StringConfigurationItem("API Url") - { - Value = "https://api.anilibria.tv/v2/" - }; - StaticLink = new StringConfigurationItem("Static Url") - { - Value = "https://static.anilibria.tv/" - }; - } - } -}