diff --git a/src/Jackett.Common/Definitions/anidex.yml b/src/Jackett.Common/Definitions/anidex.yml deleted file mode 100644 index c6d29c9f8..000000000 --- a/src/Jackett.Common/Definitions/anidex.yml +++ /dev/null @@ -1,108 +0,0 @@ ---- - site: anidex - name: Anidex - description: "Anidex is a Public torrent tracker and indexer, primarily for English fansub groups of anime" - language: en-us - encoding: UTF-8 - type: public - links: - - https://anidex.info/ - - caps: - categorymappings: - - {id: 1, cat: TV/Anime, desc: "Anime - Sub"} - - {id: 2, cat: TV/Anime, desc: "Anime - Raw"} - - {id: 3, cat: TV/Anime, desc: "Anime - Dub"} - - {id: 4, cat: TV/Anime, desc: "LA - Sub"} - - {id: 5, cat: TV/Anime, desc: "LA - Raw"} - - {id: 6, cat: TV/Anime, desc: "Light Novel"} - - {id: 7, cat: TV/Anime, desc: "Manga - TLed"} - - {id: 8, cat: TV/Anime, desc: "Manga - Raw"} - - {id: 9, cat: TV/Anime, desc: "♫ - Lossy"} - - {id: 10, cat: TV/Anime, desc: "♫ - Lossless"} - - {id: 11, cat: TV/Anime, desc: "♫ - Video"} - - {id: 12, cat: TV/Anime, desc: "Games"} - - {id: 13, cat: TV/Anime, desc: "Applications"} - - {id: 14, cat: TV/Anime, desc: "Pictures"} - - {id: 15, cat: TV/Anime, desc: "Adult Video"} - - {id: 16, cat: TV/Anime, desc: "Other"} - - modes: - search: [q] - tv-search: [q, season, ep] - - settings: - - name: lang-id - type: text - label: Language ID - - name: info - type: info - label: Language ID Note - default: "You can filter your searches using any of the following language ID (comma delimited):
19 :Arabic
22 :Bengali
14 :Bulgarian
21 :Chinese (Simplified)
24 :Czech
20 :Danish
5 :Dutch
1 :English
11 :Finnish
10 :French
8 :German
13 :Greek
9 :Hungarian
27 :Indonesian
6 :Italian
2 :Japanese
28 :Korean
31 :Malaysian
25 :Mongolian
30 :Persian
3 :Polish
16 :Portuguese (Brazil)
17 :Portuguese (Portugal)
23 :Romanian
7 :Russian
4 :Serbo-Croatian
29 :Spanish (LATAM)
15 :Spanish (Spain)
18 :Swedish
26 :Turkish
12 :Vietnamese" - - name: sort - type: select - label: Sort requested from site - default: "upload_timestamp" - options: - "upload_timestamp": "created" - "seeders": "seeders" - "size": "size" - "filename": "title" - - name: type - type: select - label: Order requested from site - default: "desc" - options: - "desc": "desc" - "asc": "asc" - - search: - paths: - # https://anidex.info/?page=search&id=1,2,3&lang_id=5,1,10&group_id=0&q=rinshi - - path: "?page=search&id={{ if .Categories }}{{ range .Categories }},{{.}}{{end}}{{else}}0{{end}}{{ if .Config.lang-id }}&lang_id={{ .Config.lang-id }}{{else}}{{end}}&group_id=0&q={{ if .Keywords }}{{ .Keywords }}{{else}}{{end}}&s={{ .Config.sort }}&o={{ .Config.type }}" - - rows: - selector: div.table-responsive > table > tbody > tr - - fields: - category: - selector: a[href^="/?id="] - attribute: href - filters: - - name: querystring - args: id - title: - selector: td:nth-child(3) > a.torrent > span.span-1440 - filters: - - name: re_replace # remove anidb id from return string - args: ["(\\[[A-Z0-9]*\\])\\.", "."] - details: - selector: td:nth-child(3) > a.torrent - attribute: href - download: - selector: td:nth-child(5) > a - attribute: href - magnet: - selector: a[href^="magnet:?"] - attribute: href - size: - selector: td:nth-child(7) - date: - selector: td:nth-child(8) - attribute: title - filters: - - name: replace - args: ["UTC", "+00:00"] - - name: dateparse - args: "2006-01-02 15:04:05 -07:00" - seeders: - selector: td:nth-child(9) - leechers: - selector: td:nth-child(10) - grabs: - selector: td:nth-child(11) - downloadvolumefactor: - text: 0 - uploadvolumefactor: - text: 1 -# engine n/a diff --git a/src/Jackett.Common/Indexers/Anidex.cs b/src/Jackett.Common/Indexers/Anidex.cs new file mode 100644 index 000000000..2f26da13f --- /dev/null +++ b/src/Jackett.Common/Indexers/Anidex.cs @@ -0,0 +1,319 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using AngleSharp.Dom; +using AngleSharp.Html.Parser; +using Jackett.Common.Models; +using Jackett.Common.Models.IndexerConfig; +using Jackett.Common.Services.Interfaces; +using Jackett.Common.Utils; +using Newtonsoft.Json.Linq; +using NLog; +using static Jackett.Common.Models.IndexerConfig.ConfigurationData; + +namespace Jackett.Common.Indexers +{ + public class Anidex : BaseWebIndexer + { + public Anidex(IIndexerConfigurationService configService, Utils.Clients.WebClient wc, Logger l, IProtectionService ps) + : base(name: "Anidex", + description: "Anidex is a Public torrent tracker and indexer, primarily for English fansub groups of anime", + link: "https://anidex.info/", + caps: new TorznabCapabilities(), + configService: configService, + client: wc, + logger: l, + p: ps, + configData: new ConfigurationData()) + { + Encoding = Encoding.UTF8; + Language = "en-us"; + Type = "public"; + + // Configure the category mappings + AddCategoryMapping(1, TorznabCatType.TVAnime, "Anime - Sub"); + AddCategoryMapping(2, TorznabCatType.TVAnime, "Anime - Raw"); + AddCategoryMapping(3, TorznabCatType.TVAnime, "Anime - Dub"); + AddCategoryMapping(4, TorznabCatType.TVAnime, "LA - Sub"); + AddCategoryMapping(5, TorznabCatType.TVAnime, "LA - Raw"); + AddCategoryMapping(6, TorznabCatType.TVAnime, "Light Novel"); + AddCategoryMapping(7, TorznabCatType.TVAnime, "Manga - TLed"); + AddCategoryMapping(8, TorznabCatType.TVAnime, "Manga - Raw"); + AddCategoryMapping(9, TorznabCatType.TVAnime, "♫ - Lossy"); + AddCategoryMapping(10, TorznabCatType.TVAnime, "♫ - Lossless"); + AddCategoryMapping(11, TorznabCatType.TVAnime, "♫ - Video"); + AddCategoryMapping(12, TorznabCatType.TVAnime, "Games"); + AddCategoryMapping(13, TorznabCatType.TVAnime, "Applications"); + AddCategoryMapping(14, TorznabCatType.TVAnime, "Pictures"); + AddCategoryMapping(15, TorznabCatType.TVAnime, "Adult Video"); + AddCategoryMapping(16, TorznabCatType.TVAnime, "Other"); + + // Configure the language select option + var languageSelect = new SelectItem(new Dictionary() + { + {"1", "English"}, + {"2", "Japanese"}, + {"3", "Polish"}, + {"4", "Serbo-Croatian" }, + {"5", "Dutch"}, + {"6", "Italian"}, + {"7", "Russian"}, + {"8", "German"}, + {"9", "Hungarian"}, + {"10", "French"}, + {"11", "Finnish"}, + {"12", "Vietnamese"}, + {"13", "Greek"}, + {"14", "Bulgarian"}, + {"15", "Spanish (Spain)" }, + {"16", "Portuguese (Brazil)" }, + {"17", "Portuguese (Portugal)" }, + {"18", "Swedish"}, + {"19", "Arabic"}, + {"20", "Danish"}, + {"21", "Chinese (Simplified)" }, + {"22", "Bengali"}, + {"23", "Romanian"}, + {"24", "Czech"}, + {"25", "Mongolian"}, + {"26", "Turkish"}, + {"27", "Indonesian"}, + {"28", "Korean"}, + {"29", "Spanish (LATAM)" }, + {"30", "Persian"}, + {"31", "Malaysian"} + }) { Name = "Language", Value = "1" }; + configData.AddDynamic("languageid", languageSelect); + + // Configure the sort selects + var sortBySelect = new SelectItem(new Dictionary() + { + {"upload_timestamp", "created"}, + {"seeders", "seeders"}, + {"size", "size"}, + {"filename", "title"} + }) { Name = "Sort by", Value = "upload_timestamp" }; + configData.AddDynamic("sortrequestedfromsite", sortBySelect); + + var orderSelect = new SelectItem(new Dictionary() + { + {"desc", "Descending"}, + {"asc", "Ascending"} + }) + { Name = "Order", Value = "desc" }; + configData.AddDynamic("orderrequestedfromsite", orderSelect); + } + + private string GetSortBy => ((SelectItem)configData.GetDynamic("sortrequestedfromsite")).Value; + + private string GetOrder => ((SelectItem)configData.GetDynamic("orderrequestedfromsite")).Value; + + private Uri GetAbsoluteUrl(string relativeUrl) => new Uri(SiteLink + relativeUrl.TrimStart('/')); + + 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; + } + + protected override async Task> PerformQuery(TorznabQuery query) + { + try + { + await ConfigureDDoSGuardCookie(); + } + catch (Exception ex) + { + logger.Log(LogLevel.Warn, ex, $"Exception while configuring DDoS Guard cookie. Attempting search without. (Exception: {ex})"); + } + + // Get specified categories. If none were specified, use all available. + var searchCategories = MapTorznabCapsToTrackers(query); + if (searchCategories.Count == 0) + searchCategories = GetAllTrackerCategories(); + + // Prepare the search query + var queryParameters = new NameValueCollection + { + { "page", "search" }, + { "id", string.Join(",", searchCategories) }, + { "group", "0" }, // No group + { "q", query.SearchTerm ?? string.Empty }, + { "s", GetSortBy }, + { "o", GetOrder } + }; + + // Make search request + var searchUri = GetAbsoluteUrl("?" + queryParameters.GetQueryString()); + var response = await RequestStringWithCookiesAndRetry(searchUri.AbsoluteUri); + + // Check for DDOS Guard or other error + if (response.Status == System.Net.HttpStatusCode.Forbidden) + throw new IOException("Anidex search was forbidden. This was likely caused by DDOS protection."); + + if (response.Status != System.Net.HttpStatusCode.OK) + throw new IOException($"Anidex search returned unexpected result. Expected 200 OK but got {response.Status.ToString()}."); + + // Search seems to have been a success so parse it + return ParseResult(response.Content); + } + + private IEnumerable ParseResult(string response) + { + const string rowSelector = "div#content table > tbody > tr"; + + try + { + var resultParser = new HtmlParser(); + var resultDocument = resultParser.ParseDocument(response); + IEnumerable rows = resultDocument.QuerySelectorAll(rowSelector); + + var releases = new List(); + foreach (var r in rows) + try + { + var release = new ReleaseInfo(); + + release.Category = ParseValueFromRow(r, nameof(release.Category), "td:nth-child(1) a", (e) => MapTrackerCatToNewznab(e.Attributes["href"].Value.Substring(5))); + release.Title = ParseStringValueFromRow(r, nameof(release.Title), "td:nth-child(3) span"); + release.Link = ParseValueFromRow(r, nameof(release.Link), "a[href^=\"/dl/\"]", (e) => GetAbsoluteUrl(e.Attributes["href"].Value)); + release.MagnetUri = ParseValueFromRow(r, nameof(release.MagnetUri), "a[href^=\"magnet:?\"]", (e) => new Uri(e.Attributes["href"].Value)); + release.Size = ParseValueFromRow(r, nameof(release.Size), "td:nth-child(7)", (e) => ReleaseInfo.GetBytes(e.Text())); + release.PublishDate = ParseValueFromRow(r, nameof(release.PublishDate), "td:nth-child(8)", (e) => DateTime.ParseExact(e.Attributes["title"].Value, "yyyy-MM-dd HH:mm:ss UTC", CultureInfo.InvariantCulture)); + release.Seeders = ParseIntValueFromRow(r, nameof(release.Seeders), "td:nth-child(9)"); + release.Peers = ParseIntValueFromRow(r, nameof(release.Peers), "td:nth-child(10)") + release.Seeders; + release.Grabs = ParseIntValueFromRow(r, nameof(release.Grabs), "td:nth-child(11)"); + release.Comments = ParseValueFromRow(r, nameof(release.Comments), "td:nth-child(3) a", (e) => GetAbsoluteUrl(e.Attributes["href"].Value)); + release.Guid = release.Comments; + release.MinimumRatio = 1; + release.MinimumSeedTime = 172800; // 48 hours + release.DownloadVolumeFactor = 0; + release.UploadVolumeFactor = 1; + + releases.Add(release); + } + catch (Exception ex) + { + logger.Error($"Anidex: Error parsing search result row '{r.ToHtmlPretty()}':\n\n{ex}"); + } + + return releases; + } + catch (Exception ex) + { + throw new IOException($"Error parsing search result page: {ex}"); + } + } + + private async Task ConfigureDDoSGuardCookie() + { + const string pathAndQueryBase64Encoded = "Lw=="; // "/" + const string baseUriBase64Encoded = "aHR0cHM6Ly9hbmlkZXguaW5mbw=="; // "http://anidex.info" + const string ddosPostUrl = "https://ddgu.ddos-guard.net/ddgu/"; + + try + { + // Check if the cookie already exists, if so exit without doing anything + if (IsCookiePresent("__ddgu") && IsCookiePresent("__ddg1")) + { + logger.Debug("DDOS Guard cookies are already present. Skipping bypass."); + return; + } + + // Make a request to DDoS Guard to get the redirect URL + var ddosPostData = new List> + { + { "u", pathAndQueryBase64Encoded }, + { "h", baseUriBase64Encoded }, + { "p", string.Empty } + }; + + var result = await PostDataWithCookiesAndRetry(ddosPostUrl, ddosPostData); + + if (!result.IsRedirect) + // Success returns a redirect. For anything else, assume a failure. + throw new IOException($"Unexpected result from DDOS Guard while attempting to bypass: {result.Content}"); + + // Call the redirect URL to retrieve the cookie + result = await RequestStringWithCookiesAndRetry(result.RedirectingTo); + if (!result.IsRedirect) + // Success is another redirect. For anything else, assume a failure. + throw new IOException($"Unexpected result when returning from DDOS Guard bypass: {result.Content}"); + + // If we got to this point, the bypass should have succeeded and we have stored the necessary cookies to access the site normally. + } + catch (Exception ex) + { + throw new IOException($"Error while configuring DDoS Guard cookie: {ex}"); + } + } + + private bool IsCookiePresent(string name) + { + var rawCookies = CookieHeader.Split(';'); + IDictionary cookies = rawCookies + .Where(e => e.Contains('=')) + .ToDictionary((e) => e.Split('=')[0].Trim(), (e) => e.Split('=')[1].Trim()); + + return cookies.ContainsKey(name); + } + + private static TResult ParseValueFromRow(IElement row, string propertyName, string selector, + Func parseFunction) + { + try + { + var selectedElement = row.QuerySelector(selector); + if (selectedElement == null) + throw new IOException($"Unable to find '{selector}'."); + + return parseFunction(selectedElement); + } + catch (Exception ex) + { + throw new IOException($"Error parsing for property '{propertyName}': {ex.Message}"); + } + } + + private static string ParseStringValueFromRow(IElement row, string propertyName, string selector) + { + try + { + var selectedElement = row.QuerySelector(selector); + if (selectedElement == null) + throw new IOException($"Unable to find '{selector}'."); + + return selectedElement.Text(); + } + catch (Exception ex) + { + throw new IOException($"Error parsing for property '{propertyName}': {ex.Message}"); + } + } + + private static int ParseIntValueFromRow(IElement row, string propertyName, string selector) + { + try + { + var text = ParseStringValueFromRow(row, propertyName, selector); + if (!int.TryParse(text, out var value)) + throw new IOException($"Could not convert '{text}' to int."); + return value; + } + catch (Exception ex) + { + throw new IOException($"Error parsing for property '{propertyName}': {ex.Message}"); + } + } + } +} diff --git a/src/Jackett.Updater/Program.cs b/src/Jackett.Updater/Program.cs index 4ef4f4160..42ceb71f8 100644 --- a/src/Jackett.Updater/Program.cs +++ b/src/Jackett.Updater/Program.cs @@ -267,49 +267,118 @@ namespace Jackett.Updater // delete old files string[] oldFiles = new string[] { + "appsettings.Development.json", + "Autofac.Integration.WebApi.dll", + "Content/congruent_outline.png", + "Content/crissXcross.png", "Content/css/jquery.dataTables.css", "Content/css/jquery.dataTables_themeroller.css", - "Definitions/tspate.yml", - "Definitions/freakstrackingsystem.yml", - "Definitions/rarbg.yml", - "Definitions/t411.yml", - "Definitions/hdbc.yml", // renamed to hdbitscom - "Definitions/maniatorrent.yml", - "Definitions/nyaa.yml", - "Definitions/nachtwerk.yml", - "Definitions/leparadisdunet.yml", - "Definitions/qctorrent.yml", - "Definitions/dragonworld.yml", - "Definitions/hdclub.yml", - "Definitions/polishtracker.yml", - "Definitions/zetorrents.yml", - "Definitions/rapidetracker.yml", - "Definitions/isohunt.yml", - "Definitions/t411v2.yml", - "Definitions/bithq.yml", - "Definitions/blubits.yml", - "Definitions/torrentproject.yml", - "Definitions/torrentvault.yml", - "Definitions/apollo.yml", // migrated to C# gazelle base tracker - "Definitions/secretcinema.yml", // migrated to C# gazelle base tracker - "Definitions/utorrents.yml", // same as SzeneFZ now - "Definitions/ultrahdclub.yml", - "Definitions/infinityt.yml", - "Definitions/hachede-c.yml", - "Definitions/skytorrents.yml", - "Definitions/gormogon.yml", - "Definitions/czteam.yml", - "Definitions/rockhardlossless.yml", - "Definitions/tehconnection.yml", - "Definitions/torrentwtf.yml", - "Definitions/eotforum.yml", - "Definitions/nexttorrent.yml", - "Definitions/torrentsmd.yml", - "Definitions/scenehd.yml", // migrated to C# (use JSON API) - "appsettings.Development.json", "CurlSharp.dll", "CurlSharp.pdb", - "Autofac.Integration.WebApi.dll", + "Definitions/420files.yml", + "Definitions/aox.yml", + "Definitions/anidex.yml", // migrated to C# + "Definitions/apollo.yml", // migrated to C# gazelle base tracker + "Definitions/archetorrent.yml", + "Definitions/asiandvdclub.yml", + "Definitions/avg.yml", + "Definitions/b2s-share.yml", + "Definitions/bithq.yml", + "Definitions/bitme.yml", + "Definitions/blubits.yml", + "Definitions/bt-scene.yml", + "Definitions/btbit.yml", + "Definitions/btkitty.yml", + "Definitions/btstornet.yml", + "Definitions/btxpress.yml", + "Definitions/cinefilhd.yml", + "Definitions/czteam.yml", + "Definitions/dark-shadow.yml", + "Definitions/digbt.yml", + "Definitions/dragonworld.yml", + "Definitions/dreamteam.yml", + "Definitions/elitehd.yml", + "Definitions/elittracker.yml", + "Definitions/eotforum.yml", + "Definitions/evolutionpalace.yml", + "Definitions/extratorrent-ag.yml", + "Definitions/extratorrentclone.yml", + "Definitions/freakstrackingsystem.yml", + "Definitions/freedomhd.yml", + "Definitions/gdf76.yml", + "Definitions/gfxnews.yml", + "Definitions/gods.yml", + "Definitions/gormogon.yml", + "Definitions/hachede-c.yml", + "Definitions/hd4free.yml", + "Definitions/hdbc.yml", // renamed to hdbitscom + "Definitions/hdclub.yml", + "Definitions/hdplus.yml", + "Definitions/hon3yhd-net.yml", + "Definitions/horriblesubs.yml", + "Definitions/hyperay.yml", + "Definitions/idopeclone.yml", + "Definitions/iloveclassics.yml", + "Definitions/infinityt.yml", + "Definitions/isohunt.yml", + "Definitions/katcrs.yml", + "Definitions/kikibt.yml", + "Definitions/lapausetorrents.yml", + "Definitions/lechaudron.yml", + "Definitions/lemencili.yml", + "Definitions/leparadisdunet.yml", + "Definitions/maniatorrent.yml", + "Definitions/manicomioshare.yml", + "Definitions/megabliz.yml", + "Definitions/mkvcage.yml", + "Definitions/music-master.yml", + "Definitions/nachtwerk.yml", + "Definitions/nexttorrent.yml", + "Definitions/nyaa.yml", + "Definitions/nyoo.yml", + "Definitions/passionetorrent.yml", + "Definitions/polishtracker.yml", + "Definitions/qctorrent.yml", + "Definitions/qxr.yml", + "Definitions/rapidetracker.yml", + "Definitions/rarbg.yml", + "Definitions/redtopia.yml", + "Definitions/rgu.yml", + "Definitions/rockethd.yml", + "Definitions/rockhardlossless.yml", + "Definitions/scenehd.yml", // migrated to C# (use JSON API) + "Definitions/scenereactor.yml", + "Definitions/secretcinema.yml", // migrated to C# gazelle base tracker + "Definitions/sharingue.yml", + "Definitions/skytorrents.yml", + "Definitions/solidtorrents.yml", // migrated to C# + "Definitions/speed-share.yml", + "Definitions/t411.yml", + "Definitions/t411v2.yml", + "Definitions/tazmaniaden.yml", + "Definitions/tbplus.yml", + "Definitions/tehconnection.yml", + "Definitions/themoviecave.yml", + "Definitions/thetorrents.yml", + "Definitions/tigers-dl.yml", + "Definitions/tntvillage.yml", + "Definitions/torrentcouch.yml", + "Definitions/torrentkim.yml", + "Definitions/torrentproject.yml", + "Definitions/torrentsmd.yml", + "Definitions/torrentvault.yml", + "Definitions/torrentwtf.yml", + "Definitions/torrof.yml", + "Definitions/torviet.yml", + "Definitions/tspate.yml", + "Definitions/ultimategamerclub.yml", + "Definitions/ultrahdclub.yml", + "Definitions/utorrents.yml", // same as SzeneFZ now + "Definitions/waffles.yml", + "Definitions/worldofp2p.yml", + "Definitions/worldwidetorrents.yml", + "Definitions/xktorrent.yml", + "Definitions/zetorrents.yml", "Microsoft.Owin.dll", "Microsoft.Owin.FileSystems.dll", "Microsoft.Owin.Host.HttpListener.dll", @@ -319,74 +388,6 @@ namespace Jackett.Updater "System.Web.Http.dll", "System.Web.Http.Owin.dll", "System.Web.Http.Tracing.dll", - "Definitions/torrentkim.yml", - "Definitions/horriblesubs.yml", - "Definitions/bt-scene.yml", - "Definitions/extratorrentclone.yml", - "Definitions/torrentcouch.yml", - "Definitions/idopeclone.yml", - "Definitions/torrof.yml", - "Definitions/archetorrent.yml", - "Definitions/420files.yml", - "Definitions/redtopia.yml", - "Definitions/btxpress.yml", - "Definitions/btstornet.yml", - "Definitions/hdplus.yml", - "Definitions/gods.yml", - "Definitions/freedomhd.yml", - "Definitions/sharingue.yml", - "Definitions/cinefilhd.yml", - "Definitions/tbplus.yml", - "Definitions/manicomioshare.yml", - "Definitions/speed-share.yml", - "Definitions/b2s-share.yml", - "Definitions/nyoo.yml", - "Definitions/ultimategamerclub.yml", - "Definitions/evolutionpalace.yml", - "Definitions/qxr.yml", - "Definitions/gfxnews.yml", - "Definitions/megabliz.yml", - "Definitions/tigers-dl.yml", - "Definitions/worldwidetorrents.yml", - "Definitions/tntvillage.yml", - "Definitions/xktorrent.yml", - "Definitions/btkitty.yml", - "Definitions/kikibt.yml", - "Definitions/rockethd.yml", - "Definitions/worldofp2p.yml", - "Definitions/avg.yml", - "Definitions/aox.yml", - "Definitions/dreamteam.yml", - "Definitions/elitehd.yml", - "Definitions/gdf76.yml", - "Definitions/hyperay.yml", - "Definitions/scenereactor.yml", - "Definitions/lapausetorrents.yml", - "Definitions/lechaudron.yml", - "Definitions/katcrs.yml", - "Definitions/iloveclassics.yml", - "Definitions/hd4free.yml", - "Definitions/lemencili.yml", - "Definitions/btbit.yml", - "Definitions/digbt.yml", - "Definitions/mkvcage.yml", - "Content/congruent_outline.png", - "Content/crissXcross.png", - "Definitions/dark-shadow.yml", - "Definitions/bitme.yml", - "Definitions/asiandvdclub.yml", - "Definitions/music-master.yml", - "Definitions/torviet.yml", - "Definitions/waffles.yml", - "Definitions/rgu.yml", - "Definitions/elittracker.yml", - "Definitions/hon3yhd-net.yml", - "Definitions/solidtorrents.yml", - "Definitions/extratorrent-ag.yml", - "Definitions/passionetorrent.yml", - "Definitions/thetorrents.yml", - "Definitions/themoviecave.yml", - "Definitions/tazmaniaden.yml", }; foreach (var oldFile in oldFiles)