From e3766edc56665875cf952556c969e5748781798b Mon Sep 17 00:00:00 2001 From: ThomasAmpen Date: Thu, 25 Jun 2015 19:48:48 +0200 Subject: [PATCH 1/2] Showrss All.rss support --- src/Jackett/Indexers/ShowRSS.cs | 176 +++++++++++++++++++++++ src/Jackett/Indexers/Torrentz.cs | 23 ++- src/Jackett/Jackett.csproj | 2 + src/Jackett/WebContent/logos/showrss.png | Bin 0 -> 7560 bytes 4 files changed, 195 insertions(+), 6 deletions(-) create mode 100644 src/Jackett/Indexers/ShowRSS.cs create mode 100644 src/Jackett/WebContent/logos/showrss.png diff --git a/src/Jackett/Indexers/ShowRSS.cs b/src/Jackett/Indexers/ShowRSS.cs new file mode 100644 index 000000000..50518f893 --- /dev/null +++ b/src/Jackett/Indexers/ShowRSS.cs @@ -0,0 +1,176 @@ +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Xml; + +namespace Jackett.Indexers +{ + public class ShowRSS : IndexerInterface + { + public event Action OnSaveConfigurationRequested; + + public event Action OnResultParsingError; + + public string DisplayName + { + get { return "ShowRSS"; } + } + + public string DisplayDescription + { + get { return "showRSS is a service that allows you to keep track of your favorite TV shows"; } + } + + public Uri SiteLink + { + get { return new Uri(DefaultUrl); } + } + + const string DefaultUrl = "http://showrss.info"; + const string searchAllUrl = DefaultUrl + "/feeds/all.rss"; + string BaseUrl; + static string chromeUserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36"; + + CookieContainer cookies; + HttpClientHandler handler; + HttpClient client; + + public bool IsConfigured + { + get; + private set; + } + + public ShowRSS() + { + IsConfigured = false; + cookies = new CookieContainer(); + handler = new HttpClientHandler + { + CookieContainer = cookies, + AllowAutoRedirect = true, + UseCookies = true, + }; + client = new HttpClient(handler); + } + + public Task GetConfigurationForSetup() + { + var config = new ConfigurationDataUrl(DefaultUrl); + return Task.FromResult(config); + } + + public async Task ApplyConfiguration(Newtonsoft.Json.Linq.JToken configJson) + { + var config = new ConfigurationDataUrl(DefaultUrl); + config.LoadValuesFromJson(configJson); + + var formattedUrl = config.GetFormattedHostUrl(); + var releases = await PerformQuery(new TorznabQuery(), formattedUrl); + if (releases.Length == 0) + throw new Exception("Could not find releases from this URL"); + + BaseUrl = formattedUrl; + + var configSaveData = new JObject(); + configSaveData["base_url"] = BaseUrl; + + if (OnSaveConfigurationRequested != null) + OnSaveConfigurationRequested(this, configSaveData); + + IsConfigured = true; + } + + public void LoadFromSavedConfiguration(Newtonsoft.Json.Linq.JToken jsonConfig) + { + BaseUrl = (string)jsonConfig["base_url"]; + IsConfigured = true; + } + + public async Task PerformQuery(TorznabQuery query) + { + return await PerformQuery(query, BaseUrl); + } + + public Task Download(Uri link) + { + throw new NotImplementedException(); + } + + private WebClient getWebClient() + { + WebClient wc = new WebClient(); + WebHeaderCollection headers = new WebHeaderCollection(); + headers.Add("User-Agent", chromeUserAgent); + wc.Headers = headers; + return wc; + } + + async Task PerformQuery(TorznabQuery query, string baseUrl) + { + List releases = new List(); + + foreach (var title in query.ShowTitles ?? new string[] { string.Empty }) + { + var searchString = title + " " + query.GetEpisodeSearchString(); + var episodeSearchUrl = string.Format(searchAllUrl); + + XmlDocument xmlDoc = new XmlDocument(); + string xml = string.Empty; + WebClient wc = getWebClient(); + + try + { + using (wc) + { + xml = wc.DownloadString(episodeSearchUrl); + xmlDoc.LoadXml(xml); + } + + ReleaseInfo release; + TorrentzHelper td; + string serie_title; + + foreach (XmlNode node in xmlDoc.GetElementsByTagName("item")) + { + release = new ReleaseInfo(); + + release.MinimumRatio = 1; + release.MinimumSeedTime = 172800; + + serie_title = node.SelectSingleNode("title").InnerText; + release.Title = serie_title; + + release.Comments = new Uri(node.SelectSingleNode("link").InnerText); + release.Category = node.SelectSingleNode("title").InnerText; + var test = node.SelectSingleNode("enclosure"); + release.Guid = new Uri(test.Attributes["url"].Value); + release.PublishDate = DateTime.Parse(node.SelectSingleNode("pubDate").InnerText, CultureInfo.InvariantCulture); + + release.Description = node.SelectSingleNode("description").InnerText; + release.InfoHash = node.SelectSingleNode("description").InnerText; + release.Size = 0; + release.Seeders = 1; + release.Peers = 1; + release.MagnetUri = new Uri(node.SelectSingleNode("link").InnerText); + releases.Add(release); + } + } + catch (Exception ex) + { + OnResultParsingError(this, xml, ex); + throw ex; + } + } + + return releases.ToArray(); + } + } +} diff --git a/src/Jackett/Indexers/Torrentz.cs b/src/Jackett/Indexers/Torrentz.cs index c9109055a..78b60edf1 100644 --- a/src/Jackett/Indexers/Torrentz.cs +++ b/src/Jackett/Indexers/Torrentz.cs @@ -122,7 +122,8 @@ namespace Jackett.Indexers } ReleaseInfo release; - TorrentzDescription td; + TorrentzHelper td; + string serie_title; foreach (XmlNode node in xmlDoc.GetElementsByTagName("item")) { @@ -130,20 +131,21 @@ namespace Jackett.Indexers release.MinimumRatio = 1; release.MinimumSeedTime = 172800; - release.Title = node.SelectSingleNode("title").InnerText; + serie_title = node.SelectSingleNode("title").InnerText; + release.Title = serie_title; release.Comments = new Uri(node.SelectSingleNode("link").InnerText); release.Category = node.SelectSingleNode("category").InnerText; release.Guid = new Uri(node.SelectSingleNode("guid").InnerText); release.PublishDate = DateTime.Parse(node.SelectSingleNode("pubDate").InnerText, CultureInfo.InvariantCulture); - td = new TorrentzDescription(node.SelectSingleNode("description").InnerText); + td = new TorrentzHelper(node.SelectSingleNode("description").InnerText); release.Description = td.Description; release.InfoHash = td.hash; release.Size = td.Size; release.Seeders = td.Seeders; release.Peers = td.Peers; - release.MagnetUri = new Uri("https://torrage.com/torrent/" + td.hash.ToUpper() + ".torrent"); + release.MagnetUri = TorrentzHelper.createMagnetLink(td.hash, serie_title); releases.Add(release); } } @@ -176,9 +178,9 @@ namespace Jackett.Indexers } - public class TorrentzDescription + public class TorrentzHelper { - public TorrentzDescription(string description) + public TorrentzHelper(string description) { this.Description = description; if (null == description) @@ -193,6 +195,15 @@ namespace Jackett.Indexers FillProperties(); } + public static Uri createMagnetLink(string hash, string title) + { + string MagnetLink = "magnet:?xt=urn:btih:{0}&dn={1}&tr={2}"; + string Trackers = WebUtility.UrlEncode("udp://tracker.publicbt.com:80&tr=udp://tracker.openbittorrent.com:80&tr=udp://tracker.ccc.de:80&tr=udp://tracker.istole.it:80"); + title = WebUtility.UrlEncode(title); + + return new Uri(string.Format(MagnetLink, hash, title, Trackers)); + } + private void FillProperties() { string description = this.Description; diff --git a/src/Jackett/Jackett.csproj b/src/Jackett/Jackett.csproj index 2c895d48b..da08c5216 100644 --- a/src/Jackett/Jackett.csproj +++ b/src/Jackett/Jackett.csproj @@ -98,6 +98,7 @@ + @@ -150,6 +151,7 @@ PreserveNewest + PreserveNewest diff --git a/src/Jackett/WebContent/logos/showrss.png b/src/Jackett/WebContent/logos/showrss.png new file mode 100644 index 0000000000000000000000000000000000000000..4549816c61f8415310ce2a7dc0dac9e71b9ca319 GIT binary patch literal 7560 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 e&{%H={m%eT9$$tiG Date: Thu, 25 Jun 2015 21:21:06 +0200 Subject: [PATCH 2/2] index cleanup, piratebay size culture fix tbp wasn't always working correctly depending on your cultureinfo. Placed the css in a seperate file (custom.css) placed the js in a seperate file (custom.js) --- src/Jackett/Indexers/ThePirateBay.cs | 2 +- src/Jackett/Jackett.csproj | 2 + src/Jackett/WebContent/custom.css | 178 ++++++++++ src/Jackett/WebContent/custom.js | 296 +++++++++++++++++ src/Jackett/WebContent/index.html | 481 +-------------------------- 5 files changed, 479 insertions(+), 480 deletions(-) create mode 100644 src/Jackett/WebContent/custom.css create mode 100644 src/Jackett/WebContent/custom.js diff --git a/src/Jackett/Indexers/ThePirateBay.cs b/src/Jackett/Indexers/ThePirateBay.cs index 511486fb0..715aef264 100644 --- a/src/Jackett/Indexers/ThePirateBay.cs +++ b/src/Jackett/Indexers/ThePirateBay.cs @@ -168,7 +168,7 @@ namespace Jackett.Indexers release.InfoHash = release.MagnetUri.ToString().Split(':')[3].Split('&')[0]; var sizeString = row.ChildElements.ElementAt(4).Cq().Text().Split(' '); - var sizeVal = float.Parse(sizeString[0]); + var sizeVal = float.Parse(sizeString[0], CultureInfo.InvariantCulture); var sizeUnit = sizeString[1]; release.Size = ReleaseInfo.GetBytes(sizeUnit, sizeVal); diff --git a/src/Jackett/Jackett.csproj b/src/Jackett/Jackett.csproj index da08c5216..342743671 100644 --- a/src/Jackett/Jackett.csproj +++ b/src/Jackett/Jackett.csproj @@ -148,6 +148,8 @@ + + PreserveNewest diff --git a/src/Jackett/WebContent/custom.css b/src/Jackett/WebContent/custom.css new file mode 100644 index 000000000..1fa5cddc4 --- /dev/null +++ b/src/Jackett/WebContent/custom.css @@ -0,0 +1,178 @@ + body { + background-image: url("binding_dark.png"); + background-repeat: repeat; + } + + #page { + border-radius: 6px; + background-color: white; + max-width: 900px; + margin: 0 auto; + margin-top: 30px; + padding: 20px; + margin-bottom: 100px; + } + + .container-fluid { + } + + #templates { + display: none; + } + + .card { + background-color: #f9f9f9; + border-radius: 6px; + box-shadow: 1px 1px 5px 2px #cdcdcd; + padding: 10px; + width: 260px; + display: inline-block; + vertical-align: top; + margin: 10px; + } + + .unconfigured-indexer { + height: 170px; + } + + .indexer { + height: 230px; + } + + .add-indexer { + border: 0; + } + + .indexer-logo { + text-align: center; + } + + .indexer-logo > img { + border: 1px solid #828282; + } + + .indexer-name > h3 { + margin-top: 13px; + text-align: center; + } + + .indexer-buttons { + text-align: center; + } + + .indexer-buttons > .btn { + margin-bottom: 10px; + } + + + .indexer-button-test { + width: 60px; + } + + .indexer-add-content { + color: gray; + text-align: center; + } + + .indexer-add-content > .glyphicon { + font-size: 50px; + vertical-align: bottom; + } + + .indexer-add-content > .light-text { + margin-top: 11px; + font-size: 18px; + margin-left: -5px; + } + + + .indexer-host > input { + font-size: 12px; + padding: 2px; + } + + .setup-item-inputstring { + max-width: 260px; + } + + .spinner { + -webkit-animation: spin 2s infinite linear; + -moz-animation: spin 2s infinite linear; + -o-animation: spin 2s infinite linear; + animation: spin 2s infinite linear; + } + + @-moz-keyframes spin { + from { + -moz-transform: rotate(0deg); + } + + to { + -moz-transform: rotate(360deg); + } + } + + @-webkit-keyframes spin { + from { + -webkit-transform: rotate(0deg); + } + + to { + -webkit-transform: rotate(360deg); + } + } + + @keyframes spin { + from { + transform: rotate(0deg); + } + + to { + transform: rotate(360deg); + } + } + + #setup-indexer-go { + width: 70px; + } + + hr { + border-top-color: #cdcdcd; + } + + .input-area { + } + + .input-area > * { + vertical-align: middle; + } + + .input-area > p { + margin-top: 10px; + } + + .input-header { + font-size: 18px; + width: 140px; + display: inline-block; + } + + .input-right { + width: 300px; + display: inline-block; + font-family: monospace; + } + + #sonarr-warning { + display: none; + } + + #logo { + max-width: 50px; + } + + #header-title { + font-size: 34px; + vertical-align: middle; + padding-left: 15px; + } \ No newline at end of file diff --git a/src/Jackett/WebContent/custom.js b/src/Jackett/WebContent/custom.js new file mode 100644 index 000000000..6ca36f85f --- /dev/null +++ b/src/Jackett/WebContent/custom.js @@ -0,0 +1,296 @@ + + +reloadIndexers(); +loadSonarrInfo(); + +function loadSonarrInfo() { + getSonarrConfig(function (data) { + $("#sonarr-host").val(""); + var host, port, apiKey; + for (var i = 0; i < data.config.length; i++) { + if (data.config[i].id == "host") + host = data.config[i].value; + if (data.config[i].id == "port") + port = data.config[i].value; + if (data.config[i].id == "apikey") + apiKey = data.config[i].value; + } + if (!apiKey) + $("#sonarr-warning").show(); + else { + $("#sonarr-warning").hide(); + $("#sonarr-host").val(host + ":" + port); + } + }); +} + +function getSonarrConfig(callback) { + var jqxhr = $.get("get_sonarr_config", function (data) { + callback(data); + }).fail(function () { + doNotify("Error loading Sonarr API configuration, request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); + }); +} + +$("#sonarr-test").click(function () { + var jqxhr = $.get("get_indexers", function (data) { + if (data.result == "error") + doNotify("Test failed for Sonarr API\n" + data.error, "danger", "glyphicon glyphicon-alert"); + else + doNotify("Test successful for Sonarr API", "success", "glyphicon glyphicon-ok"); + }).fail(function () { + doNotify("Error testing Sonarr, request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); + }); +}); + +$("#sonarr-settings").click(function () { + getSonarrConfig(function (data) { + var config = data.config; + + var configForm = newConfigModal("Sonarr API", config); + + var $goButton = configForm.find(".setup-indexer-go"); + $goButton.click(function () { + var data = getConfigModalJson(configForm); + + var originalBtnText = $goButton.html(); + $goButton.prop('disabled', true); + $goButton.html($('#templates > .spinner')[0].outerHTML); + + var jqxhr = $.post("apply_sonarr_config", JSON.stringify(data), function (data) { + if (data.result == "error") { + if (data.config) { + populateSetupForm(data.indexer, data.name, data.config); + } + doNotify("Configuration failed: " + data.error, "danger", "glyphicon glyphicon-alert"); + } + else { + configForm.modal("hide"); + loadSonarrInfo(); + doNotify("Successfully configured Sonarr API", "success", "glyphicon glyphicon-ok"); + } + }).fail(function () { + doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); + }).always(function () { + $goButton.html(originalBtnText); + $goButton.prop('disabled', false); + }); + }); + + configForm.modal("show"); + + }); +}); + + +function reloadIndexers() { + $('#indexers').hide(); + $('#indexers > .indexer').remove(); + $('#unconfigured-indexers').empty(); + var jqxhr = $.get("get_indexers", function (data) { + $("#api-key-input").val(data.api_key); + displayIndexers(data.items); + }).fail(function () { + doNotify("Error loading indexers, request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); + }); +} + +function displayIndexers(items) { + var indexerTemplate = Handlebars.compile($("#templates > .configured-indexer")[0].outerHTML); + var unconfiguredIndexerTemplate = Handlebars.compile($("#templates > .unconfigured-indexer")[0].outerHTML); + for (var i = 0; i < items.length; i++) { + var item = items[i]; + item.torznab_host = resolveUrl("/api/" + item.id); + if (item.configured) + $('#indexers').append(indexerTemplate(item)); + else + $('#unconfigured-indexers').append($(unconfiguredIndexerTemplate(item))); + } + + var addIndexerButton = $("#templates > .add-indexer")[0].outerHTML; + $('#indexers').append(addIndexerButton); + + $('#indexers').fadeIn(); + prepareSetupButtons(); + prepareTestButtons(); + prepareDeleteButtons(); +} + +function prepareDeleteButtons() { + $(".indexer-button-delete").each(function (i, btn) { + var $btn = $(btn); + var id = $btn.data("id"); + $btn.click(function () { + var jqxhr = $.post("delete_indexer", JSON.stringify({ indexer: id }), function (data) { + if (data.result == "error") { + doNotify("Delete error for " + id + "\n" + data.error, "danger", "glyphicon glyphicon-alert"); + } + else { + doNotify("Deleted " + id, "success", "glyphicon glyphicon-ok"); + } + }).fail(function () { + doNotify("Error deleting indexer, request to Jackett server error", "danger", "glyphicon glyphicon-alert"); + }).always(function () { + reloadIndexers(); + }); + }); + }); +} + +function prepareSetupButtons() { + $('.indexer-setup').each(function (i, btn) { + var $btn = $(btn); + var id = $btn.data("id"); + $btn.click(function () { + displayIndexerSetup(id); + }); + }); +} + +function prepareTestButtons() { + $(".indexer-button-test").each(function (i, btn) { + var $btn = $(btn); + var id = $btn.data("id"); + $btn.click(function () { + doNotify("Test started for " + id, "info", "glyphicon glyphicon-transfer"); + var jqxhr = $.post("test_indexer", JSON.stringify({ indexer: id }), function (data) { + if (data.result == "error") { + doNotify("Test failed for " + data.name + "\n" + data.error, "danger", "glyphicon glyphicon-alert"); + } + else { + doNotify("Test successful for " + data.name, "success", "glyphicon glyphicon-ok"); + } + }).fail(function () { + doNotify("Error testing indexer, request to Jackett server error", "danger", "glyphicon glyphicon-alert"); + }); + }); + }); +} + +function displayIndexerSetup(id) { + + var jqxhr = $.post("get_config_form", JSON.stringify({ indexer: id }), function (data) { + if (data.result == "error") { + doNotify("Error: " + data.error, "danger", "glyphicon glyphicon-alert"); + return; + } + populateSetupForm(id, data.name, data.config); + + }).fail(function () { + doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); + }); + + $("#select-indexer-modal").modal("hide"); +} + +function populateConfigItems(configForm, config) { + var $formItemContainer = configForm.find(".config-setup-form"); + $formItemContainer.empty(); + var setupItemTemplate = Handlebars.compile($("#templates > .setup-item")[0].outerHTML); + for (var i = 0; i < config.length; i++) { + var item = config[i]; + var setupValueTemplate = Handlebars.compile($("#templates > .setup-item-" + item.type)[0].outerHTML); + item.value_element = setupValueTemplate(item); + $formItemContainer.append(setupItemTemplate(item)); + } +} + +function newConfigModal(title, config) { + //config-setup-modal + var configTemplate = Handlebars.compile($("#templates > .config-setup-modal")[0].outerHTML); + var configForm = $(configTemplate({ title: title })); + + $("#modals").append(configForm); + + populateConfigItems(configForm, config); + + return configForm; + //modal.remove(); +} + +function getConfigModalJson(configForm) { + var configJson = {}; + configForm.find(".config-setup-form").children().each(function (i, el) { + $el = $(el); + var type = $el.data("type"); + var id = $el.data("id"); + switch (type) { + case "inputstring": + configJson[id] = $el.find(".setup-item-inputstring").val(); + break; + case "inputbool": + configJson[id] = $el.find(".setup-item-checkbox").val(); + break; + } + }); + return configJson; +} + +function populateSetupForm(indexerId, name, config) { + + var configForm = newConfigModal(name, config); + + var $goButton = configForm.find(".setup-indexer-go"); + $goButton.click(function () { + var data = { indexer: indexerId, name: name }; + data.config = getConfigModalJson(configForm); + + var originalBtnText = $goButton.html(); + $goButton.prop('disabled', true); + $goButton.html($('#templates > .spinner')[0].outerHTML); + + var jqxhr = $.post("configure_indexer", JSON.stringify(data), function (data) { + if (data.result == "error") { + if (data.config) { + populateConfigItems(configForm, data.config); + } + doNotify("Configuration failed: " + data.error, "danger", "glyphicon glyphicon-alert"); + } + else { + configForm.modal("hide"); + reloadIndexers(); + doNotify("Successfully configured " + data.name, "success", "glyphicon glyphicon-ok"); + } + }).fail(function () { + doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); + }).always(function () { + $goButton.html(originalBtnText); + $goButton.prop('disabled', false); + }); + }); + + configForm.modal("show"); +} + +function resolveUrl(url) { + var a = document.createElement('a'); + a.href = url; + url = a.href; + return url; +} + + + +function doNotify(message, type, icon) { + $.notify({ + message: message, + icon: icon + }, { + element: 'body', + type: type, + allow_dismiss: true, + z_index: 9000, + mouse_over: 'pause', + placement: { + from: "bottom", + align: "center" + } + }); +} + +function clearNotifications() { + $('[data-notify="container"]').remove(); +} + +$('#test').click(doNotify); + diff --git a/src/Jackett/WebContent/index.html b/src/Jackett/WebContent/index.html index f54b8f533..45c5af196 100644 --- a/src/Jackett/WebContent/index.html +++ b/src/Jackett/WebContent/index.html @@ -13,188 +13,9 @@ + Jackett -
@@ -341,305 +162,7 @@
- + \ No newline at end of file