mirror of
https://github.com/Jackett/Jackett.git
synced 2025-09-12 23:14:08 +02:00
Compare commits
54 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
861a33f4af | ||
![]() |
57c52d9eb2 | ||
![]() |
f574dedbe8 | ||
![]() |
a6d2ecffbb | ||
![]() |
300354ef13 | ||
![]() |
4a519226f5 | ||
![]() |
6a4f6e3638 | ||
![]() |
157b042c0a | ||
![]() |
9385218c9d | ||
![]() |
7482e8d9c4 | ||
![]() |
5501d282de | ||
![]() |
123bb4af5f | ||
![]() |
4d36dae634 | ||
![]() |
eac11ab807 | ||
![]() |
b6892f1dc6 | ||
![]() |
0695b8f84e | ||
![]() |
04995f1a10 | ||
![]() |
44d9b3ecc8 | ||
![]() |
a311509b7c | ||
![]() |
0db4229bd4 | ||
![]() |
441aad5a18 | ||
![]() |
d8d911abf8 | ||
![]() |
7423e3f5bc | ||
![]() |
48fea35645 | ||
![]() |
cef72f11d0 | ||
![]() |
ad3039b70f | ||
![]() |
73d590cebd | ||
![]() |
1d0790471f | ||
![]() |
3b3048aa01 | ||
![]() |
183fb56b0a | ||
![]() |
466be31e6f | ||
![]() |
db42bc944b | ||
![]() |
102e7338f9 | ||
![]() |
01b30b0743 | ||
![]() |
947dbac485 | ||
![]() |
0d29e85c80 | ||
![]() |
89a28e2e95 | ||
![]() |
66b2c20b42 | ||
![]() |
e6035bcaa5 | ||
![]() |
68aac78360 | ||
![]() |
4b02141250 | ||
![]() |
8e1d321817 | ||
![]() |
3354d37aa3 | ||
![]() |
7675214092 | ||
![]() |
7af8e1916e | ||
![]() |
6d4720e58f | ||
![]() |
9928815777 | ||
![]() |
a7d65fedfb | ||
![]() |
464b142130 | ||
![]() |
e1bcdce019 | ||
![]() |
ced9bad4f8 | ||
![]() |
c6140d7eef | ||
![]() |
97f4a9de5d | ||
![]() |
be1f6a43a7 |
43
README.md
43
README.md
@@ -1,4 +1,4 @@
|
||||
# Jackett
|
||||
# Jackett
|
||||
|
||||
[](https://github.com/Jackett/Jackett/issues)
|
||||
[](https://github.com/Jackett/Jackett/pulls)
|
||||
@@ -18,7 +18,7 @@ Developer note: The software implements the [Torznab](https://github.com/Sonarr/
|
||||
|
||||
#### Supported Systems
|
||||
* Windows using .NET 4.5
|
||||
* Linux and OSX using Mono 4 (mono 3 is no longer supported).
|
||||
* Linux and macOS using Mono 4 (mono 3 is no longer supported).
|
||||
|
||||
### Supported Public Trackers
|
||||
* Anidex
|
||||
@@ -30,7 +30,7 @@ Developer note: The software implements the [Torznab](https://github.com/Sonarr/
|
||||
* Il Corsaro Nero <!-- maintained by bonny1992 -->
|
||||
* Isohunt
|
||||
* KickAssTorrent
|
||||
* KickAssTorrent (kat.how clone)
|
||||
* KickAssTorrent (thekat.se clone)
|
||||
* LimeTorrents
|
||||
* NextTorrent
|
||||
* Nyaa.si
|
||||
@@ -69,7 +69,6 @@ Developer note: The software implements the [Torznab](https://github.com/Sonarr/
|
||||
* B2S-Share
|
||||
* BakaBT [![(invite needed)][inviteneeded]](#)
|
||||
* bB
|
||||
* Best Friends
|
||||
* BeyondHD
|
||||
* BIGTorrent
|
||||
* Bit-City Reloaded
|
||||
@@ -82,7 +81,7 @@ Developer note: The software implements the [Torznab](https://github.com/Sonarr/
|
||||
* Blu-bits
|
||||
* BlueBird
|
||||
* Blutopia
|
||||
* BroadcastTheNet [![(invite needed)][inviteneeded]](#)
|
||||
* BroadcastTheNet
|
||||
* BrokenStones
|
||||
* BTNext
|
||||
* Carpathians
|
||||
@@ -92,13 +91,13 @@ Developer note: The software implements the [Torznab](https://github.com/Sonarr/
|
||||
* CinemaZ
|
||||
* Classix
|
||||
* CZTeam
|
||||
* CzTorrent
|
||||
* DanishBits
|
||||
* DataScene
|
||||
* Deildu
|
||||
* Demonoid
|
||||
* Diablo Torrent
|
||||
* DigitalHive
|
||||
* Dragon World (DTW)
|
||||
* Dragonworld Reloaded
|
||||
* Dream Team
|
||||
* EoT-Forum
|
||||
@@ -190,6 +189,7 @@ Developer note: The software implements the [Torznab](https://github.com/Sonarr/
|
||||
* Shazbat
|
||||
* Shellife
|
||||
* SpeedCD
|
||||
* SpeedTorrent Reloaded
|
||||
* SportsCult
|
||||
* SportHD
|
||||
* Superbits
|
||||
@@ -272,14 +272,21 @@ Jackett can also be run from the command line if you would like to see log messa
|
||||
|
||||
Detailed instructions for [Ubuntu 14.x](http://www.htpcguides.com/install-jackett-on-ubuntu-14-x-for-custom-torrents-in-sonarr/) and [Ubuntu 15.x](http://www.htpcguides.com/install-jackett-ubuntu-15-x-for-custom-torrents-in-sonarr/)
|
||||
|
||||
## Installation on OSX
|
||||
1. Install [Mono 4](http://www.mono-project.com/download/#download-mac) or better (version 4.8 is recommended)
|
||||
* Setup ssl support by running
|
||||
```
|
||||
https://curl.haxx.se/ca/cacert.pem
|
||||
cert-sync --user ~/Downloads/cacert.pem
|
||||
```
|
||||
1. Download and extract the latest `Jackett.Binaries.Mono.tar.gz` release from the [releases page](https://github.com/Jackett/Jackett/releases) and run Jackett using mono with the command `mono --debug JackettConsole.exe`.
|
||||
## Installation on macOS
|
||||
|
||||
### Prerequisites
|
||||
Install [Mono 4](http://www.mono-project.com/download/#download-mac) or better (version 4.8 is recommended).
|
||||
* Setup ssl support by running `curl -sS https://curl.haxx.se/ca/cacert.pem | cert-sync --user /dev/stdin`
|
||||
|
||||
### Install as service
|
||||
1. Download and extract the latest `Jackett.Binaries.Mono.tar.gz` release from the [releases page](https://github.com/Jackett/Jackett/releases).
|
||||
2. In Terminal, run the install script from the extracted directory using `./install_service_macos.sh`
|
||||
|
||||
The service will start on each logon. You can always stop it by running `launchctl unload ~/Library/LaunchAgents/org.user.Jackett.plist` from Terminal. You can start it again it using `launchctl load ~/Library/LaunchAgents/org.user.Jackett.plist`.
|
||||
Logs are stored as usual under `~/.config/Jackett/log.txt`.
|
||||
|
||||
### Run without installing as a service
|
||||
Download and extract the latest `Jackett.Binaries.Mono.tar.gz` release from the [releases page](https://github.com/Jackett/Jackett/releases) and run Jackett using mono with the command `mono --debug JackettConsole.exe`.
|
||||
|
||||
## Installation using Docker
|
||||
Detailed instructions are available at [LinuxServer.io Jackett Docker](https://hub.docker.com/r/linuxserver/jackett/). The Jackett Docker is highly recommended, especially if you are having Mono stability issues or having issues running Mono on your system eg. QNAP, Synology. Thanks to [LinuxServer.io](https://linuxserver.io)
|
||||
@@ -297,16 +304,16 @@ Jackett is available as beta package from [SynoCommunity](https://synocommunity.
|
||||
|
||||
If you're using mono this is often caused by missing ca-certificates.
|
||||
Try reimporting the certificates in this case:
|
||||
|
||||
`wget -O - https://curl.haxx.se/ca/cacert.pem | cert-sync /dev/stdin`
|
||||
- On Linux: `wget -O - https://curl.haxx.se/ca/cacert.pem | cert-sync /dev/stdin`
|
||||
- On macOS: `curl -sS https://curl.haxx.se/ca/cacert.pem | cert-sync --user /dev/stdin`
|
||||
|
||||
As a option of last resort you can disable certificate validation using the `--IgnoreSslErrors true` option but it's not recommended to use it as it enables Man-in-the-middle attacks on your connections.
|
||||
|
||||
* __Enable logging__
|
||||
|
||||
You can get additional logging with the command line switches `-t -l` or by enabeling `Enhanced logging` via the web interface.
|
||||
You can get additional logging with the command line switches `-t -l` or by enabling `Enhanced logging` via the web interface.
|
||||
Please post logs if you are unable to resolve your issue with these switches ensuring to remove your username/password/cookies.
|
||||
The logfiles (log.txt/updater.txt) are stored in `%ProgramData%\Jackett` on Windows and `~/.config/Jackett/` on Linux/OSX.
|
||||
The logfiles (log.txt/updater.txt) are stored in `%ProgramData%\Jackett` on Windows and `~/.config/Jackett/` on Linux/macOS.
|
||||
|
||||
## Creating an issue
|
||||
Please supply as much information about the problem you are experiencing as possible. Your issue has a much greater chance of being resolved if logs are supplied so that we can see what is going on. Creating an issue with '### isn't working' doesn't help anyone to fix the problem.
|
||||
|
@@ -60,7 +60,7 @@ namespace Jackett.Console
|
||||
[Option('n', "IgnoreSslErrors", HelpText = "[true/false] Ignores invalid SSL certificates")]
|
||||
public bool? IgnoreSslErrors { get; set; }
|
||||
|
||||
[Option('d', "DataFolder", HelpText = "Specify the location of the data folder (Must be admin on Windows) eg. --DataFolder=\"D:\\Your Data\\Jackett\\\"")]
|
||||
[Option('d', "DataFolder", HelpText = "Specify the location of the data folder (Must be admin on Windows) eg. --DataFolder=\"D:\\Your Data\\Jackett\\\". Don't use this on Unix (mono) systems. On Unix just adjust the HOME directory of the user to the datedir or set the XDG_CONFIG_HOME environment variable.")]
|
||||
public string DataFolder { get; set; }
|
||||
|
||||
[Option(HelpText = "Don't restart after update")]
|
||||
|
@@ -153,6 +153,9 @@
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="packages.config" />
|
||||
<Content Include="install_service_macos.sh">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CurlSharp\CurlSharp.csproj">
|
||||
@@ -182,4 +185,4 @@
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
67
src/Jackett.Console/install_service_macos.sh
Executable file
67
src/Jackett.Console/install_service_macos.sh
Executable file
@@ -0,0 +1,67 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Stop and unload the service if it's running
|
||||
launchctl remove org.user.Jackett
|
||||
|
||||
# Check if we're running from Jackett's directory
|
||||
if [ ! -f ./JackettConsole.exe ]; then
|
||||
echo "Couldn't locate JackettConsole.exe. Are you running from the right directory?"
|
||||
exit 1
|
||||
fi
|
||||
jackettdir="$(pwd)"
|
||||
|
||||
# Check if mono is installed
|
||||
command -v mono >/dev/null 2>&1 || { echo >&2 "Jackett requires Mono but it's not installed. Aborting."; exit 1; }
|
||||
monodir="$(dirname $(command -v mono))"
|
||||
|
||||
# Check that no other service called Jackett is already running
|
||||
if [[ $(launchctl list | grep org.user.Jackett) ]]; then
|
||||
echo "Jackett already seems to be running as a service. Please stop it before running this script again."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Write the plist to LaunchAgents
|
||||
cat >~/Library/LaunchAgents/org.user.Jackett.plist <<EOL
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>PATH</key>
|
||||
<string>/usr/bin:/bin:/usr/sbin:/sbin:${monodir}</string>
|
||||
</dict>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>Label</key>
|
||||
<string>org.user.Jackett</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>${monodir}/mono</string>
|
||||
<string>--debug</string>
|
||||
<string>JackettConsole.exe</string>
|
||||
<string>--NoRestart</string>
|
||||
</array>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>WorkingDirectory</key>
|
||||
<string>${jackettdir}</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
EOL
|
||||
|
||||
# Run the agent
|
||||
launchctl load ~/Library/LaunchAgents/org.user.Jackett.plist
|
||||
|
||||
# Check that it's running
|
||||
if [[ $(launchctl list | grep org.user.Jackett) ]]; then
|
||||
echo "Agent successfully installed and launched!"
|
||||
else
|
||||
cat << EOL
|
||||
Could not launch agent. The installation might have failed.
|
||||
Please open an issue on https://github.com/Jackett/Jackett/issues and paste following information:
|
||||
Mono directory: \`${monodir}\`
|
||||
Jackett directory: \`${jackettdir}\`
|
||||
EOL
|
||||
fi
|
@@ -190,6 +190,7 @@ namespace Jackett.Updater
|
||||
"Definitions/nachtwerk.yml",
|
||||
"Definitions/leparadisdunet.yml",
|
||||
"Definitions/qctorrent.yml",
|
||||
"Definitions/dragonworld.yml",
|
||||
};
|
||||
|
||||
foreach (var oldFIle in oldFiles)
|
||||
|
@@ -42,12 +42,9 @@ $(document).ready(function () {
|
||||
});
|
||||
|
||||
function openSearchIfNecessary() {
|
||||
var parser = document.createElement('a');
|
||||
parser.href = window.location.href;
|
||||
|
||||
if (parser.hash.startsWith("#search")) {
|
||||
var query = parser.hash.split('=')[1];
|
||||
showSearch(null, query);
|
||||
const hashArgs = location.hash.substring(1).split('&').reduce((prev, item) => Object.assign({ [item.split('=')[0]]: (item.split('=').length < 2 ? undefined : decodeURIComponent(item.split('=')[1])) }, prev), {});
|
||||
if ("search" in hashArgs) {
|
||||
showSearch(hashArgs.tracker, hashArgs.search, hashArgs.category);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,6 +368,7 @@ function prepareSearchButtons(element) {
|
||||
var $btn = $(btn);
|
||||
var id = $btn.data("id");
|
||||
$btn.click(function() {
|
||||
window.location.hash = "search&tracker=" + id;
|
||||
showSearch(id);
|
||||
});
|
||||
});
|
||||
@@ -725,7 +723,7 @@ function updateReleasesRow(row)
|
||||
}
|
||||
}
|
||||
|
||||
function showSearch(selectedIndexer, query) {
|
||||
function showSearch(selectedIndexer, query, category) {
|
||||
$('#select-indexer-modal').remove();
|
||||
var releaseTemplate = Handlebars.compile($("#jackett-search").html());
|
||||
var releaseDialog = $(releaseTemplate({
|
||||
@@ -788,7 +786,7 @@ function showSearch(selectedIndexer, query) {
|
||||
Tracker: releaseDialog.find('#searchTracker').val().replace("'", "").replace("'", ""),
|
||||
};
|
||||
|
||||
window.location.hash = "search=" + searchString;
|
||||
window.location.hash = $.param({ search: queryObj.Query, tracker: queryObj.Tracker, category: queryObj.Category});
|
||||
|
||||
$('#jackett-search-perform').html($('#spinner').html());
|
||||
$('#searchResults div.dataTables_filter input').val("");
|
||||
@@ -824,8 +822,12 @@ function showSearch(selectedIndexer, query) {
|
||||
clearSearchResultTable($('#searchResults'));
|
||||
releaseDialog.modal("show");
|
||||
|
||||
if (category !== undefined) {
|
||||
$('#searchCategory').val(category);
|
||||
}
|
||||
|
||||
if (query !== undefined) {
|
||||
queryField.value = decodeURIComponent(query);
|
||||
queryField.value = query;
|
||||
searchButton.click();
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,7 @@ using Jackett.Utils;
|
||||
using Jackett.Utils.Clients;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using Jackett.Models.DTO;
|
||||
|
||||
namespace Jackett.Controllers.V20
|
||||
{
|
||||
@@ -154,20 +155,67 @@ namespace Jackett.Controllers.V20
|
||||
[HttpGet]
|
||||
public async Task<Models.DTO.ManualSearchResult> Results([FromUri]Models.DTO.ApiSearch request)
|
||||
{
|
||||
var manualResult = new ManualSearchResult();
|
||||
var trackers = IndexerService.GetAllIndexers().Where(t => t.IsConfigured);
|
||||
if (CurrentIndexer.ID != "all")
|
||||
trackers = trackers.Where(t => t.ID == CurrentIndexer.ID).ToList();
|
||||
trackers = trackers.Where(t => t.IsConfigured && t.CanHandleQuery(CurrentQuery));
|
||||
trackers = trackers.Where(t => t.CanHandleQuery(CurrentQuery));
|
||||
|
||||
var tasks = trackers.ToList().Select(t => t.ResultsForQuery(CurrentQuery)).ToList();
|
||||
var aggregateTask = Task.WhenAll(tasks);
|
||||
|
||||
await aggregateTask;
|
||||
|
||||
var results = tasks.Where(t => t.Status == TaskStatus.RanToCompletion).Where(t => t.Result.Count() > 0).SelectMany(t =>
|
||||
try
|
||||
{
|
||||
var searchResults = t.Result;
|
||||
var indexer = searchResults.First().Origin;
|
||||
var aggregateTask = Task.WhenAll(tasks);
|
||||
await aggregateTask;
|
||||
}
|
||||
catch (AggregateException aex)
|
||||
{
|
||||
foreach (var ex in aex.InnerExceptions)
|
||||
{
|
||||
logger.Error(ex);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error(ex);
|
||||
}
|
||||
|
||||
manualResult.Indexers = tasks.Select(t =>
|
||||
{
|
||||
var resultIndexer = new ManualSearchResultIndexer();
|
||||
IIndexer indexer = null;
|
||||
if (t.Status == TaskStatus.RanToCompletion)
|
||||
{
|
||||
resultIndexer.Status = ManualSearchResultIndexerStatus.OK;
|
||||
resultIndexer.Results = t.Result.Releases.Count();
|
||||
resultIndexer.Error = null;
|
||||
indexer = t.Result.Indexer;
|
||||
}
|
||||
else if (t.Exception.InnerException is IndexerException)
|
||||
{
|
||||
resultIndexer.Status = ManualSearchResultIndexerStatus.Error;
|
||||
resultIndexer.Results = 0;
|
||||
resultIndexer.Error = ((IndexerException)t.Exception.InnerException).ToString();
|
||||
indexer = ((IndexerException)t.Exception.InnerException).Indexer;
|
||||
}
|
||||
else
|
||||
{
|
||||
resultIndexer.Status = ManualSearchResultIndexerStatus.Unknown;
|
||||
resultIndexer.Results = 0;
|
||||
resultIndexer.Error = null;
|
||||
}
|
||||
|
||||
if (indexer != null)
|
||||
{
|
||||
resultIndexer.ID = indexer.ID;
|
||||
resultIndexer.Name = indexer.DisplayName;
|
||||
}
|
||||
return resultIndexer;
|
||||
}).ToList();
|
||||
|
||||
manualResult.Results = tasks.Where(t => t.Status == TaskStatus.RanToCompletion).Where(t => t.Result.Releases.Count() > 0).SelectMany(t =>
|
||||
{
|
||||
var searchResults = t.Result.Releases;
|
||||
var indexer = t.Result.Indexer;
|
||||
cacheService.CacheRssResults(indexer, searchResults);
|
||||
|
||||
return searchResults.Select(result =>
|
||||
@@ -181,17 +229,7 @@ namespace Jackett.Controllers.V20
|
||||
});
|
||||
}).OrderByDescending(d => d.PublishDate).ToList();
|
||||
|
||||
ConfigureCacheResults(results);
|
||||
|
||||
var manualResult = new Models.DTO.ManualSearchResult()
|
||||
{
|
||||
Results = results,
|
||||
Indexers = trackers.Select(t => t.DisplayName).ToList()
|
||||
};
|
||||
|
||||
|
||||
if (manualResult.Indexers.Count() == 0)
|
||||
manualResult.Indexers = new List<string>() { "None" };
|
||||
ConfigureCacheResults(manualResult.Results);
|
||||
|
||||
logger.Info(string.Format("Manual search for \"{0}\" on {1} with {2} results.", CurrentQuery.SanitizedSearchTerm, string.Join(", ", manualResult.Indexers), manualResult.Results.Count()));
|
||||
return manualResult;
|
||||
@@ -236,7 +274,7 @@ namespace Jackett.Controllers.V20
|
||||
}
|
||||
}
|
||||
|
||||
var releases = await CurrentIndexer.ResultsForQuery(CurrentQuery);
|
||||
var result = await CurrentIndexer.ResultsForQuery(CurrentQuery);
|
||||
|
||||
// Some trackers do not support multiple category filtering so filter the releases that match manually.
|
||||
int? newItemCount = null;
|
||||
@@ -244,19 +282,19 @@ namespace Jackett.Controllers.V20
|
||||
// Cache non query results
|
||||
if (string.IsNullOrEmpty(CurrentQuery.SanitizedSearchTerm))
|
||||
{
|
||||
newItemCount = cacheService.GetNewItemCount(CurrentIndexer, releases);
|
||||
cacheService.CacheRssResults(CurrentIndexer, releases);
|
||||
newItemCount = cacheService.GetNewItemCount(CurrentIndexer, result.Releases);
|
||||
cacheService.CacheRssResults(CurrentIndexer, result.Releases);
|
||||
}
|
||||
|
||||
// Log info
|
||||
var logBuilder = new StringBuilder();
|
||||
if (newItemCount != null)
|
||||
{
|
||||
logBuilder.AppendFormat("Found {0} ({1} new) releases from {2}", releases.Count(), newItemCount, CurrentIndexer.DisplayName);
|
||||
logBuilder.AppendFormat("Found {0} ({1} new) releases from {2}", result.Releases.Count(), newItemCount, CurrentIndexer.DisplayName);
|
||||
}
|
||||
else
|
||||
{
|
||||
logBuilder.AppendFormat("Found {0} releases from {1}", releases.Count(), CurrentIndexer.DisplayName);
|
||||
logBuilder.AppendFormat("Found {0} releases from {1}", result.Releases.Count(), CurrentIndexer.DisplayName);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(CurrentQuery.SanitizedSearchTerm))
|
||||
@@ -278,7 +316,7 @@ namespace Jackett.Controllers.V20
|
||||
ImageDescription = CurrentIndexer.DisplayName
|
||||
});
|
||||
|
||||
var proxiedReleases = releases.Select(r => AutoMapper.Mapper.Map<ReleaseInfo>(r)).Select(r =>
|
||||
var proxiedReleases = result.Releases.Select(r => AutoMapper.Mapper.Map<ReleaseInfo>(r)).Select(r =>
|
||||
{
|
||||
r.Link = serverService.ConvertToProxyLink(r.Link, serverUrl, r.Origin.ID, "dl", r.Title + ".torrent");
|
||||
return r;
|
||||
@@ -316,20 +354,20 @@ namespace Jackett.Controllers.V20
|
||||
[JsonResponse]
|
||||
public async Task<Models.DTO.TorrentPotatoResponse> Potato([FromUri]Models.DTO.TorrentPotatoRequest request)
|
||||
{
|
||||
var releases = await CurrentIndexer.ResultsForQuery(CurrentQuery);
|
||||
var result = await CurrentIndexer.ResultsForQuery(CurrentQuery);
|
||||
|
||||
// Cache non query results
|
||||
if (string.IsNullOrEmpty(CurrentQuery.SanitizedSearchTerm))
|
||||
cacheService.CacheRssResults(CurrentIndexer, releases);
|
||||
cacheService.CacheRssResults(CurrentIndexer, result.Releases);
|
||||
|
||||
// Log info
|
||||
if (string.IsNullOrWhiteSpace(CurrentQuery.SanitizedSearchTerm))
|
||||
logger.Info($"Found {releases.Count()} torrentpotato releases from {CurrentIndexer.DisplayName}");
|
||||
logger.Info($"Found {result.Releases.Count()} torrentpotato releases from {CurrentIndexer.DisplayName}");
|
||||
else
|
||||
logger.Info($"Found {releases.Count()} torrentpotato releases from {CurrentIndexer.DisplayName} for: {CurrentQuery.GetQueryString()}");
|
||||
logger.Info($"Found {result.Releases.Count()} torrentpotato releases from {CurrentIndexer.DisplayName} for: {CurrentQuery.GetQueryString()}");
|
||||
|
||||
var serverUrl = string.Format("{0}://{1}:{2}{3}", Request.RequestUri.Scheme, Request.RequestUri.Host, Request.RequestUri.Port, serverService.BasePath());
|
||||
var potatoReleases = releases.Where(r => r.Link != null || r.MagnetUri != null).Select(r =>
|
||||
var potatoReleases = result.Releases.Where(r => r.Link != null || r.MagnetUri != null).Select(r =>
|
||||
{
|
||||
var release = AutoMapper.Mapper.Map<ReleaseInfo>(r);
|
||||
release.Link = serverService.ConvertToProxyLink(release.Link, serverUrl, CurrentIndexer.ID, "dl", release.Title + ".torrent");
|
||||
|
@@ -112,6 +112,9 @@
|
||||
args: ["torrents-details.php", "download.php"]
|
||||
title:
|
||||
selector: a[href^="torrents-details.php?id="]
|
||||
filters:
|
||||
- name: replace
|
||||
args: [" - (Nouveau!)", ""]
|
||||
category:
|
||||
selector: a[href^="torrents.php?cat="]
|
||||
attribute: href
|
||||
|
@@ -120,7 +120,7 @@
|
||||
search_type: "name"
|
||||
searchin: "title"
|
||||
error:
|
||||
- selector: div.error
|
||||
- selector: div.error:not(:contains("Não existem resultados encontrados."))
|
||||
rows:
|
||||
selector: table#torrents_table_classic > tbody > tr:has(td.torrent_name)
|
||||
fields:
|
||||
|
125
src/Jackett/Definitions/cztorrent.yml
Normal file
125
src/Jackett/Definitions/cztorrent.yml
Normal file
@@ -0,0 +1,125 @@
|
||||
---
|
||||
site: cztorrent
|
||||
name: CzTorrent
|
||||
language: cs-cz
|
||||
type: semi-private
|
||||
encoding: UTF-8
|
||||
links:
|
||||
- https://tracker.cztorrent.net/
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
- {id: 1, cat: Movies, desc: "Filmy"}
|
||||
- {id: 25, cat: TV, desc: "Seriály"}
|
||||
- {id: 23, cat: TV/Documentary, desc: "Filmy - dokument"}
|
||||
- {id: 22, cat: PC, desc: "Aplikace"}
|
||||
- {id: 36, cat: Movies/3D, desc: "Filmy - 3D"}
|
||||
- {id: 35, cat: Movies/Other, desc: "Filmy - anime"}
|
||||
- {id: 37, cat: Movies/BluRay, desc: "Filmy - Blu-ray"}
|
||||
- {id: 11, cat: Movies/DVD, desc: "Filmy - DVD"}
|
||||
- {id: 30, cat: Movies/DVD, desc: "Filmy - DVD full"}
|
||||
- {id: 5, cat: Movies, desc: "Filmy - kreslené"}
|
||||
- {id: 31, cat: Movies/HD, desc: "HD"}
|
||||
- {id: 38, cat: Movies/HD, desc: "HD-LQ"}
|
||||
- {id: 3, cat: PC/Games, desc: "Hry"}
|
||||
- {id: 2, cat: Audio, desc: "Hudba"}
|
||||
- {id: 34, cat: Audio/Video, desc: "Hudba DVD/HD"}
|
||||
- {id: 6, cat: Books, desc: "Knihy"}
|
||||
- {id: 13, cat: Console, desc: "Konzole"}
|
||||
- {id: 32, cat: Audio, desc: "Mluvené slovo"}
|
||||
- {id: 16, cat: PC/Phone-Other, desc: "Mobil, PDA"}
|
||||
- {id: 4, cat: Other, desc: "Ostatní"}
|
||||
- {id: 29, cat: Audio, desc: "Soundtrack"}
|
||||
- {id: 19, cat: Audio/Video, desc: "Videoklipy"}
|
||||
- {id: 24, cat: XXX, desc: "xXx"}
|
||||
|
||||
modes:
|
||||
search: [q]
|
||||
tv-search: [q, season, ep]
|
||||
movie-search: [q]
|
||||
|
||||
login:
|
||||
path: /login-page
|
||||
method: form
|
||||
form: form[action^="/login"]
|
||||
inputs:
|
||||
username: "{{ .Config.username }}"
|
||||
password: "{{ .Config.password }}"
|
||||
persistent_login: "1"
|
||||
error:
|
||||
- selector: div.error
|
||||
test:
|
||||
path: /torrents
|
||||
|
||||
search:
|
||||
path: /torrents
|
||||
inputs:
|
||||
$raw: "{{range .Categories}}c{{.}}=1&{{end}}"
|
||||
s: "{{ .Keywords }}"
|
||||
t: "1"
|
||||
rows:
|
||||
selector: tr.torr_hover
|
||||
fields:
|
||||
title:
|
||||
selector: td.detaily a
|
||||
filters:
|
||||
- name: re_replace
|
||||
args: [".*? / ", ""]
|
||||
category:
|
||||
selector: td:nth-child(2)
|
||||
case:
|
||||
":contains(\"Filmy\")": 1
|
||||
":contains(\"Seriály\")": 25
|
||||
":contains(\"Filmy - dokument\")": 23
|
||||
":contains(\"Aplikace\")": 22
|
||||
":contains(\"Filmy - 3D\")": 36
|
||||
":contains(\"Filmy - anime\")": 35
|
||||
":contains(\"Filmy - Blu-ray\")": 37
|
||||
":contains(\"Filmy - DVD\")": 11
|
||||
":contains(\"Filmy - DVD full\")": 30
|
||||
":contains(\"Filmy - kreslené\")": 5
|
||||
":contains(\"HD\")": 31
|
||||
":contains(\"HD-LQ\")": 38
|
||||
":contains(\"Hry\")": 3
|
||||
":contains(\"Hudba\")": 2
|
||||
":contains(\"Hudba DVD/HD\")": 34
|
||||
":contains(\"Knihy\")": 6
|
||||
":contains(\"Konzole\")": 13
|
||||
":contains(\"Mluvené slovo\")": 32
|
||||
":contains(\"Mobil, PDA\")": 16
|
||||
":contains(\"Ostatní\")": 4
|
||||
":contains(\"Soundtrack\")": 29
|
||||
":contains(\"Videoklipy\")": 19
|
||||
":contains(\"xXx\")": 24
|
||||
details:
|
||||
selector: td.detaily a
|
||||
attribute: href
|
||||
download:
|
||||
selector: td.download a
|
||||
attribute: href
|
||||
size:
|
||||
selector: td.detaily
|
||||
filters:
|
||||
- name: split
|
||||
args: [ "|", 0 ]
|
||||
- name: regexp
|
||||
args: "Velikost: (.+?) ?$"
|
||||
date:
|
||||
selector: td:nth-child(4)
|
||||
filters:
|
||||
- name: split
|
||||
args: [ "|", 1 ]
|
||||
- name: regexp
|
||||
args: "Přidán: (.+?) ?$"
|
||||
- name: append
|
||||
args: " +02:00"
|
||||
seeders:
|
||||
selector: td:nth-child(7) span
|
||||
leechers:
|
||||
selector: td:nth-child(8) span
|
||||
downloadvolumefactor:
|
||||
case:
|
||||
"*": "1"
|
||||
uploadvolumefactor:
|
||||
case:
|
||||
"*": "1"
|
@@ -67,7 +67,7 @@
|
||||
search: "{{ .Query.Keywords }}"
|
||||
incldead: 1
|
||||
rows:
|
||||
selector: tr:has(a.tname)
|
||||
selector: div.ncls > table > tbody > tr:has(a.tname)
|
||||
fields:
|
||||
title-attribute:
|
||||
selector: a.tname
|
||||
@@ -86,7 +86,7 @@
|
||||
- name: querystring
|
||||
args: cat
|
||||
download:
|
||||
selector: a[href^="/download.php/"]
|
||||
selector: a[href^="/download.php/"], a[href^="/downloadd.php/"] # some releases use a download link with two d's
|
||||
attribute: href
|
||||
grabs:
|
||||
selector: td:nth-child(8)
|
||||
@@ -97,10 +97,9 @@
|
||||
selector: td:nth-child(7)
|
||||
date:
|
||||
selector: td:nth-child(2) > right > div:has(font:contains("Uploaded"))
|
||||
remove: div > font
|
||||
filters:
|
||||
- name: trim
|
||||
args: ":"
|
||||
- name: replace
|
||||
args: ["Uploaded: ", ""]
|
||||
seeders:
|
||||
selector: td:nth-child(9)
|
||||
leechers:
|
||||
@@ -117,7 +116,7 @@
|
||||
attribute: href
|
||||
downloadvolumefactor:
|
||||
case:
|
||||
"img[src=\"pic/free.gif\"]": "0"
|
||||
"img[src=\"pic/free.png\"]": "0"
|
||||
"*": "1"
|
||||
uploadvolumefactor:
|
||||
case:
|
||||
|
@@ -1,154 +0,0 @@
|
||||
---
|
||||
site: dragonworld
|
||||
name: Dragon World (DTW)
|
||||
language: de-de
|
||||
type: private
|
||||
encoding: UTF-8
|
||||
links:
|
||||
- http://dtw.sytes.net/
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
# Dokumentation
|
||||
- {id: 46, cat: TV/Documentary, desc: "Dokumentation"}
|
||||
- {id: 55, cat: TV/Documentary, desc: "Dokumentation/HD"}
|
||||
- {id: 56, cat: TV/Documentary, desc: "Dokumentation/SD"}
|
||||
# Ebooks
|
||||
- {id: 36, cat: Books, desc: "Ebooks"}
|
||||
- {id: 37, cat: Books, desc: "Ebooks"}
|
||||
- {id: 38, cat: Books, desc: "Ebooks/Hoerspiele/Hoerbuecher"}
|
||||
# Games
|
||||
- {id: 21, cat: Console, desc: "Games"}
|
||||
- {id: 24, cat: Console/Other, desc: "Games/Nintendo"}
|
||||
- {id: 22, cat: PC/Games, desc: "Games/PC"}
|
||||
- {id: 23, cat: Console/PS4, desc: "Games/Playstation"}
|
||||
- {id: 25, cat: Console/Xbox, desc: "Games/Xbox"}
|
||||
# Kinder
|
||||
- {id: 10, cat: Other, desc: "Kinder"}
|
||||
- {id: 14, cat: Other, desc: "Kinder/Diverses"}
|
||||
- {id: 12, cat: Movies, desc: "Kinder/Filme"}
|
||||
- {id: 11, cat: PC/Games, desc: "Kinder/Games"}
|
||||
- {id: 13, cat: Audio, desc: "Kinder/Musik"}
|
||||
# Movies
|
||||
- {id: 15, cat: Movies, desc: "Movies"}
|
||||
- {id: 50, cat: Movies/3D, desc: "Movies/3D"}
|
||||
- {id: 48, cat: Movies/HD, desc: "Movies/HD"}
|
||||
- {id: 53, cat: Movies/HD, desc: "Movies/HD Pack"}
|
||||
- {id: 45, cat: Movies/HD, desc: "Movies/Remuxe"}
|
||||
- {id: 17, cat: Movies/SD, desc: "Movies/SD"}
|
||||
- {id: 54, cat: Movies/SD, desc: "Movies/SD Pack"}
|
||||
# Musik
|
||||
- {id: 4, cat: Audio, desc: "Musik"}
|
||||
- {id: 57, cat: Audio, desc: "Musik/Album"}
|
||||
- {id: 8, cat: Audio/Lossless, desc: "Musik/Flac"}
|
||||
- {id: 7, cat: Audio/MP3, desc: "Musik/Mp3"}
|
||||
- {id: 9, cat: Audio/Video, desc: "Musik/Video"}
|
||||
# Serien
|
||||
- {id: 26, cat: TV, desc: "Serien"}
|
||||
- {id: 27, cat: TV/HD, desc: "Serien/HD"}
|
||||
- {id: 28, cat: TV/SD, desc: "Serien/SD"}
|
||||
# Software
|
||||
- {id: 29, cat: PC/0day, desc: "Software"}
|
||||
- {id: 32, cat: PC/0day, desc: "Software/Diverses"}
|
||||
- {id: 31, cat: PC/Mac, desc: "Software/Mac"}
|
||||
- {id: 30, cat: PC/0day, desc: "Software/Windows"}
|
||||
# Sport
|
||||
- {id: 39, cat: TV/Sport, desc: "Sport"}
|
||||
- {id: 40, cat: TV/Sport, desc: "Sport HD"}
|
||||
- {id: 58, cat: TV/Sport, desc: "Sport SD"}
|
||||
# XXX
|
||||
- {id: 33, cat: XXX, desc: "XXX"}
|
||||
- {id: 34, cat: XXX, desc: "XXX/HD"}
|
||||
- {id: 35, cat: XXX, desc: "XXX/SD"}
|
||||
|
||||
|
||||
modes:
|
||||
search: [q]
|
||||
tv-search: [q, season, ep]
|
||||
movie-search: [q]
|
||||
|
||||
login:
|
||||
path: takelogin.php
|
||||
method: post
|
||||
inputs:
|
||||
username: "{{ .Config.username }}"
|
||||
password: "{{ .Config.password }}"
|
||||
error:
|
||||
- selector: table:has(td:contains("Ein Fehler ist aufgetreten"))
|
||||
test:
|
||||
path: browse.php
|
||||
selector: a[href*="/logout.php"]
|
||||
|
||||
download:
|
||||
before:
|
||||
path: "takethanks.php"
|
||||
method: "post"
|
||||
inputs:
|
||||
torrentid: "{{ .DownloadUri.Query.id }}"
|
||||
|
||||
search:
|
||||
path: browse.php
|
||||
keywordsfilters:
|
||||
- name: re_replace
|
||||
args: ["[^a-zA-Z0-9]+", "%"]
|
||||
inputs:
|
||||
do: "search"
|
||||
keywords: "{{ .Keywords }}"
|
||||
search_type: "t_name"
|
||||
category: "0" # multi cat search not supported
|
||||
include_dead_torrents: "yes"
|
||||
rows:
|
||||
selector: table#sortabletable > tbody > tr:has(a[href*="/details.php?id="])
|
||||
filters:
|
||||
- name: andmatch
|
||||
args: 66
|
||||
fields:
|
||||
download:
|
||||
selector: a[href*="/download.php?id="]
|
||||
attribute: href
|
||||
magnet:
|
||||
selector: a[href^="magnet:"]
|
||||
attribute: href
|
||||
title:
|
||||
selector: a[href*="/details.php?id="]
|
||||
title:
|
||||
selector: div.tooltip-content > div
|
||||
optional: true
|
||||
details:
|
||||
selector: a[href*="/details.php?id="]
|
||||
attribute: href
|
||||
category:
|
||||
selector: a[href*="/browse.php?category="]
|
||||
attribute: href
|
||||
filters:
|
||||
- name: querystring
|
||||
args: category
|
||||
banner:
|
||||
selector: div.tooltip-content > img
|
||||
attribute: src
|
||||
optional: true
|
||||
size:
|
||||
selector: td:nth-child(5)
|
||||
grabs:
|
||||
selector: td:nth-child(6)
|
||||
seeders:
|
||||
selector: td:nth-child(7)
|
||||
leechers:
|
||||
selector: td:nth-child(8)
|
||||
downloadvolumefactor:
|
||||
case:
|
||||
img[alt^="OnlyUp Torrent"]: "0"
|
||||
img[alt^="50% "]: "0.5"
|
||||
"*": "1"
|
||||
uploadvolumefactor:
|
||||
case:
|
||||
img[alt^="multi2 Torrent"]: "2"
|
||||
"*": "1"
|
||||
date:
|
||||
selector: "td:nth-child(2) > div:has(span[style=\"float: right;\"])"
|
||||
remove: span
|
||||
filters:
|
||||
- name: append
|
||||
args: " +01:00"
|
||||
- name: dateparse
|
||||
args: "02-01-2006 15:04 -07:00"
|
@@ -6,7 +6,7 @@
|
||||
type: private
|
||||
encoding: windows-1252
|
||||
links:
|
||||
- http://eot-forum.net
|
||||
- https://eot-forum.net
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
|
@@ -70,6 +70,8 @@
|
||||
blah: "0"
|
||||
rows:
|
||||
selector: table#torrenttable > tbody > tr:has()
|
||||
error:
|
||||
- selector: div.content:contains("Meg van vonva a letöltési jogod")
|
||||
fields:
|
||||
download:
|
||||
selector: a[href^="/details.php?id="]
|
||||
|
@@ -77,7 +77,7 @@
|
||||
search_type: "name"
|
||||
searchin: "title"
|
||||
error:
|
||||
- selector: div#show_error
|
||||
- selector: div#show_error:not(:contains("Ουπς! Λάθος!Δεν βρέθηκαν αποτελέσματα."))
|
||||
rows:
|
||||
selector: div#content > div.torrent-box[id^="torrent_"]
|
||||
filters:
|
||||
|
@@ -30,9 +30,6 @@
|
||||
test:
|
||||
path: index.php
|
||||
|
||||
download:
|
||||
selector: a[href^="download.php?id="]
|
||||
|
||||
search:
|
||||
path: browse.php
|
||||
inputs:
|
||||
@@ -47,11 +44,8 @@
|
||||
title:
|
||||
selector: td:nth-child(2) span
|
||||
download:
|
||||
selector: a[href^="details.php?id="]
|
||||
selector: a[href^="down.php"]
|
||||
attribute: href
|
||||
filters:
|
||||
- name: replace
|
||||
args: ["details.php?id=", "download.php?id="]
|
||||
details:
|
||||
selector: a[href^="details.php?id="]
|
||||
attribute: href
|
||||
|
4
src/Jackett/Definitions/kickasstorrent-kathow.yml
Normal file → Executable file
4
src/Jackett/Definitions/kickasstorrent-kathow.yml
Normal file → Executable file
@@ -1,11 +1,11 @@
|
||||
---
|
||||
site: kickasstorrent-kathow
|
||||
name: KickAssTorrent (kat.how)
|
||||
name: KickAssTorrent (thekat.se)
|
||||
language: en-us
|
||||
type: public
|
||||
encoding: UTF-8
|
||||
links:
|
||||
- https://kat.how
|
||||
- https://thekat.se
|
||||
|
||||
caps:
|
||||
categories:
|
||||
|
2
src/Jackett/Definitions/kickasstorrent.yml
Normal file → Executable file
2
src/Jackett/Definitions/kickasstorrent.yml
Normal file → Executable file
@@ -88,7 +88,7 @@
|
||||
settings: []
|
||||
|
||||
search:
|
||||
path: "/new/{{if .Query.Keywords}}search-torrents.php{{else}}torrents.php{{end}}"
|
||||
path: "/new/{{if .Query.Keywords}}search-torrents.php{{else}}index.php{{end}}"
|
||||
inputs:
|
||||
$raw: "{{range .Categories}}c{{.}}=1&{{end}}"
|
||||
search: "\"{{ .Query.Keywords }}\""
|
||||
|
4
src/Jackett/Definitions/nexttorrent.yml
Normal file → Executable file
4
src/Jackett/Definitions/nexttorrent.yml
Normal file → Executable file
@@ -24,7 +24,7 @@
|
||||
search:
|
||||
path: "recherche/{{ .Query.Keywords }}"
|
||||
rows:
|
||||
selector: div.listing-torrent > table tbody tr
|
||||
selector: div.listing-torrent > table tbody tr:has(a)
|
||||
fields:
|
||||
site_date:
|
||||
selector: td:nth-child(1) a
|
||||
@@ -85,4 +85,4 @@
|
||||
downloadvolumefactor:
|
||||
text: "0"
|
||||
uploadvolumefactor:
|
||||
text: "1"
|
||||
text: "1"
|
||||
|
122
src/Jackett/Definitions/speedtorrentreloaded.yml
Normal file
122
src/Jackett/Definitions/speedtorrentreloaded.yml
Normal file
@@ -0,0 +1,122 @@
|
||||
---
|
||||
site: speedtorrentreloaded
|
||||
name: SpeedTorrent Reloaded
|
||||
language: de-de
|
||||
type: private
|
||||
encoding: UTF-8
|
||||
links:
|
||||
- https://speedtorrent-tracker.mine.nu/
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
- {id: 201, cat: Movies/HD, desc: "Filme: HD 720P / 1080P"}
|
||||
- {id: 103, cat: Movies/DVD, desc: "Filme: DVD"}
|
||||
- {id: 104, cat: Movies/DVD, desc: "Filme: HD2DVD"}
|
||||
- {id: 137, cat: Audio/Video, desc: "Musik: Video"}
|
||||
- {id: 106, cat: Movies/SD, desc: "Filme: DVDRip"}
|
||||
- {id: 107, cat: Movies/SD, desc: "Filme: BDRip "}
|
||||
- {id: 108, cat: Movies/3D, desc: "Filme: 3D"}
|
||||
- {id: 109, cat: Movies/BluRay, desc: "Filme: Blue Ray"}
|
||||
- {id: 111, cat: Movies/SD, desc: "Filme: SD"}
|
||||
- {id: 112, cat: Movies/Other, desc: "Filme: TV/HDTV"}
|
||||
- {id: 203, cat: XXX, desc: "Erotik: XXX PDF"}
|
||||
- {id: 116, cat: Console, desc: "Spiele: Konsolen"}
|
||||
- {id: 117, cat: PC/Games, desc: "Spiele: Windows / Mac"}
|
||||
- {id: 126, cat: PC/0day, desc: "Software: Mac / Linux"}
|
||||
- {id: 120, cat: Audio/Other, desc: "Musik: Alben/Sampler "}
|
||||
- {id: 121, cat: TV/SD, desc: "Serien: SD"}
|
||||
- {id: 123, cat: TV/Documentary, desc: "Doku: sonstige"}
|
||||
- {id: 124, cat: Console/Other, desc: "Spiele: sonstige"}
|
||||
- {id: 125, cat: PC/0day, desc: "Software: Windows"}
|
||||
- {id: 129, cat: PC/Phone-Other, desc: "Software: Handy / Navi / Sonst"}
|
||||
- {id: 131, cat: TV/HD, desc: "Serien: HD"}
|
||||
- {id: 132, cat: TV, desc: "Serien: Packs"}
|
||||
- {id: 135, cat: Audio, desc: "Musik: Discographie"}
|
||||
- {id: 138, cat: TV/Documentary, desc: "Doku: HD"}
|
||||
- {id: 139, cat: TV/Documentary, desc: "Doku: x264"}
|
||||
- {id: 141, cat: Audio/Audiobook, desc: "A/Ebook: Hoerbook"}
|
||||
- {id: 142, cat: Books, desc: "A/Ebook: EBooks"}
|
||||
- {id: 143, cat: Books, desc: "sonstige:PDF"}
|
||||
- {id: 144, cat: XXX, desc: "Erotik: XXX Pics"}
|
||||
- {id: 202, cat: TV/Sport, desc: "Sport"}
|
||||
- {id: 204, cat: XXX, desc: "XXX-Games"}
|
||||
- {id: 205, cat: Movies/SD, desc: "International-SD"}
|
||||
- {id: 206, cat: movies/HD, desc: "International-HD"}
|
||||
|
||||
modes:
|
||||
search: [q]
|
||||
tv-search: [q, season, ep]
|
||||
movie-search: [q]
|
||||
|
||||
login:
|
||||
path: takelogin.php
|
||||
method: post
|
||||
inputs:
|
||||
username: "{{ .Config.username }}"
|
||||
password: "{{ .Config.password }}"
|
||||
test:
|
||||
path: browse.php
|
||||
|
||||
search:
|
||||
path: browse.php
|
||||
inputs:
|
||||
$raw: "{{range .Categories}}c{{.}}=1&{{end}}"
|
||||
search: "{{ .Query.Keywords }}"
|
||||
incldead: "1"
|
||||
orderby: "added"
|
||||
sort: desc
|
||||
rows:
|
||||
selector: table.tableinborder > tbody > tr > td > table.tableinborder > tbody > tr:has(a[href^="details.php"])
|
||||
fields:
|
||||
title:
|
||||
selector: a[href^="details.php"]
|
||||
banner:
|
||||
selector: a[href^="details.php"][onmouseover]
|
||||
attribute: onmouseover
|
||||
filters:
|
||||
- name: regexp
|
||||
args: "<img src=(.*)>')"
|
||||
category:
|
||||
selector: a[href^="browse.php?cat="]
|
||||
attribute: href
|
||||
filters:
|
||||
- name: querystring
|
||||
args: cat
|
||||
details:
|
||||
selector: a[href^="details.php"]
|
||||
attribute: href
|
||||
comments:
|
||||
selector: a[href*="&tocomm="]
|
||||
attribute: href
|
||||
download:
|
||||
selector: a[href^="download.php"]
|
||||
attribute: href
|
||||
files:
|
||||
selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(1) > b:nth-child(2)
|
||||
grabs:
|
||||
selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(3) > b:nth-child(1)
|
||||
size:
|
||||
selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(1) > b:nth-child(1)
|
||||
filters:
|
||||
- name: replace
|
||||
args: [".", ""]
|
||||
- name: replace
|
||||
args: [",", "."]
|
||||
seeders:
|
||||
selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(2) > b:nth-child(1)
|
||||
leechers:
|
||||
selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(2) > b:nth-child(3)
|
||||
date:
|
||||
selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(5)
|
||||
filters:
|
||||
- name: append
|
||||
args: " +2:00"
|
||||
- name: dateparse
|
||||
args: "02.01.2006 15:04:05 -07:00"
|
||||
downloadvolumefactor:
|
||||
case:
|
||||
img[title="OnlyUp"]: "0"
|
||||
"*": "1"
|
||||
uploadvolumefactor:
|
||||
case:
|
||||
"*": "1"
|
37
src/Jackett/Definitions/t411v2.yml
Normal file → Executable file
37
src/Jackett/Definitions/t411v2.yml
Normal file → Executable file
@@ -2,14 +2,21 @@
|
||||
site: t411v2
|
||||
name: t411 v2
|
||||
language: fr-fr
|
||||
type: semi-private
|
||||
type: public
|
||||
encoding: UTF-8
|
||||
links:
|
||||
- https://t411.si
|
||||
caps:
|
||||
categorymappings:
|
||||
- {id: 1, cat: Movies}
|
||||
- {id: 2, cat: TV}
|
||||
- {id: 1, cat: Movies, desc: Films}
|
||||
- {id: 2, cat: TV, desc: Séries}
|
||||
- {id: 3, cat: TV/Anime, desc: Animes}
|
||||
- {id: 4, cat: Audio, desc: Musique}
|
||||
- {id: 5, cat: Books, desc: Ebooks}
|
||||
- {id: 6, cat: PC/0day, desc: Logiciels}
|
||||
- {id: 7, cat: PC/Games, desc: Jeux}
|
||||
- {id: 8, cat: TV/Documentary, desc: Documentaires}
|
||||
- {id: 9, cat: XXX, desc: XXX}
|
||||
modes:
|
||||
search: [q]
|
||||
tv-search: [q, season, ep]
|
||||
@@ -21,17 +28,23 @@
|
||||
search:
|
||||
path: /torrents/search/?search={{ .Keywords}}
|
||||
rows:
|
||||
selector: div.isItem
|
||||
selector: tr.isItem.isItemDesk
|
||||
fields:
|
||||
category:
|
||||
selector: td.m-cat > a
|
||||
attribute: href
|
||||
filters:
|
||||
- name: querystring
|
||||
args: category
|
||||
site_date:
|
||||
selector: div.gname a
|
||||
selector: td.m-name > a
|
||||
filters:
|
||||
# date is at the end of the title, so we get it and name it
|
||||
# site_date
|
||||
- name: regexp
|
||||
args: "(\\w+)$"
|
||||
title:
|
||||
selector: div.gname a
|
||||
selector: td.m-name > a
|
||||
filters:
|
||||
# now we put the date at the right place according scene
|
||||
# naming rules using .Result.site_date
|
||||
@@ -45,13 +58,13 @@
|
||||
- name: re_replace
|
||||
args: ["(\\w+)$", ""]
|
||||
details:
|
||||
selector: div.gname a
|
||||
selector: td.m-name > a
|
||||
attribute: href
|
||||
download:
|
||||
selector: div.gname a
|
||||
selector: td.m-name > a
|
||||
attribute: href
|
||||
size:
|
||||
selector: div.gsmall:nth-child(5) span
|
||||
selector: td.m-taille > span
|
||||
filters:
|
||||
- name: re_replace
|
||||
args: [ "\\.(\\w+) K", "$1X00"]
|
||||
@@ -68,19 +81,19 @@
|
||||
seeders:
|
||||
text: 0
|
||||
seeders:
|
||||
selector: div.gsmall:nth-child(6)
|
||||
selector: td.m-seeders > span
|
||||
optional: true
|
||||
leechers:
|
||||
text: 0
|
||||
leechers:
|
||||
selector: div.gsmall:nth-child(7)
|
||||
selector: td.m-leechers > span
|
||||
optional: true
|
||||
downloadvolumefactor:
|
||||
text: "0"
|
||||
uploadvolumefactor:
|
||||
text: "1"
|
||||
date:
|
||||
selector: div.gsmall:nth-child(4) span
|
||||
selector: td.m-age > span
|
||||
filters:
|
||||
- name: replace
|
||||
args: [ " jours", " days"]
|
||||
|
@@ -71,6 +71,9 @@
|
||||
keywords: "{{ .Keywords }}"
|
||||
search_type: "t_name"
|
||||
include_dead_torrents: "yes"
|
||||
keywordsfilters:
|
||||
- name: re_replace
|
||||
args: ["[^a-zA-Z0-9]+", "%"]
|
||||
rows:
|
||||
selector: table#sortabletable > tbody > tr:has(a[href])
|
||||
fields:
|
||||
|
@@ -110,9 +110,6 @@
|
||||
test:
|
||||
path: index.php
|
||||
|
||||
download:
|
||||
selector: a[href^="download.php?id="]
|
||||
|
||||
search:
|
||||
path: browse.php
|
||||
inputs:
|
||||
@@ -130,11 +127,8 @@
|
||||
title:
|
||||
selector: td:nth-child(2)
|
||||
download:
|
||||
selector: a[href^="/details.php?id="]
|
||||
selector: a[href^="/download.php/"]
|
||||
attribute: href
|
||||
filters:
|
||||
- name: replace
|
||||
args: ["/details.php?id=", "/download.php?id="]
|
||||
details:
|
||||
selector: a[href^="/details.php?id="]
|
||||
attribute: href
|
||||
|
@@ -43,6 +43,10 @@
|
||||
- name: password
|
||||
type: password
|
||||
label: Password
|
||||
- name: filter_title
|
||||
type: checkbox
|
||||
label: Try to normalize releases names by moving year after the title
|
||||
default: false
|
||||
login:
|
||||
path: "/user/login"
|
||||
method: post
|
||||
@@ -93,8 +97,23 @@
|
||||
args: [ " an", " year"]
|
||||
- name: append
|
||||
args: " ago"
|
||||
title:
|
||||
title_normal:
|
||||
selector: "a.torrent-name"
|
||||
title_filtered:
|
||||
selector: "a.torrent-name"
|
||||
filters:
|
||||
- name: re_replace
|
||||
args: ["(?i)^(?:(.+?)((?:[\\.\\-\\s_\\[]+(?:imax|(?:dvd|bd|tv)(?:rip|scr)|bluray(?:\\-?rip)?|720\\s*p?|1080\\s*p?|vof?|vost(?:fr)?|multi|vf(?:f|q)?[1-3]?|(?:true)?french|eng?)[\\.\\-\\s_\\]]*)*)([\\(\\[]?(?:20|1[7-9])\\d{2}[\\)\\]]?)(.*)$|(.*))$", "$1 $3 $2 $4 $5"]
|
||||
- name: replace
|
||||
args: [".", " "]
|
||||
- name: trim
|
||||
- name: re_replace
|
||||
args: ["(?i)\\s(mkv|avi|divx|xvid|mp4)$", ""]
|
||||
- name: re_replace
|
||||
args: ["(\\s{2,5})", " "]
|
||||
- name: trim
|
||||
title:
|
||||
text: "{{if .Config.filter_title }}{{ .Result.title_filtered }}{{else}}{{ .Result.title_normal }}{{end}}"
|
||||
details:
|
||||
selector: "a.torrent-name"
|
||||
attribute: href
|
||||
|
4
src/Jackett/Definitions/zetorrents.yml
Normal file → Executable file
4
src/Jackett/Definitions/zetorrents.yml
Normal file → Executable file
@@ -24,7 +24,7 @@
|
||||
search:
|
||||
path: "/recherche/{{ .Query.Keywords }}"
|
||||
rows:
|
||||
selector: div.content-list-torrent > table tbody tr
|
||||
selector: div.content-list-torrent > table tbody tr:has(a)
|
||||
fields:
|
||||
site_date:
|
||||
selector: td:nth-child(1) a
|
||||
@@ -85,4 +85,4 @@
|
||||
downloadvolumefactor:
|
||||
text: "0"
|
||||
uploadvolumefactor:
|
||||
text: "1"
|
||||
text: "1"
|
||||
|
30
src/Jackett/IndexerException.cs
Normal file
30
src/Jackett/IndexerException.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using Jackett.Indexers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Jackett
|
||||
{
|
||||
class IndexerException : Exception
|
||||
{
|
||||
public IIndexer Indexer { get; protected set; }
|
||||
|
||||
public IndexerException(IIndexer Indexer, string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{
|
||||
this.Indexer = Indexer;
|
||||
}
|
||||
|
||||
public IndexerException(IIndexer Indexer, string message)
|
||||
: this(Indexer, message, null)
|
||||
{
|
||||
}
|
||||
|
||||
public IndexerException(IIndexer Indexer, Exception innerException)
|
||||
: this(Indexer, "Exception (" + Indexer.ID + "): " + innerException.Message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@@ -228,7 +228,8 @@ namespace Jackett.Indexers.Abstract
|
||||
{
|
||||
release.DownloadVolumeFactor = 0;
|
||||
}
|
||||
if ((bool)torrent["isPersonalFreeleech"])
|
||||
var isPersonalFreeleech = (bool?)torrent["isPersonalFreeleech"];
|
||||
if (isPersonalFreeleech != null && isPersonalFreeleech == true)
|
||||
{
|
||||
release.DownloadVolumeFactor = 0;
|
||||
}
|
||||
|
@@ -219,23 +219,30 @@ namespace Jackett.Indexers
|
||||
|
||||
public abstract Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson);
|
||||
|
||||
public virtual async Task<IEnumerable<ReleaseInfo>> ResultsForQuery(TorznabQuery query)
|
||||
public virtual async Task<IndexerResult> ResultsForQuery(TorznabQuery query)
|
||||
{
|
||||
if (!CanHandleQuery(query))
|
||||
return new ReleaseInfo[0];
|
||||
var results = await PerformQuery(query);
|
||||
results = FilterResults(query, results);
|
||||
results = results.Select(r =>
|
||||
try
|
||||
{
|
||||
r.Origin = this;
|
||||
if (!CanHandleQuery(query))
|
||||
return new IndexerResult(this, new ReleaseInfo[0]);
|
||||
var results = await PerformQuery(query);
|
||||
results = FilterResults(query, results);
|
||||
results = results.Select(r =>
|
||||
{
|
||||
r.Origin = this;
|
||||
|
||||
// Some trackers do not keep their clocks up to date and can be ~20 minutes out!
|
||||
if (r.PublishDate > DateTime.Now)
|
||||
r.PublishDate = DateTime.Now;
|
||||
return r;
|
||||
});
|
||||
// Some trackers do not keep their clocks up to date and can be ~20 minutes out!
|
||||
if (r.PublishDate > DateTime.Now)
|
||||
r.PublishDate = DateTime.Now;
|
||||
return r;
|
||||
});
|
||||
|
||||
return results;
|
||||
return new IndexerResult(this, results);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new IndexerException(this, ex);
|
||||
}
|
||||
}
|
||||
protected abstract Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query);
|
||||
}
|
||||
@@ -667,12 +674,12 @@ namespace Jackett.Indexers
|
||||
return releases;
|
||||
}
|
||||
|
||||
public override async Task<IEnumerable<ReleaseInfo>> ResultsForQuery(TorznabQuery query)
|
||||
public override async Task<IndexerResult> ResultsForQuery(TorznabQuery query)
|
||||
{
|
||||
var results = await base.ResultsForQuery(query);
|
||||
results = CleanLinks(results);
|
||||
var result = await base.ResultsForQuery(query);
|
||||
result.Releases = CleanLinks(result.Releases);
|
||||
|
||||
return results;
|
||||
return result;
|
||||
}
|
||||
|
||||
protected virtual Uri UncleanLink(Uri link)
|
||||
|
@@ -1,234 +0,0 @@
|
||||
using Jackett.Utils.Clients;
|
||||
using NLog;
|
||||
using Jackett.Services;
|
||||
using Jackett.Utils;
|
||||
using Jackett.Models;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Collections.Generic;
|
||||
using CsQuery;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Jackett.Models.IndexerConfig;
|
||||
using System.Collections.Specialized;
|
||||
using System.Text;
|
||||
|
||||
namespace Jackett.Indexers
|
||||
{
|
||||
public class BestFriends : BaseWebIndexer
|
||||
{
|
||||
string LoginUrl { get { return SiteLink + "login.php"; } }
|
||||
string TakeLoginUrl { get { return SiteLink + "takelogin.php"; } }
|
||||
string BrowseUrl { get { return SiteLink + "browse.php"; } }
|
||||
|
||||
new ConfigurationDataCaptchaLogin configData
|
||||
{
|
||||
get { return (ConfigurationDataCaptchaLogin)base.configData; }
|
||||
set { base.configData = value; }
|
||||
}
|
||||
|
||||
public BestFriends(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
|
||||
: base(name: "Best Friends",
|
||||
description: "A German general tracker.",
|
||||
link: "http://bf.mine.nu/",
|
||||
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
|
||||
configService: configService,
|
||||
client: wc,
|
||||
logger: l,
|
||||
p: ps,
|
||||
configData: new ConfigurationDataCaptchaLogin())
|
||||
{
|
||||
Encoding = Encoding.GetEncoding("iso-8859-1");
|
||||
Language = "de-de";
|
||||
Type = "private";
|
||||
|
||||
AddCategoryMapping(18, TorznabCatType.TVAnime); // Anime
|
||||
AddCategoryMapping(8, TorznabCatType.PCMac); // Appz MAC
|
||||
AddCategoryMapping(9, TorznabCatType.PC); // Appz other
|
||||
AddCategoryMapping(7, TorznabCatType.PC); // Appz Windows
|
||||
AddCategoryMapping(23, TorznabCatType.TVDocumentary); // Dokumentationen
|
||||
AddCategoryMapping(32, TorznabCatType.Movies3D); // DVD 3D
|
||||
AddCategoryMapping(15, TorznabCatType.Books); // eBooks
|
||||
AddCategoryMapping(12, TorznabCatType.PCGames); // Games PC
|
||||
AddCategoryMapping(37, TorznabCatType.PCPhoneOther); // Handy_Mobile
|
||||
AddCategoryMapping(24, TorznabCatType.TVHD); // HDTV
|
||||
AddCategoryMapping(22, TorznabCatType.AudioAudiobook); // Hörbücher
|
||||
AddCategoryMapping(1, TorznabCatType.MoviesHD); // Movies 1080p/1080i
|
||||
AddCategoryMapping(31, TorznabCatType.Movies3D); // Movies 3D
|
||||
AddCategoryMapping(2, TorznabCatType.MoviesHD); // Movies 720p/720i
|
||||
AddCategoryMapping(21, TorznabCatType.MoviesBluRay); // Movies BluRay
|
||||
AddCategoryMapping(5, TorznabCatType.MoviesDVD); // Movies DVD/HDDVD
|
||||
AddCategoryMapping(6, TorznabCatType.MoviesSD); // Movies M/SVCD/Other
|
||||
AddCategoryMapping(4, TorznabCatType.MoviesSD); // Movies XVID/DIVX/h.264
|
||||
AddCategoryMapping(10, TorznabCatType.Audio); // Music
|
||||
AddCategoryMapping(25, TorznabCatType.AudioVideo); // Musikvideo
|
||||
AddCategoryMapping(29, TorznabCatType.ConsoleNDS); // Nintendo DS
|
||||
AddCategoryMapping(16, TorznabCatType.Other); // other
|
||||
AddCategoryMapping(13, TorznabCatType.ConsolePS4); // Playstation
|
||||
AddCategoryMapping(28, TorznabCatType.TVHD); // Serien HD
|
||||
AddCategoryMapping(11, TorznabCatType.TVSD); // Serien XviD
|
||||
AddCategoryMapping(33, TorznabCatType.Other); // Specials
|
||||
AddCategoryMapping(30, TorznabCatType.TVSport); // Sport
|
||||
AddCategoryMapping(19, TorznabCatType.TVOTHER); // TVRip
|
||||
AddCategoryMapping(38, TorznabCatType.TVDocumentary); // US Dokus
|
||||
AddCategoryMapping(20, TorznabCatType.MoviesForeign); // US Movies
|
||||
AddCategoryMapping(14, TorznabCatType.TVFOREIGN); // US Serien
|
||||
AddCategoryMapping(36, TorznabCatType.Other); // Wallpaper
|
||||
AddCategoryMapping(26, TorznabCatType.ConsoleWii); // Wii
|
||||
AddCategoryMapping(27, TorznabCatType.ConsoleXbox360); // Xbox 360
|
||||
AddCategoryMapping(3, TorznabCatType.XXX); // XXX
|
||||
}
|
||||
|
||||
public override async Task<ConfigurationData> GetConfigurationForSetup()
|
||||
{
|
||||
var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty);
|
||||
CQ dom = loginPage.Content;
|
||||
CQ qCaptchaImg = dom.Find("td.tablea > img").First();
|
||||
|
||||
var CaptchaUrl = SiteLink + qCaptchaImg.Attr("src");
|
||||
var captchaImage = await RequestBytesWithCookies(CaptchaUrl, loginPage.Cookies);
|
||||
configData.CaptchaImage.Value = captchaImage.Content;
|
||||
configData.CaptchaCookie.Value = loginPage.Cookies;
|
||||
return configData;
|
||||
}
|
||||
|
||||
public override async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
|
||||
{
|
||||
LoadValuesFromJson(configJson);
|
||||
|
||||
var pairs1 = new Dictionary<string, string>
|
||||
{
|
||||
{ "proofcode", configData.CaptchaText.Value }
|
||||
};
|
||||
var cookies = configData.CaptchaCookie.Value;
|
||||
var result1 = await RequestLoginAndFollowRedirect(LoginUrl, pairs1, cookies, true, null, LoginUrl, true);
|
||||
if(result1.Content == null || !result1.Content.Contains("takelogin.php"))
|
||||
{
|
||||
CQ dom = result1.Content;
|
||||
var errorMessage = dom["#login_error"].Text().Trim();
|
||||
errorMessage = result1.Content;
|
||||
throw new ExceptionWithConfigData(errorMessage, configData);
|
||||
}
|
||||
|
||||
var pairs2 = new Dictionary<string, string>
|
||||
{
|
||||
{ "username", configData.Username.Value },
|
||||
{ "password", configData.Password.Value }
|
||||
};
|
||||
|
||||
var result = await RequestLoginAndFollowRedirect(TakeLoginUrl, pairs2, result1.Cookies, true, null, LoginUrl, true);
|
||||
await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () =>
|
||||
{
|
||||
CQ dom = result.Content;
|
||||
var errorMessage = dom["#login_error"].Text().Trim();
|
||||
errorMessage = result.Content;
|
||||
throw new ExceptionWithConfigData(errorMessage, configData);
|
||||
});
|
||||
return IndexerConfigurationStatus.RequiresTesting;
|
||||
}
|
||||
|
||||
protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
|
||||
{
|
||||
TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 3, 0, 0), 3, 5, DayOfWeek.Sunday);
|
||||
TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 4, 0, 0), 10, 5, DayOfWeek.Sunday);
|
||||
TimeSpan delta = new TimeSpan(1, 0, 0);
|
||||
TimeZoneInfo.AdjustmentRule adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1999, 10, 1), DateTime.MaxValue.Date, delta, startTransition, endTransition);
|
||||
TimeZoneInfo.AdjustmentRule[] adjustments = { adjustment };
|
||||
TimeZoneInfo germanyTz = TimeZoneInfo.CreateCustomTimeZone("W. Europe Standard Time", new TimeSpan(1, 0, 0), "(GMT+01:00) W. Europe Standard Time", "W. Europe Standard Time", "W. Europe DST Time", adjustments);
|
||||
|
||||
var releases = new List<ReleaseInfo>();
|
||||
|
||||
var searchString = query.GetQueryString();
|
||||
var searchUrl = BrowseUrl;
|
||||
var queryCollection = new NameValueCollection();
|
||||
queryCollection.Add("showsearch", "1");
|
||||
queryCollection.Add("incldead", "1");
|
||||
queryCollection.Add("blah", "0");
|
||||
queryCollection.Add("orderby", "added");
|
||||
queryCollection.Add("sort", "desc");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(searchString))
|
||||
{
|
||||
queryCollection.Add("search", searchString);
|
||||
}
|
||||
|
||||
foreach (var cat in MapTorznabCapsToTrackers(query))
|
||||
{
|
||||
queryCollection.Add("c" + cat, "1");
|
||||
}
|
||||
searchUrl += "?" + queryCollection.GetQueryString();
|
||||
|
||||
var response = await RequestStringWithCookiesAndRetry(searchUrl, null, BrowseUrl);
|
||||
var results = response.Content;
|
||||
try
|
||||
{
|
||||
CQ dom = results;
|
||||
var rows = dom["table.tableinborder > tbody > tr:has(td.tableb)"];
|
||||
|
||||
foreach (var row in rows)
|
||||
{
|
||||
var release = new ReleaseInfo();
|
||||
release.MinimumRatio = 0.75;
|
||||
release.MinimumSeedTime = 0;
|
||||
var qRow = row.Cq();
|
||||
|
||||
var qDetailsLink = qRow.Find("a[href^=details.php?id=]").First();
|
||||
release.Title = qDetailsLink.Attr("title");
|
||||
|
||||
if (!query.MatchQueryStringAND(release.Title))
|
||||
continue;
|
||||
|
||||
var qCatLink = qRow.Find("a[href^=browse.php?cat=]").First();
|
||||
|
||||
// use negative indexes as if a user has "Wartezeit" there's an extra column after the title
|
||||
var qSeeders = qRow.Find("td:nth-last-child(4)");
|
||||
var qLeechers = qRow.Find("td:nth-last-child(3)");
|
||||
var qDateStr = qRow.Find("td:nth-last-child(7)");
|
||||
var qSize = qRow.Find("td:nth-last-child(6)");
|
||||
|
||||
var torrentId = qDetailsLink.Attr("href").Replace("&hit=1", "").Split('=')[1];
|
||||
|
||||
var catStr = qCatLink.Attr("href").Split('=')[1];
|
||||
release.Category = MapTrackerCatToNewznab(catStr);
|
||||
|
||||
release.Link = new Uri(SiteLink + "download.php?torrent="+torrentId);
|
||||
release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href"));
|
||||
release.Guid = release.Link;
|
||||
|
||||
var sizeStr = qSize.Text();
|
||||
release.Size = ReleaseInfo.GetBytes(sizeStr.Replace(",", "."));
|
||||
|
||||
release.Seeders = ParseUtil.CoerceInt(qSeeders.Text());
|
||||
release.Peers = ParseUtil.CoerceInt(qLeechers.Text()) + release.Seeders;
|
||||
|
||||
var dateStr = qDateStr.Text();
|
||||
var dateGerman = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "dd.MM.yyyyHH:mm:ss", CultureInfo.InvariantCulture), DateTimeKind.Unspecified);
|
||||
DateTime pubDateUtc = TimeZoneInfo.ConvertTimeToUtc(dateGerman, germanyTz);
|
||||
release.PublishDate = pubDateUtc;
|
||||
|
||||
var files = qRow.Find("td:nth-last-child(9)").Text();
|
||||
release.Files = ParseUtil.CoerceInt(files);
|
||||
|
||||
var grabs = qRow.Find("td:nth-last-child(5)").Text();
|
||||
release.Grabs = ParseUtil.CoerceInt(grabs);
|
||||
|
||||
if (qRow.Find("font[color=\"red\"]:contains(OnlyUp)").Length >= 1)
|
||||
release.DownloadVolumeFactor = 0;
|
||||
else
|
||||
release.DownloadVolumeFactor = 1;
|
||||
|
||||
release.UploadVolumeFactor = 1;
|
||||
|
||||
releases.Add(release);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnParseError(results, ex);
|
||||
}
|
||||
|
||||
return releases;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -27,9 +27,9 @@ namespace Jackett.Indexers
|
||||
|
||||
public BroadcastTheNet(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
|
||||
: base(name: "BroadcastTheNet",
|
||||
description: "Needs no description..",
|
||||
description: null,
|
||||
link: "https://broadcasthe.net/",
|
||||
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
|
||||
caps: new TorznabCapabilities(),
|
||||
configService: configService,
|
||||
client: wc,
|
||||
logger: l,
|
||||
@@ -39,6 +39,16 @@ namespace Jackett.Indexers
|
||||
Encoding = Encoding.UTF8;
|
||||
Language = "en-us";
|
||||
Type = "private";
|
||||
|
||||
TorznabCaps.LimitsDefault = 100;
|
||||
TorznabCaps.LimitsMax = 1000;
|
||||
|
||||
AddCategoryMapping("SD", TorznabCatType.TVSD, "SD");
|
||||
AddCategoryMapping("720p", TorznabCatType.TVHD, "720p");
|
||||
AddCategoryMapping("1080p", TorznabCatType.TVHD, "1080p");
|
||||
AddCategoryMapping("1080i", TorznabCatType.TVHD, "1080i");
|
||||
AddCategoryMapping("2160p", TorznabCatType.TVHD, "2160p");
|
||||
AddCategoryMapping("Portable Device", TorznabCatType.TVSD, "Portable Device");
|
||||
}
|
||||
|
||||
public override async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
|
||||
@@ -76,13 +86,17 @@ namespace Jackett.Indexers
|
||||
protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
|
||||
{
|
||||
var searchString = query.GetQueryString();
|
||||
var btnResults = query.Limit;
|
||||
if (btnResults == 0)
|
||||
btnResults = (int)TorznabCaps.LimitsDefault;
|
||||
var btnOffset = query.Offset;
|
||||
var releases = new List<ReleaseInfo>();
|
||||
|
||||
var parameters = new JArray();
|
||||
parameters.Add(new JValue(configData.Key.Value));
|
||||
parameters.Add(new JValue(searchString.Trim()));
|
||||
parameters.Add(new JValue(100));
|
||||
parameters.Add(new JValue(0));
|
||||
parameters.Add(new JValue(btnResults));
|
||||
parameters.Add(new JValue(btnOffset));
|
||||
var response = await PostDataWithCookiesAndRetry(APIBASE, null, null, null, new Dictionary<string, string>()
|
||||
{
|
||||
{ "Accept", "application/json-rpc, application/json"},
|
||||
@@ -93,17 +107,19 @@ namespace Jackett.Indexers
|
||||
{
|
||||
var btnResponse = JsonConvert.DeserializeObject<BTNRPCResponse>(response.Content);
|
||||
|
||||
if (btnResponse != null && btnResponse.Result != null)
|
||||
if (btnResponse != null && btnResponse.Result != null && btnResponse.Result.Torrents != null)
|
||||
{
|
||||
foreach (var itemKey in btnResponse.Result.Torrents)
|
||||
{
|
||||
var descriptions = new List<string>();
|
||||
var btnResult = itemKey.Value;
|
||||
var item = new ReleaseInfo();
|
||||
if (!string.IsNullOrEmpty(btnResult.SeriesBanner))
|
||||
item.BannerUrl = new Uri(btnResult.SeriesBanner);
|
||||
item.Category = new List<int> { TorznabCatType.TV.ID };
|
||||
item.Comments = new Uri($"https://broadcasthe.net/torrents.php?id={btnResult.GroupID}&torrentid={btnResult.TorrentID}");
|
||||
item.Description = btnResult.ReleaseName;
|
||||
item.Category = MapTrackerCatToNewznab(btnResult.Resolution);
|
||||
if (item.Category.Count == 0) // default to TV
|
||||
item.Category.Add(TorznabCatType.TV.ID);
|
||||
item.Comments = new Uri($"{SiteLink}torrents.php?id={btnResult.GroupID}&torrentid={btnResult.TorrentID}");
|
||||
item.Guid = new Uri(btnResult.DownloadURL);
|
||||
if (!string.IsNullOrWhiteSpace(btnResult.ImdbID))
|
||||
item.Imdb = ParseUtil.CoerceLong(btnResult.ImdbID);
|
||||
@@ -116,6 +132,29 @@ namespace Jackett.Indexers
|
||||
item.Size = btnResult.Size;
|
||||
item.TVDBId = btnResult.TvdbID;
|
||||
item.Title = btnResult.ReleaseName;
|
||||
item.UploadVolumeFactor = 1;
|
||||
item.DownloadVolumeFactor = 0; // ratioless
|
||||
item.Grabs = btnResult.Snatched;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(btnResult.Series))
|
||||
descriptions.Add("Series: " + btnResult.Series);
|
||||
if (!string.IsNullOrWhiteSpace(btnResult.GroupName))
|
||||
descriptions.Add("Group Name: " + btnResult.GroupName);
|
||||
if (!string.IsNullOrWhiteSpace(btnResult.Source))
|
||||
descriptions.Add("Source: " + btnResult.Source);
|
||||
if (!string.IsNullOrWhiteSpace(btnResult.Container))
|
||||
descriptions.Add("Container: " + btnResult.Container);
|
||||
if (!string.IsNullOrWhiteSpace(btnResult.Codec))
|
||||
descriptions.Add("Codec: " + btnResult.Codec);
|
||||
if (!string.IsNullOrWhiteSpace(btnResult.Resolution))
|
||||
descriptions.Add("Resolution: " + btnResult.Resolution);
|
||||
if (!string.IsNullOrWhiteSpace(btnResult.Origin))
|
||||
descriptions.Add("Origin: " + btnResult.Origin);
|
||||
if (!string.IsNullOrWhiteSpace(btnResult.Series))
|
||||
descriptions.Add("Youtube Trailer: <a href=\"" + btnResult.YoutubeTrailer + "\">" + btnResult.YoutubeTrailer + "</a>");
|
||||
|
||||
item.Description = string.Join("<br />\n", descriptions);
|
||||
|
||||
releases.Add(item);
|
||||
}
|
||||
}
|
||||
|
@@ -106,6 +106,10 @@ namespace Jackett.Indexers
|
||||
{
|
||||
// ex: "Monday, Jun 01, 2015", "Monday, Aug 03, 2015"
|
||||
var dateStr = rowA.Cq().Text().Trim().Replace("Added on ", "");
|
||||
if (string.IsNullOrWhiteSpace(dateStr) || dateStr == "Sponsored links" || dateStr.StartsWith("!function")) // ignore ads
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (dateStr.ToLowerInvariant().Contains("today"))
|
||||
lastDateTime = DateTime.Now;
|
||||
else
|
||||
|
@@ -90,50 +90,53 @@ namespace Jackett.Indexers
|
||||
{
|
||||
//var json = JArray.Parse(results.Content);
|
||||
dynamic json = JsonConvert.DeserializeObject<dynamic>(results.Content);
|
||||
foreach (var row in json)
|
||||
{
|
||||
var release = new ReleaseInfo();
|
||||
var descriptions = new List<string>();
|
||||
var tags = new List<string>();
|
||||
|
||||
release.MinimumRatio = 0.5;
|
||||
release.MinimumSeedTime = 0;
|
||||
release.Title = row.name;
|
||||
release.Category = new List<int> { TorznabCatType.Audio.ID };
|
||||
release.Size = row.size;
|
||||
release.Seeders = row.seeders;
|
||||
release.Peers = row.leechers + release.Seeders;
|
||||
release.PublishDate = DateTime.ParseExact(row.added.ToString() + " +01:00", "yyyy-MM-dd HH:mm:ss zzz", CultureInfo.InvariantCulture);
|
||||
release.Files = row.numfiles;
|
||||
release.Grabs = row.times_completed;
|
||||
|
||||
release.Comments = new Uri(SiteLink + "torrent/" + row.id.ToString() + "/");
|
||||
release.Link = new Uri(SiteLink + "api/v1/torrents/download/" + row.id.ToString());
|
||||
|
||||
if (row.frileech == 1)
|
||||
release.DownloadVolumeFactor = 0;
|
||||
else
|
||||
release.DownloadVolumeFactor = 0.33;
|
||||
release.UploadVolumeFactor = 1;
|
||||
|
||||
if ((int)row.p2p == 1)
|
||||
tags.Add("P2P");
|
||||
if ((int)row.pack == 1)
|
||||
tags.Add("Pack");
|
||||
if ((int)row.reqid != 0)
|
||||
tags.Add("Archive");
|
||||
if ((int)row.flac != 0)
|
||||
if (json != null) // no results
|
||||
{
|
||||
foreach (var row in json)
|
||||
{
|
||||
tags.Add("FLAC");
|
||||
release.Category = new List<int> { TorznabCatType.AudioLossless.ID };
|
||||
var release = new ReleaseInfo();
|
||||
var descriptions = new List<string>();
|
||||
var tags = new List<string>();
|
||||
|
||||
release.MinimumRatio = 0.5;
|
||||
release.MinimumSeedTime = 0;
|
||||
release.Title = row.name;
|
||||
release.Category = new List<int> { TorznabCatType.Audio.ID };
|
||||
release.Size = row.size;
|
||||
release.Seeders = row.seeders;
|
||||
release.Peers = row.leechers + release.Seeders;
|
||||
release.PublishDate = DateTime.ParseExact(row.added.ToString() + " +01:00", "yyyy-MM-dd HH:mm:ss zzz", CultureInfo.InvariantCulture);
|
||||
release.Files = row.numfiles;
|
||||
release.Grabs = row.times_completed;
|
||||
|
||||
release.Comments = new Uri(SiteLink + "torrent/" + row.id.ToString() + "/");
|
||||
release.Link = new Uri(SiteLink + "api/v1/torrents/download/" + row.id.ToString());
|
||||
|
||||
if (row.frileech == 1)
|
||||
release.DownloadVolumeFactor = 0;
|
||||
else
|
||||
release.DownloadVolumeFactor = 0.33;
|
||||
release.UploadVolumeFactor = 1;
|
||||
|
||||
if ((int)row.p2p == 1)
|
||||
tags.Add("P2P");
|
||||
if ((int)row.pack == 1)
|
||||
tags.Add("Pack");
|
||||
if ((int)row.reqid != 0)
|
||||
tags.Add("Archive");
|
||||
if ((int)row.flac != 0)
|
||||
{
|
||||
tags.Add("FLAC");
|
||||
release.Category = new List<int> { TorznabCatType.AudioLossless.ID };
|
||||
}
|
||||
|
||||
if (tags.Count > 0)
|
||||
descriptions.Add("Tags: " + string.Join(", ", tags));
|
||||
|
||||
release.Description = string.Join("<br>\n", descriptions);
|
||||
|
||||
releases.Add(release);
|
||||
}
|
||||
|
||||
if (tags.Count > 0)
|
||||
descriptions.Add("Tags: " + string.Join(", ", tags));
|
||||
|
||||
release.Description = string.Join("<br>\n", descriptions);
|
||||
|
||||
releases.Add(release);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@@ -151,8 +151,11 @@ namespace Jackett.Indexers
|
||||
var cat = catUrl.Substring(catUrl.LastIndexOf('[') + 1).Trim(']');
|
||||
release.Category = MapTrackerCatToNewznab(cat);
|
||||
|
||||
// support both date format (profile settings)
|
||||
var qAdded = row.ChildElements.ElementAt(4).ChildElements.ElementAt(0).Cq();
|
||||
var addedStr = qAdded.Attr("title");
|
||||
if (!addedStr.Contains(","))
|
||||
addedStr = qAdded.Text();
|
||||
release.PublishDate = DateTime.ParseExact(addedStr, "MMM dd yyyy, HH:mm", CultureInfo.InvariantCulture);
|
||||
|
||||
var overlayScript = qRow.Find("script:contains(\"var overlay\")").Text();
|
||||
|
@@ -10,6 +10,18 @@ using System.Web.UI.WebControls;
|
||||
|
||||
namespace Jackett.Indexers
|
||||
{
|
||||
public class IndexerResult
|
||||
{
|
||||
public IIndexer Indexer { get; set; }
|
||||
public IEnumerable<ReleaseInfo> Releases { get; set; }
|
||||
|
||||
public IndexerResult(IIndexer Indexer, IEnumerable<ReleaseInfo> Releases)
|
||||
{
|
||||
this.Indexer = Indexer;
|
||||
this.Releases = Releases;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IIndexer
|
||||
{
|
||||
string SiteLink { get; }
|
||||
@@ -39,7 +51,7 @@ namespace Jackett.Indexers
|
||||
|
||||
void Unconfigure();
|
||||
|
||||
Task<IEnumerable<ReleaseInfo>> ResultsForQuery(TorznabQuery query);
|
||||
Task<IndexerResult> ResultsForQuery(TorznabQuery query);
|
||||
|
||||
bool CanHandleQuery(TorznabQuery query);
|
||||
}
|
||||
|
@@ -115,7 +115,7 @@ namespace Jackett.Indexers
|
||||
{
|
||||
CQ dom = results.Content;
|
||||
|
||||
var rows = dom["#sortabletable tr"];
|
||||
var rows = dom["#sortabletable tr:has(a[href*=\"details.php?id=\"])"];
|
||||
foreach (var row in rows.Skip(1))
|
||||
{
|
||||
var release = new ReleaseInfo();
|
||||
|
@@ -27,25 +27,32 @@ namespace Jackett.Indexers.Meta
|
||||
return Task.FromResult(IndexerConfigurationStatus.Completed);
|
||||
}
|
||||
|
||||
public override async Task<IEnumerable<ReleaseInfo>> ResultsForQuery(TorznabQuery query)
|
||||
public override async Task<IndexerResult> ResultsForQuery(TorznabQuery query)
|
||||
{
|
||||
if (!CanHandleQuery(query))
|
||||
return new ReleaseInfo[0];
|
||||
var results = await PerformQuery(query);
|
||||
var correctedResults = results.Select(r =>
|
||||
try
|
||||
{
|
||||
if (r.PublishDate > DateTime.Now)
|
||||
r.PublishDate = DateTime.Now;
|
||||
return r;
|
||||
});
|
||||
if (!CanHandleQuery(query))
|
||||
return new IndexerResult(this, new ReleaseInfo[0]);
|
||||
var results = await PerformQuery(query);
|
||||
var correctedResults = results.Select(r =>
|
||||
{
|
||||
if (r.PublishDate > DateTime.Now)
|
||||
r.PublishDate = DateTime.Now;
|
||||
return r;
|
||||
});
|
||||
|
||||
return correctedResults;
|
||||
return new IndexerResult(this, correctedResults);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new IndexerException(this, ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
|
||||
{
|
||||
var indexers = validIndexers;
|
||||
IEnumerable<Task<IEnumerable<ReleaseInfo>>> supportedTasks = indexers.Where(i => i.CanHandleQuery(query)).Select(i => i.ResultsForQuery(query)).ToList(); // explicit conversion to List to execute LINQ query
|
||||
IEnumerable<Task<IndexerResult>> supportedTasks = indexers.Where(i => i.CanHandleQuery(query)).Select(i => i.ResultsForQuery(query)).ToList(); // explicit conversion to List to execute LINQ query
|
||||
|
||||
var fallbackStrategies = fallbackStrategyProvider.FallbackStrategiesForQuery(query);
|
||||
var fallbackQueries = fallbackStrategies.Select(async f => await f.FallbackQueries()).SelectMany(t => t.Result);
|
||||
@@ -72,7 +79,7 @@ namespace Jackett.Indexers.Meta
|
||||
logger.Error(aggregateTask.Exception, "Error during request in metaindexer " + ID);
|
||||
}
|
||||
|
||||
var unorderedResult = aggregateTask.Result.Flatten();
|
||||
var unorderedResult = aggregateTask.Result.Select(r => r.Releases).Flatten();
|
||||
var resultFilters = resultFilterProvider.FiltersForQuery(query);
|
||||
var filteredResults = resultFilters.Select(async f => await f.FilterResults(unorderedResult)).SelectMany(t => t.Result);
|
||||
var uniqueFilteredResults = filteredResults.Distinct();
|
||||
|
@@ -16,6 +16,7 @@ using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace Jackett.Indexers
|
||||
{
|
||||
@@ -33,7 +34,7 @@ namespace Jackett.Indexers
|
||||
private bool Latency => ConfigData.Latency.Value;
|
||||
private bool DevMode => ConfigData.DevMode.Value;
|
||||
private bool CacheMode => ConfigData.HardDriveCache.Value;
|
||||
private static string Directory => System.IO.Path.GetTempPath() + "Jackett\\" + MethodBase.GetCurrentMethod().DeclaringType?.Name + "\\";
|
||||
private static string Directory => Path.Combine(Path.GetTempPath(), "Jackett", MethodBase.GetCurrentMethod().DeclaringType?.Name);
|
||||
|
||||
private readonly Dictionary<string, string> _emulatedBrowserHeaders = new Dictionary<string, string>();
|
||||
private CQ _fDom;
|
||||
@@ -49,7 +50,6 @@ namespace Jackett.Indexers
|
||||
client: w,
|
||||
logger: l,
|
||||
p: ps,
|
||||
downloadBase: "https://norbits.net/download.php?id=",
|
||||
configData: new ConfigurationDataNorbits())
|
||||
{
|
||||
Encoding = Encoding.GetEncoding("iso-8859-1");
|
||||
|
@@ -129,8 +129,7 @@ namespace Jackett.Indexers
|
||||
|
||||
release.MinimumRatio = 1;
|
||||
release.MinimumSeedTime = 129600;
|
||||
release.Title = qRow.Find(".ttr_name > a").Text();
|
||||
release.Description = release.Title;
|
||||
release.Title = qRow.Find(".ttr_name > a").Attr("title");
|
||||
release.Guid = new Uri(SiteLink + qRow.Find(".ttr_name > a").Attr("href"));
|
||||
release.Comments = release.Guid;
|
||||
release.Link = new Uri(SiteLink + qRow.Find(".td_dl > a").Attr("href"));
|
||||
|
@@ -6,19 +6,24 @@ using Jackett.Models;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Collections.Generic;
|
||||
using CsQuery;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Jackett.Models.IndexerConfig;
|
||||
using System.Collections.Specialized;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
using static Jackett.Models.IndexerConfig.ConfigurationData;
|
||||
|
||||
namespace Jackett.Indexers
|
||||
{
|
||||
public class TorrentNetwork : BaseWebIndexer
|
||||
{
|
||||
string LoginUrl { get { return SiteLink + "takelogin.php"; } }
|
||||
string BrowseUrl { get { return SiteLink + "browse.php"; } }
|
||||
string APIUrl { get { return SiteLink + "api/"; } }
|
||||
private string passkey;
|
||||
|
||||
private Dictionary<string, string> APIHeaders = new Dictionary<string, string>()
|
||||
{
|
||||
{"Content-Type", "application/json"},
|
||||
};
|
||||
|
||||
new ConfigurationDataBasicLoginWithRSSAndDisplay configData
|
||||
{
|
||||
@@ -28,9 +33,9 @@ namespace Jackett.Indexers
|
||||
|
||||
public TorrentNetwork(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
|
||||
: base(name: "Torrent Network",
|
||||
description: "A German general tracker.",
|
||||
description: null,
|
||||
link: "https://tntracker.org/",
|
||||
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
|
||||
caps: new TorznabCapabilities(),
|
||||
configService: configService,
|
||||
client: wc,
|
||||
logger: l,
|
||||
@@ -41,51 +46,93 @@ namespace Jackett.Indexers
|
||||
Language = "de-de";
|
||||
Type = "private";
|
||||
|
||||
AddCategoryMapping(1, TorznabCatType.AudioAudiobook); // aBook
|
||||
AddCategoryMapping(4, TorznabCatType.PCMac); // App|Mac
|
||||
AddCategoryMapping(5, TorznabCatType.PC); // App|Win
|
||||
AddCategoryMapping(7, TorznabCatType.TVDocumentary); // Docu|HD
|
||||
AddCategoryMapping(6, TorznabCatType.TVDocumentary); // Docu|SD
|
||||
AddCategoryMapping(8, TorznabCatType.Books); // eBook
|
||||
AddCategoryMapping(10, TorznabCatType.PCGames); // Game|PC
|
||||
AddCategoryMapping(13, TorznabCatType.ConsolePS4); // Game|PSX
|
||||
AddCategoryMapping(12, TorznabCatType.ConsoleWii); // Game|Wii
|
||||
AddCategoryMapping(14, TorznabCatType.ConsoleXbox); // Game|XBOX
|
||||
AddCategoryMapping(30, TorznabCatType.Other); // Misc
|
||||
AddCategoryMapping(17, TorznabCatType.MoviesHD); // Movie|DE|1080p
|
||||
AddCategoryMapping(20, TorznabCatType.MoviesHD); // Movie|DE|2160p
|
||||
AddCategoryMapping(36, TorznabCatType.Movies3D); // Movie|DE|3D
|
||||
AddCategoryMapping(18, TorznabCatType.MoviesHD); // Movie|DE|720p
|
||||
AddCategoryMapping(34, TorznabCatType.TVAnime); // Movie|DE|Anime
|
||||
AddCategoryMapping(19, TorznabCatType.MoviesBluRay); // Movie|DE|BluRay
|
||||
AddCategoryMapping(45, TorznabCatType.Movies); // Movie|DE|Remux
|
||||
AddCategoryMapping(24, TorznabCatType.MoviesSD); // Movie|DE|SD
|
||||
AddCategoryMapping(39, TorznabCatType.Movies); // Movie|EN/JP|Anime
|
||||
AddCategoryMapping(43, TorznabCatType.MoviesHD); // Movie|EN|1080p
|
||||
AddCategoryMapping(37, TorznabCatType.MoviesHD); // Movie|EN|2160p
|
||||
AddCategoryMapping(35, TorznabCatType.MoviesHD); // Movie|EN|720p
|
||||
AddCategoryMapping(38, TorznabCatType.MoviesBluRay); // Movie|EN|BluRay
|
||||
AddCategoryMapping(46, TorznabCatType.Movies); // Movie|EN|Remux
|
||||
AddCategoryMapping(22, TorznabCatType.MoviesSD); // Movie|EN|SD
|
||||
AddCategoryMapping(44, TorznabCatType.AudioLossless); // Music|Flac
|
||||
AddCategoryMapping(25, TorznabCatType.AudioMP3); // Music|MP3
|
||||
AddCategoryMapping(26, TorznabCatType.AudioVideo); // Music|Video
|
||||
AddCategoryMapping(31, TorznabCatType.TVSport); // Sport
|
||||
AddCategoryMapping(2, TorznabCatType.TVAnime); // TV|DE|Anime
|
||||
AddCategoryMapping(28, TorznabCatType.TVHD); // TV|DE|HD
|
||||
AddCategoryMapping(16, TorznabCatType.TV); // TV|DE|Pack
|
||||
AddCategoryMapping(27, TorznabCatType.TVSD); // TV|DE|SD
|
||||
AddCategoryMapping(41, TorznabCatType.TVAnime); // TV|EN/JP|Anime
|
||||
AddCategoryMapping(40, TorznabCatType.TVHD); // TV|EN|HD
|
||||
AddCategoryMapping(42, TorznabCatType.TV); // TV|EN|Pack
|
||||
AddCategoryMapping(29, TorznabCatType.TVSD); // TV|EN|SD
|
||||
AddCategoryMapping(33, TorznabCatType.XXX); // XXX|HD
|
||||
AddCategoryMapping(32, TorznabCatType.XXX); // XXX|SD
|
||||
configData.AddDynamic("token", new HiddenItem() { Name = "token" });
|
||||
configData.AddDynamic("passkey", new HiddenItem() { Name = "passkey" });
|
||||
|
||||
AddCategoryMapping(24, TorznabCatType.MoviesSD, "Movies GER/SD");
|
||||
AddCategoryMapping(18, TorznabCatType.MoviesHD, "Movies GER/720p");
|
||||
AddCategoryMapping(17, TorznabCatType.MoviesHD, "Movies GER/1080p");
|
||||
AddCategoryMapping(20, TorznabCatType.MoviesHD, "Movies GER/2160p");
|
||||
AddCategoryMapping(45, TorznabCatType.MoviesOther, "Movies GER/Remux");
|
||||
AddCategoryMapping(19, TorznabCatType.MoviesBluRay, "Movies GER/BluRay");
|
||||
AddCategoryMapping(34, TorznabCatType.TVAnime, "Movies GER/Anime");
|
||||
AddCategoryMapping(36, TorznabCatType.Movies3D, "Movies GER/3D");
|
||||
|
||||
AddCategoryMapping(22, TorznabCatType.MoviesSD, "Movies ENG/SD");
|
||||
AddCategoryMapping(35, TorznabCatType.MoviesHD, "Movies ENG/720p");
|
||||
AddCategoryMapping(43, TorznabCatType.MoviesHD, "Movies ENG/1080p");
|
||||
AddCategoryMapping(37, TorznabCatType.MoviesHD, "Movies ENG/2160p");
|
||||
AddCategoryMapping(46, TorznabCatType.MoviesOther, "Movies ENG/Remux");
|
||||
AddCategoryMapping(38, TorznabCatType.MoviesBluRay, "Movies ENG/BluRay");
|
||||
AddCategoryMapping(39, TorznabCatType.TVAnime, "Movies ENG/Anime");
|
||||
|
||||
AddCategoryMapping(27, TorznabCatType.TVSD, "Series GER/SD");
|
||||
AddCategoryMapping(28, TorznabCatType.TVHD, "Series GER/HD");
|
||||
AddCategoryMapping(2, TorznabCatType.TVAnime, "Series GER/Anime");
|
||||
AddCategoryMapping(16, TorznabCatType.TV, "Series GER/Pack");
|
||||
AddCategoryMapping(6, TorznabCatType.TVDocumentary, "Docu/SD");
|
||||
AddCategoryMapping(7, TorznabCatType.TVDocumentary, "Docu/HD");
|
||||
|
||||
AddCategoryMapping(29, TorznabCatType.TVSD, "Series ENG/SD");
|
||||
AddCategoryMapping(40, TorznabCatType.TVHD, "Series ENG/HD");
|
||||
AddCategoryMapping(41, TorznabCatType.TVAnime, "Series ENG/Anime");
|
||||
AddCategoryMapping(42, TorznabCatType.TV, "Series ENG/Pack");
|
||||
AddCategoryMapping(31, TorznabCatType.TVSport, "Sport");
|
||||
|
||||
|
||||
AddCategoryMapping(10, TorznabCatType.PCGames, "Games/Win");
|
||||
AddCategoryMapping(12, TorznabCatType.ConsoleWii, "Games/Wii");
|
||||
AddCategoryMapping(13, TorznabCatType.ConsolePS4, "Games/PSX");
|
||||
AddCategoryMapping(14, TorznabCatType.ConsoleXbox, "Games/XBOX");
|
||||
|
||||
AddCategoryMapping(4, TorznabCatType.PCMac, "Apps/Mac");
|
||||
AddCategoryMapping(5, TorznabCatType.PC0day, "Apps/Win");
|
||||
|
||||
AddCategoryMapping(1, TorznabCatType.AudioAudiobook, "Misc/aBook");
|
||||
AddCategoryMapping(8, TorznabCatType.Books, "Misc/eBook");
|
||||
AddCategoryMapping(30, TorznabCatType.Other, "Misc/Sonstiges");
|
||||
|
||||
AddCategoryMapping(44, TorznabCatType.AudioLossless, "Musik/Flac");
|
||||
AddCategoryMapping(25, TorznabCatType.AudioMP3, "Musik/MP3");
|
||||
AddCategoryMapping(26, TorznabCatType.AudioVideo, "Musik/Video");
|
||||
|
||||
AddCategoryMapping(32, TorznabCatType.XXX, "XXX/XXX");
|
||||
AddCategoryMapping(33, TorznabCatType.XXX, "XXX/XXX|HD");
|
||||
}
|
||||
|
||||
public override void LoadValuesFromJson(JToken jsonConfig, bool useProtectionService = false)
|
||||
{
|
||||
base.LoadValuesFromJson(jsonConfig, useProtectionService);
|
||||
|
||||
var tokenItem = (HiddenItem)configData.GetDynamic("token");
|
||||
if (tokenItem != null)
|
||||
{
|
||||
var token = tokenItem.Value;
|
||||
if (!string.IsNullOrWhiteSpace(token))
|
||||
APIHeaders["Authorization"] = token;
|
||||
}
|
||||
|
||||
var passkeyItem = (HiddenItem)configData.GetDynamic("passkey");
|
||||
if (passkeyItem != null)
|
||||
{
|
||||
passkey = passkeyItem.Value;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<dynamic> SendAPIRequest(string endpoint, object data)
|
||||
{
|
||||
var jsonData = JsonConvert.SerializeObject(data);
|
||||
var result = await PostDataWithCookies(APIUrl + endpoint, null, null, SiteLink, APIHeaders, jsonData);
|
||||
if (!result.Content.StartsWith("{")) // not JSON => error
|
||||
throw new ExceptionWithConfigData(result.Content, configData);
|
||||
dynamic json = JsonConvert.DeserializeObject<dynamic>(result.Content);
|
||||
return json;
|
||||
}
|
||||
|
||||
public override async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
|
||||
{
|
||||
LoadValuesFromJson(configJson);
|
||||
APIHeaders.Remove("Authorization"); // remove any token from the headers
|
||||
|
||||
var pairs = new Dictionary<string, string>
|
||||
{
|
||||
@@ -93,113 +140,100 @@ namespace Jackett.Indexers
|
||||
{ "password", configData.Password.Value }
|
||||
};
|
||||
|
||||
var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl, true);
|
||||
await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () =>
|
||||
var json = await SendAPIRequest("auth", pairs);
|
||||
string token = json.token;
|
||||
|
||||
APIHeaders["Authorization"] = token;
|
||||
|
||||
var curuser = await SendAPIRequest("curuser", null);
|
||||
|
||||
var passkeyItem = (HiddenItem)configData.GetDynamic("passkey");
|
||||
passkeyItem.Value = curuser.passkey;
|
||||
|
||||
var tokenItem = (HiddenItem)configData.GetDynamic("token");
|
||||
tokenItem.Value = token;
|
||||
|
||||
await ConfigureIfOK("", token.Length > 0, () =>
|
||||
{
|
||||
CQ dom = result.Content;
|
||||
var errorMessage = dom["table.tableinborder"].Html();
|
||||
errorMessage = result.Content;
|
||||
throw new ExceptionWithConfigData(errorMessage, configData);
|
||||
throw new ExceptionWithConfigData(json.ToString(), configData);
|
||||
});
|
||||
|
||||
return IndexerConfigurationStatus.RequiresTesting;
|
||||
}
|
||||
|
||||
protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
|
||||
{
|
||||
TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 3, 0, 0), 3, 5, DayOfWeek.Sunday);
|
||||
TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 4, 0, 0), 10, 5, DayOfWeek.Sunday);
|
||||
TimeSpan delta = new TimeSpan(1, 0, 0);
|
||||
TimeZoneInfo.AdjustmentRule adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1999, 10, 1), DateTime.MaxValue.Date, delta, startTransition, endTransition);
|
||||
TimeZoneInfo.AdjustmentRule[] adjustments = { adjustment };
|
||||
TimeZoneInfo germanyTz = TimeZoneInfo.CreateCustomTimeZone("W. Europe Standard Time", new TimeSpan(1, 0, 0), "(GMT+01:00) W. Europe Standard Time", "W. Europe Standard Time", "W. Europe DST Time", adjustments);
|
||||
|
||||
var releases = new List<ReleaseInfo>();
|
||||
|
||||
|
||||
var searchUrl = "browse";
|
||||
var searchString = query.GetQueryString();
|
||||
var searchUrl = BrowseUrl;
|
||||
var queryCollection = new NameValueCollection();
|
||||
queryCollection.Add("incldead", "1");
|
||||
queryCollection.Add("_by", "0");
|
||||
queryCollection.Add("sort", "4");
|
||||
queryCollection.Add("type", "desc");
|
||||
queryCollection.Add("orderC", "4");
|
||||
queryCollection.Add("orderD", "desc");
|
||||
queryCollection.Add("start", "0");
|
||||
queryCollection.Add("length", "100");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(searchString))
|
||||
{
|
||||
queryCollection.Add("search", searchString);
|
||||
}
|
||||
|
||||
foreach (var cat in MapTorznabCapsToTrackers(query))
|
||||
{
|
||||
queryCollection.Add("c" + cat, "1");
|
||||
}
|
||||
var cats = MapTorznabCapsToTrackers(query);
|
||||
if (cats.Count > 0)
|
||||
queryCollection.Add("cats", string.Join(",", cats));
|
||||
|
||||
searchUrl += "?" + queryCollection.GetQueryString();
|
||||
|
||||
var response = await RequestStringWithCookies(searchUrl);
|
||||
var results = response.Content;
|
||||
var result = await SendAPIRequest(searchUrl, null);
|
||||
try
|
||||
{
|
||||
CQ dom = results;
|
||||
var rows = dom["table[border=1] > tbody > tr:has(td.torrenttable)"];
|
||||
if (result["error"] != null)
|
||||
throw new Exception(result["error"].ToString());
|
||||
|
||||
foreach (var row in rows)
|
||||
var data = (JArray)result.data;
|
||||
|
||||
foreach (JArray torrent in data)
|
||||
{
|
||||
var release = new ReleaseInfo();
|
||||
release.MinimumRatio = 0.8;
|
||||
release.MinimumSeedTime = 48 * 60 * 60;
|
||||
|
||||
var qRow = row.Cq();
|
||||
release.Category = MapTrackerCatToNewznab(torrent[0].ToString());
|
||||
release.Title = torrent[1].ToString();
|
||||
var torrentID = (long)torrent[2];
|
||||
release.Comments = new Uri(SiteLink + "torrent/" + torrentID);
|
||||
release.Guid = release.Comments;
|
||||
release.Link = new Uri(SiteLink + "sdownload/" + torrentID + "/" + passkey);
|
||||
release.PublishDate = DateTimeUtil.UnixTimestampToDateTime((double)torrent[3]).ToLocalTime();
|
||||
//var preDelaySeconds = (long)torrent[4];
|
||||
release.Size = (long)torrent[5];
|
||||
release.Seeders = (int)torrent[6];
|
||||
release.Peers = release.Seeders + (int)torrent[7];
|
||||
//var imdbRating = (double)torrent[8] / 10;
|
||||
var genres = (string)torrent[9];
|
||||
if (!string.IsNullOrWhiteSpace(genres))
|
||||
release.Description = "Genres: " + genres;
|
||||
|
||||
var qDetailsLink = qRow.Find("a[href^=details.php?id=]").First();
|
||||
var qTitle = qDetailsLink.Find("b").First();
|
||||
release.Title = qTitle.Text();
|
||||
|
||||
var qCatLink = qRow.Find("a[href^=browse.php?cat=]").First();
|
||||
var qDLLink = qRow.Find("a.download").First();
|
||||
var qSeeders = qRow.Find("td.torrenttable:eq(7)");
|
||||
var qLeechers = qRow.Find("td.torrenttable:eq(8)");
|
||||
var qDateStr = qRow.Find("td.torrenttable:eq(4)").First();
|
||||
var qSize = qRow.Find("td.torrenttable:eq(5)").First();
|
||||
|
||||
var catStr = qCatLink.Attr("href").Split('=')[1].Split('\'')[0];
|
||||
release.Category = MapTrackerCatToNewznab(catStr);
|
||||
|
||||
release.Link = new Uri(SiteLink + qDLLink.Attr("href"));
|
||||
release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href"));
|
||||
release.Guid = release.Link;
|
||||
|
||||
var sizeStr = qSize.Text();
|
||||
release.Size = ReleaseInfo.GetBytes(sizeStr);
|
||||
|
||||
release.Seeders = ParseUtil.CoerceInt(qSeeders.Text());
|
||||
release.Peers = ParseUtil.CoerceInt(qLeechers.Text()) + release.Seeders;
|
||||
|
||||
var dateStr = qDateStr.Text().Trim();
|
||||
DateTime dateGerman = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "MMM d yyyy HH:mm", CultureInfo.InvariantCulture), DateTimeKind.Unspecified);
|
||||
|
||||
DateTime pubDateUtc = TimeZoneInfo.ConvertTimeToUtc(dateGerman, germanyTz);
|
||||
release.PublishDate = pubDateUtc.ToLocalTime();
|
||||
|
||||
var files = qRow.Find("td:nth-child(4)").Text();
|
||||
release.Files = ParseUtil.CoerceInt(files);
|
||||
|
||||
var grabs = qRow.Find("td:nth-child(8)").Get(0).FirstChild.ToString();
|
||||
release.Grabs = ParseUtil.CoerceInt(grabs);
|
||||
|
||||
if (qRow.Find("img[src=\"pic/torrent_ou.gif\"]").Length >= 1)
|
||||
var DownloadVolumeFlag = (long)torrent[10];
|
||||
release.UploadVolumeFactor = 1;
|
||||
if (DownloadVolumeFlag == 2) // Only Up
|
||||
release.DownloadVolumeFactor = 0;
|
||||
else if (qRow.Find("font[color=\"gray\"]:contains(50% Down)").Length >= 1)
|
||||
else if (DownloadVolumeFlag == 1) // 50 % Down
|
||||
release.DownloadVolumeFactor = 0.5;
|
||||
else
|
||||
else if (DownloadVolumeFlag == 0)
|
||||
release.DownloadVolumeFactor = 1;
|
||||
|
||||
release.UploadVolumeFactor = 1;
|
||||
release.Grabs = (long)torrent[11];
|
||||
|
||||
// 12/13/14 unknown, probably IDs/name of the uploader
|
||||
//var row12 = (long)torrent[12];
|
||||
//var row13 = (string)torrent[13];
|
||||
//var row14 = (long)torrent[14];
|
||||
|
||||
releases.Add(release);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnParseError(results, ex);
|
||||
OnParseError(result.ToString(), ex);
|
||||
}
|
||||
|
||||
return releases;
|
||||
|
@@ -113,7 +113,7 @@ namespace Jackett.Indexers
|
||||
searchUrl += "?" + queryCollection.GetQueryString();
|
||||
|
||||
var response = await RequestStringWithCookies(searchUrl);
|
||||
if (response.IsRedirect || response.Cookies.Contains("pass=deleted;"))
|
||||
if (response.IsRedirect || response.Cookies != null && response.Cookies.Contains("pass=deleted;"))
|
||||
{
|
||||
// re-login
|
||||
await ApplyConfiguration(null);
|
||||
|
@@ -173,6 +173,7 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="AuthenticationException.cs" />
|
||||
<Compile Include="CacheControlAttribute.cs" />
|
||||
<Compile Include="IndexerException.cs" />
|
||||
<Compile Include="Controllers\BlackholeController.cs" />
|
||||
<Compile Include="Controllers\DownloadController.cs" />
|
||||
<Compile Include="Engine.cs" />
|
||||
@@ -207,7 +208,6 @@
|
||||
<Compile Include="Indexers\Andraste.cs" />
|
||||
<Compile Include="Indexers\TorrentHeaven.cs" />
|
||||
<Compile Include="Indexers\NewRealWorld.cs" />
|
||||
<Compile Include="Indexers\BestFriends.cs" />
|
||||
<Compile Include="Indexers\BitCityReloaded.cs" />
|
||||
<Compile Include="Indexers\FunFile.cs" />
|
||||
<Compile Include="Indexers\GhostCity.cs" />
|
||||
|
@@ -5,5 +5,8 @@ namespace Jackett.Models.DTO
|
||||
{
|
||||
public string id { get; set; }
|
||||
public string value { get; set; }
|
||||
public string cookie { get; set; } // for cookie alternative login (captcha needed + remote host)
|
||||
public string challenge { get; set; } // for reCaptcha V1 compatibility
|
||||
public string version { get; set; } // for reCaptcha V1 compatibility
|
||||
}
|
||||
}
|
||||
|
@@ -35,7 +35,7 @@ namespace Jackett.Models.DTO
|
||||
site_link = indexer.SiteLink;
|
||||
language = indexer.Language;
|
||||
last_error = indexer.LastError;
|
||||
potatoenabled = indexer.TorznabCaps.Categories.Select(c => c.ID).Any(i => i == TorznabCatType.Movies.ID);
|
||||
potatoenabled = indexer.TorznabCaps.Categories.Any(i => TorznabCatType.Movies.Contains(i));
|
||||
|
||||
alternativesitelinks = indexer.AlternativeSiteLinks;
|
||||
|
||||
|
@@ -7,9 +7,20 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Jackett.Models.DTO
|
||||
{
|
||||
public enum ManualSearchResultIndexerStatus { Unknown = 0, Error = 1, OK = 2 };
|
||||
|
||||
public class ManualSearchResultIndexer
|
||||
{
|
||||
public string ID { get; set; }
|
||||
public string Name { get; set; }
|
||||
public ManualSearchResultIndexerStatus Status { get; set; }
|
||||
public int Results { get; set; }
|
||||
public string Error { get; set; }
|
||||
}
|
||||
|
||||
public class ManualSearchResult
|
||||
{
|
||||
public IEnumerable<TrackerCacheResult> Results { get; set; }
|
||||
public IEnumerable<string> Indexers { get; set; }
|
||||
public IList<ManualSearchResultIndexer> Indexers { get; set; }
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Jackett.Indexers;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Jackett.Models
|
||||
{
|
||||
@@ -32,6 +33,7 @@ namespace Jackett.Models
|
||||
public long? MinimumSeedTime { get; set; }
|
||||
public double? DownloadVolumeFactor { get; set; }
|
||||
public double? UploadVolumeFactor { get; set; }
|
||||
[JsonIgnore] // don't export the Origin to the manul search API, otherwise each result line contains a full recursive indexer JSON structure
|
||||
public IIndexer Origin;
|
||||
|
||||
public double? Gain
|
||||
|
@@ -207,11 +207,11 @@ namespace Jackett.Services
|
||||
browseQuery.QueryType = "search";
|
||||
browseQuery.SearchTerm = "";
|
||||
browseQuery.IsTest = true;
|
||||
var results = await indexer.ResultsForQuery(browseQuery);
|
||||
logger.Info(string.Format("Found {0} releases from {1}", results.Count(), indexer.DisplayName));
|
||||
if (results.Count() == 0)
|
||||
var result = await indexer.ResultsForQuery(browseQuery);
|
||||
logger.Info(string.Format("Found {0} releases from {1}", result.Releases.Count(), indexer.DisplayName));
|
||||
if (result.Releases.Count() == 0)
|
||||
throw new Exception("Found no results while trying to browse this tracker");
|
||||
cacheService.CacheRssResults(indexer, results);
|
||||
cacheService.CacheRssResults(indexer, result.Releases);
|
||||
}
|
||||
|
||||
public void DeleteIndexer(string name)
|
||||
|
@@ -43,6 +43,7 @@ namespace Jackett
|
||||
|
||||
json["result"] = "error";
|
||||
json["error"] = msg;
|
||||
json["stacktrace"] = exception.StackTrace;
|
||||
|
||||
var response = actionExecutedContext.Request.CreateResponse();
|
||||
response.Content = new JsonContent(json);
|
||||
|
@@ -196,6 +196,15 @@ namespace Jackett.Utils.Clients
|
||||
{
|
||||
result.RedirectingTo = response.Headers.Location.ToString();
|
||||
}
|
||||
// Mono won't add the baseurl to relative redirects.
|
||||
// e.g. a "Location: /index.php" header will result in the Uri "file:///index.php"
|
||||
// See issue #1200
|
||||
if (result.RedirectingTo != null && result.RedirectingTo.StartsWith("file://"))
|
||||
{
|
||||
var newRedirectingTo = result.RedirectingTo.Replace("file://", request.RequestUri.Scheme + "://" + request.RequestUri.Host);
|
||||
logger.Debug("[MONO relative redirect bug] Rewriting relative redirect URL from " + result.RedirectingTo + " to " + newRedirectingTo);
|
||||
result.RedirectingTo = newRedirectingTo;
|
||||
}
|
||||
result.Status = response.StatusCode;
|
||||
|
||||
// Compatiblity issue between the cookie format and httpclient
|
||||
|
@@ -207,6 +207,15 @@ namespace Jackett.Utils.Clients
|
||||
{
|
||||
result.RedirectingTo = response.Headers.Location.ToString();
|
||||
}
|
||||
// Mono won't add the baseurl to relative redirects.
|
||||
// e.g. a "Location: /index.php" header will result in the Uri "file:///index.php"
|
||||
// See issue #1200
|
||||
if (result.RedirectingTo != null && result.RedirectingTo.StartsWith("file://"))
|
||||
{
|
||||
var newRedirectingTo = result.RedirectingTo.Replace("file://", request.RequestUri.Scheme + "://" + request.RequestUri.Host);
|
||||
logger.Debug("[MONO relative redirect bug] Rewriting relative redirect URL from " + result.RedirectingTo + " to " + newRedirectingTo);
|
||||
result.RedirectingTo = newRedirectingTo;
|
||||
}
|
||||
result.Status = response.StatusCode;
|
||||
|
||||
// Compatiblity issue between the cookie format and httpclient
|
||||
|
Reference in New Issue
Block a user