1
0
Fork 0
mirror of https://github.com/Jackett/Jackett synced 2024-12-29 11:17:22 +00:00

anidex: rewrite in C# to bypass DDOS. resolves #7036 resolves #6834 (#7142)

* Replace Cardigann Anidex indexer for C# impelementation

Add bypass for DDOS Guard

* Improve error messages from type conversions

* Add missing cookie check

* Fix index out of range exception

* Change error handling to only warn about DDoS bypass exceptions

This is so that searches will still be attempted if there are issues with the DDoS protection (e.g. if it is removed).

* Improve error handling and clean up code

* pending changes
This commit is contained in:
Diego Heras 2020-02-09 03:43:32 +01:00 committed by GitHub
parent c12da520a4
commit e2310ea70b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 427 additions and 215 deletions

View file

@ -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):<br>19 :Arabic<br>22 :Bengali<br>14 :Bulgarian<br>21 :Chinese (Simplified)<br>24 :Czech<br>20 :Danish<br>5 :Dutch<br>1 :English<br>11 :Finnish<br>10 :French<br>8 :German<br>13 :Greek<br>9 :Hungarian<br>27 :Indonesian<br>6 :Italian<br>2 :Japanese<br>28 :Korean<br>31 :Malaysian<br>25 :Mongolian<br>30 :Persian<br>3 :Polish<br>16 :Portuguese (Brazil)<br>17 :Portuguese (Portugal)<br>23 :Romanian<br>7 :Russian<br>4 :Serbo-Croatian<br>29 :Spanish (LATAM)<br>15 :Spanish (Spain)<br>18 :Swedish<br>26 :Turkish<br>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

View file

@ -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<string, string>()
{
{"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<string, string>()
{
{"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<string, string>()
{
{"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<IndexerConfigurationStatus> 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<IEnumerable<ReleaseInfo>> 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<ReleaseInfo> ParseResult(string response)
{
const string rowSelector = "div#content table > tbody > tr";
try
{
var resultParser = new HtmlParser();
var resultDocument = resultParser.ParseDocument(response);
IEnumerable<IElement> rows = resultDocument.QuerySelectorAll(rowSelector);
var releases = new List<ReleaseInfo>();
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<KeyValuePair<string, string>>
{
{ "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<string, string> 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<TResult>(IElement row, string propertyName, string selector,
Func<IElement, TResult> 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}");
}
}
}
}

View file

@ -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)