Compare commits

..

26 Commits

Author SHA1 Message Date
flightlevel
9507369293 Cake build: Code tidy (#2121) 2017-11-12 11:01:05 +11:00
kaso17
84571f05fc The Place: update site links 2017-11-11 13:56:18 +01:00
flightlevel
a6ba9040d9 Use Cake to Build (#2113) 2017-11-11 17:14:14 +11:00
Nathan Holland
29e61feede Bugfixes (#2112)
* The module will need to be registered first thing in order to support commands such as --Help.

* Ignore mac directory attribute files

* Fix command line parameters not being correctly passed to the console
2017-11-11 16:21:26 +11:00
Garfield69
d055cf789f downloadville: add French Private site for Movies/TV/General. resolves #1565 2017-11-11 16:35:04 +13:00
Garfield69
15412c2508 elittracker: add Hungarian Private site 0day/general #1445 2017-11-11 07:32:09 +13:00
kaso17
c216727735 PassThePopcorn: make GUID uniq 2017-11-10 16:56:08 +01:00
kaso17
a38b13608e automapper: default to UTF8 encoding 2017-11-10 12:48:24 +01:00
kaso17
0b302915d6 Fix automapper encoding handling 2017-11-10 12:46:04 +01:00
kaso17
009cc28415 Torrent Downloads: use magnet links 2017-11-10 12:06:59 +01:00
kaso17
7007f2e650 ETTV: improve keywordsfilters 2017-11-10 11:30:11 +01:00
Garfield69
05b1895205 ettv: fix #2052 so that 'sortby added' returns proper results
the default search for ettv is to return 'any words' matched, which when
paired with 'sortby added' meant the top resutls were not useful.
now we prefix the keyworks with '+' and urlencodes them, ensuring that
'all words' matched is returned.
2017-11-10 09:50:30 +13:00
Garfield69
955aa2c9ec ettv: add description 2017-11-10 08:02:09 +13:00
kaso17
7b8f6ccd7f add ETTV 2017-11-09 13:28:44 +01:00
kaso17
a6b5401c0b add support for magnet file download links 2017-11-09 13:28:15 +01:00
kaso17
6d53e486c5 fix Content/Definition folder usage in Debug mode 2017-11-09 12:32:36 +01:00
kaso17
aa35280ca9 Shareisland: force HTTPS 2017-11-09 11:38:42 +01:00
kaso17
b5d846442d Fix tracing/logging options 2017-11-09 11:22:48 +01:00
kaso17
b040187c3f fix null pointer exception 2017-11-08 17:48:27 +01:00
kaso17
804dc12a47 BJShare: fix seeders/leechers 2017-11-08 17:33:40 +01:00
kaso17
5095c543d0 The Horror Charnel: improve rows selector 2017-11-08 16:41:50 +01:00
kaso17
3ae850e69b Cardigann: fix null pointer exception in if template 2017-11-08 16:18:28 +01:00
kaso17
4cd01433b7 fix null pointer 2017-11-08 16:06:13 +01:00
kaso17
06c47ec10a fix null pointer exception during startup 2017-11-08 16:03:38 +01:00
Nathan Holland
e90bf47d8a Move service config service back into shared .NET Framework Library (#2095) 2017-11-08 15:48:47 +01:00
Nathan Holland
52c0179e8e Feature/autofac tidyup (#2096)
* Move service config service back into shared .NET Framework Library

* Move Content files into shared folder. Make autoface load different assembilies depending on what framework is using it.

* Change my mind on what the shared module should be called. Common Module is too bland.

* DotNet4.SocksProxy is not yet publically .NET Standard. Revert to previous SocksWebProxy package.

* Check in unstaged change to test dependency injection setup.
2017-11-08 15:45:21 +01:00
100 changed files with 1844 additions and 694 deletions

8
.gitignore vendored
View File

@@ -194,6 +194,8 @@ FakesAssemblies/
# Visual Studio 6 workspace options file
*.opt
/Build.mono
/Build.windows
/Output
/tools
/BuildOutput
/Artifacts
/TestResults
*.DS_Store

View File

@@ -2,7 +2,7 @@
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "Jackett"
#define MyAppVersion GetFileVersion("build.windows/Jackett.dll")
#define MyAppVersion GetFileVersion("BuildOutput\FullFramework\Windows\Jackett\Jackett.Common.dll")
#define MyAppPublisher "Jackett Inc."
#define MyAppURL "https://github.com/Jackett/Jackett"
#define MyAppExeName "JackettTray.exe"
@@ -22,7 +22,7 @@ AppUpdatesURL={#MyAppURL}
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
DisableProgramGroupPage=yes
OutputBaseFilename=setup
OutputBaseFilename=Jackett.Installer.Windows
SetupIconFile=src\Jackett.Console\jackett.ico
UninstallDisplayIcon={commonappdata}\Jackett\JackettConsole.exe
Compression=lzma
@@ -37,9 +37,9 @@ Name: "windowsService"; Description: "Install as a Windows Service"
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
[Files]
Source: "build.windows\JackettTray.exe"; DestDir: "{commonappdata}\Jackett"; Flags: ignoreversion
Source: "build.windows\JackettUpdater.exe"; DestDir: "{commonappdata}\Jackett"; Flags: ignoreversion
Source: "build.windows\*"; DestDir: "{commonappdata}\Jackett"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "BuildOutput\FullFramework\Windows\Jackett\JackettTray.exe"; DestDir: "{commonappdata}\Jackett"; Flags: ignoreversion
Source: "BuildOutput\FullFramework\Windows\Jackett\JackettUpdater.exe"; DestDir: "{commonappdata}\Jackett"; Flags: ignoreversion
Source: "BuildOutput\FullFramework\Windows\Jackett\*"; DestDir: "{commonappdata}\Jackett"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]

View File

@@ -29,6 +29,7 @@ Developer note: The software implements the [Torznab](https://github.com/Sonarr/
* BTDB
* BT-Scene
* cpasbien
* ETTV
* EZTV
* Frozen Layer
* GkTorrent
@@ -127,9 +128,11 @@ Developer note: The software implements the [Torznab](https://github.com/Sonarr/
* Demonoid
* Diablo Torrent
* DigitalHive
* Downloadville
* Dragonworld Reloaded
* Dream Team
* EliteHD [![(invite needed)][inviteneeded]](#)
* Elit Tracker
* Elite-Tracker
* EoT-Forum
* eStone

View File

@@ -19,57 +19,9 @@ dotnet_csproj:
assembly_version: '{version}'
file_version: '{version}'
informational_version: '{version}'
install:
- cmd: choco install InnoSetup
before_build:
- cmd: nuget restore src\Jackett.sln
build:
verbosity: minimal
after_build:
- cmd: >-
xcopy src\Jackett.Console\bin\Release base\ /e /y
copy /Y src\Jackett.Service\bin\Release\JackettService.exe* %APPVEYOR_BUILD_FOLDER%\base\
copy /Y src\Jackett.Tray\bin\Release\JackettTray.exe* %APPVEYOR_BUILD_FOLDER%\base\
copy /Y src\Jackett.Updater\bin\Release\JackettUpdater.exe* %APPVEYOR_BUILD_FOLDER%\base\
copy /Y Upstart.config base\Upstart.config
copy /Y LICENSE base\LICENSE
copy /Y README.md base\README.md
xcopy base build.windows\ /e /y
xcopy base BaseBuild\Jackett\ /e /y
"C:\Program Files (x86)\Inno Setup 5\ISCC.exe" Installer.iss
RENAME Output\setup.exe Jackett.Installer.Windows.exe
MOVE Output\Jackett.Installer.Windows.exe %APPVEYOR_BUILD_FOLDER%
cd BaseBuild
7z a -tzip -r "%APPVEYOR_BUILD_FOLDER%\Jackett.Binaries.Windows.zip" "Jackett\"
7z a -ttar "%APPVEYOR_BUILD_FOLDER%\Jackett.Binaries.Mono.tar" "Jackett\"
cd %APPVEYOR_BUILD_FOLDER%
7z a -tgzip "Jackett.Binaries.Mono.tar.gz" "Jackett.Binaries.Mono.tar"
appveyor PushArtifact Jackett.Installer.Windows.exe
appveyor PushArtifact Jackett.Binaries.Windows.zip
appveyor PushArtifact Jackett.Binaries.Mono.tar.gz
build_script:
- ps: .\build.ps1
test: off
deploy:
- provider: GitHub
tag: v$(appveyor_build_version)

235
build.cake Normal file
View File

@@ -0,0 +1,235 @@
#tool nuget:?package=NUnit.ConsoleRunner&version=3.7.0
//////////////////////////////////////////////////////////////////////
// ARGUMENTS
//////////////////////////////////////////////////////////////////////
var target = Argument("target", "Default");
var configuration = Argument("configuration", "Release");
//////////////////////////////////////////////////////////////////////
// PREPARATION
//////////////////////////////////////////////////////////////////////
// Define directories.
var workingDir = MakeAbsolute(Directory("./"));
var artifactsDirName = "Artifacts";
var testResultsDirName = "TestResults";
var windowsBuildFullFramework = "./BuildOutput/FullFramework/Windows";
var monoBuildFullFramework = "./BuildOutput/FullFramework/Mono";
//////////////////////////////////////////////////////////////////////
// TASKS
//////////////////////////////////////////////////////////////////////
Task("Info")
.Does(() =>
{
Information(@"Jackett Cake build script starting...");
Information(@"Requires InnoSetup and C:\cygwin to be present for packaging (Pre-installed on AppVeyor)");
Information(@"Working directory is: " + workingDir);
});
Task("Clean")
.IsDependentOn("Info")
.Does(() =>
{
CleanDirectories("./src/**/obj" + configuration);
CleanDirectories("./src/**/bin" + configuration);
CleanDirectories("./BuildOutput");
CleanDirectories("./" + artifactsDirName);
CleanDirectories("./" + testResultsDirName);
Information("Clean completed");
});
Task("Restore-NuGet-Packages")
.IsDependentOn("Clean")
.Does(() =>
{
NuGetRestore("./src/Jackett.sln");
});
Task("Build")
.IsDependentOn("Restore-NuGet-Packages")
.Does(() =>
{
MSBuild("./src/Jackett.sln", settings => settings.SetConfiguration(configuration));
});
Task("Run-Unit-Tests")
.IsDependentOn("Build")
.Does(() =>
{
CreateDirectory("./" + testResultsDirName);
var resultsFile = $"./{testResultsDirName}/JackettTestResult.xml";
NUnit3("./src/**/bin/" + configuration + "/**/*.Test.dll", new NUnit3Settings
{
Results = new[] { new NUnit3Result { FileName = resultsFile } }
});
if(AppVeyor.IsRunningOnAppVeyor)
{
AppVeyor.UploadTestResults(resultsFile, AppVeyorTestResultsType.NUnit3);
}
});
Task("Copy-Files-Full-Framework")
.IsDependentOn("Run-Unit-Tests")
.Does(() =>
{
var windowsOutput = windowsBuildFullFramework + "/Jackett";
CopyDirectory("./src/Jackett.Console/bin/" + configuration, windowsOutput);
CopyFiles("./src/Jackett.Service/bin/" + configuration + "/JackettService.*", windowsOutput);
CopyFiles("./src/Jackett.Tray/bin/" + configuration + "/JackettTray.*", windowsOutput);
CopyFiles("./src/Jackett.Updater/bin/" + configuration + "/JackettUpdater.*", windowsOutput);
CopyFiles("./Upstart.config", windowsOutput);
CopyFiles("./LICENSE", windowsOutput);
CopyFiles("./README.md", windowsOutput);
var monoOutput = monoBuildFullFramework + "/Jackett";
CopyDirectory(windowsBuildFullFramework, monoBuildFullFramework);
DeleteFiles(monoOutput + "/JackettService.*");
DeleteFiles(monoOutput + "/JackettTray.*");
Information("Full framework file copy completed");
});
Task("Check-Packaging-Platform")
.IsDependentOn("Copy-Files-Full-Framework")
.Does(() =>
{
if (IsRunningOnWindows())
{
CreateDirectory("./" + artifactsDirName);
Information("Platform is Windows");
}
else
{
throw new Exception("Packaging is currently only implemented for a Windows environment");
}
});
Task("Package-Windows-Installer-Full-Framework")
.IsDependentOn("Check-Packaging-Platform")
.Does(() =>
{
InnoSetup("./Installer.iss", new InnoSetupSettings {
OutputDirectory = workingDir + "/" + artifactsDirName
});
});
Task("Package-Files-Full-Framework-Windows")
.IsDependentOn("Check-Packaging-Platform")
.Does(() =>
{
Zip(windowsBuildFullFramework, $"./{artifactsDirName}/Jackett.Binaries.Windows.zip");
Information(@"Full Framework Windows Binaries Zipping Completed");
});
Task("Package-Files-Full-Framework-Mono")
.IsDependentOn("Check-Packaging-Platform")
.Does(() =>
{
var cygMonoBuildPath = RelativeWinPathToCygPath(monoBuildFullFramework);
var tarFileName = "Jackett.Binaries.Mono.tar";
var tarArguments = @"-cvf " + cygMonoBuildPath + "/" + tarFileName + " -C " + cygMonoBuildPath + " Jackett --mode ='755'";
var gzipArguments = @"-k " + cygMonoBuildPath + "/" + tarFileName;
RunCygwinCommand("Tar", tarArguments);
RunCygwinCommand("Gzip", gzipArguments);
MoveFile($"{monoBuildFullFramework}/{tarFileName}.gz", $"./{artifactsDirName}/{tarFileName}.gz");
});
Task("Package-Full-Framework")
.IsDependentOn("Package-Windows-Installer-Full-Framework")
.IsDependentOn("Package-Files-Full-Framework-Windows")
.IsDependentOn("Package-Files-Full-Framework-Mono")
.Does(() =>
{
Information("Full Framwork Packaging Completed");
});
Task("Appveyor-Push-Artifacts")
.IsDependentOn("Package-Full-Framework")
.Does(() =>
{
if (AppVeyor.IsRunningOnAppVeyor)
{
foreach (var file in GetFiles(workingDir + $"/{artifactsDirName}/*"))
{
AppVeyor.UploadArtifact(file.FullPath);
}
}
else
{
Information(@"Skipping as not running in AppVeyor Environment");
}
});
private void RunCygwinCommand(string utility, string utilityArguments)
{
var cygwinDir = @"C:\cygwin\bin\";
var utilityProcess = cygwinDir + utility + ".exe";
Information("CygWin Utility: " + utility);
Information("CygWin Directory: " + cygwinDir);
Information("Utility Location: " + utilityProcess);
Information("Utility Arguments: " + utilityArguments);
IEnumerable<string> redirectedStandardOutput;
IEnumerable<string> redirectedErrorOutput;
var exitCodeWithArgument =
StartProcess(
utilityProcess,
new ProcessSettings {
Arguments = utilityArguments,
WorkingDirectory = cygwinDir,
RedirectStandardOutput = true
},
out redirectedStandardOutput,
out redirectedErrorOutput
);
Information(utility + " output:" + Environment.NewLine + string.Join(Environment.NewLine, redirectedStandardOutput.ToArray()));
// Throw exception if anything was written to the standard error.
if (redirectedErrorOutput != null && redirectedErrorOutput.Any())
{
throw new Exception(
string.Format(
utility + " Errors ocurred: {0}",
string.Join(", ", redirectedErrorOutput)));
}
Information(utility + " Exit code: {0}", exitCodeWithArgument);
}
private string RelativeWinPathToCygPath(string relativePath)
{
var cygdriveBase = "/cygdrive/" + workingDir.ToString().Replace(":", "").Replace("\\", "/");
var cygPath = cygdriveBase + relativePath.Replace(".", "");
return cygPath;
}
//////////////////////////////////////////////////////////////////////
// TASK TARGETS
//////////////////////////////////////////////////////////////////////
Task("Default")
.IsDependentOn("Appveyor-Push-Artifacts")
.Does(() =>
{
Information("Default Task Completed");
});
//////////////////////////////////////////////////////////////////////
// EXECUTION
//////////////////////////////////////////////////////////////////////
RunTarget(target);

234
build.ps1 Normal file
View File

@@ -0,0 +1,234 @@
##########################################################################
# This is the Cake bootstrapper script for PowerShell.
# This file was downloaded from https://github.com/cake-build/resources
# Feel free to change this file to fit your needs.
##########################################################################
<#
.SYNOPSIS
This is a Powershell script to bootstrap a Cake build.
.DESCRIPTION
This Powershell script will download NuGet if missing, restore NuGet tools (including Cake)
and execute your Cake build script with the parameters you provide.
.PARAMETER Script
The build script to execute.
.PARAMETER Target
The build script target to run.
.PARAMETER Configuration
The build configuration to use.
.PARAMETER Verbosity
Specifies the amount of information to be displayed.
.PARAMETER ShowDescription
Shows description about tasks.
.PARAMETER DryRun
Performs a dry run.
.PARAMETER Experimental
Uses the nightly builds of the Roslyn script engine.
.PARAMETER Mono
Uses the Mono Compiler rather than the Roslyn script engine.
.PARAMETER SkipToolPackageRestore
Skips restoring of packages.
.PARAMETER ScriptArgs
Remaining arguments are added here.
.LINK
https://cakebuild.net
#>
[CmdletBinding()]
Param(
[string]$Script = "build.cake",
[string]$Target,
[string]$Configuration,
[ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")]
[string]$Verbosity,
[switch]$ShowDescription,
[Alias("WhatIf", "Noop")]
[switch]$DryRun,
[switch]$Experimental,
[switch]$Mono,
[switch]$SkipToolPackageRestore,
[Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
[string[]]$ScriptArgs
)
[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null
function MD5HashFile([string] $filePath)
{
if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf))
{
return $null
}
[System.IO.Stream] $file = $null;
[System.Security.Cryptography.MD5] $md5 = $null;
try
{
$md5 = [System.Security.Cryptography.MD5]::Create()
$file = [System.IO.File]::OpenRead($filePath)
return [System.BitConverter]::ToString($md5.ComputeHash($file))
}
finally
{
if ($file -ne $null)
{
$file.Dispose()
}
}
}
function GetProxyEnabledWebClient
{
$wc = New-Object System.Net.WebClient
$proxy = [System.Net.WebRequest]::GetSystemWebProxy()
$proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials
$wc.Proxy = $proxy
return $wc
}
Write-Host "Preparing to run build script..."
if(!$PSScriptRoot){
$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
}
$TOOLS_DIR = Join-Path $PSScriptRoot "tools"
$ADDINS_DIR = Join-Path $TOOLS_DIR "Addins"
$MODULES_DIR = Join-Path $TOOLS_DIR "Modules"
$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe"
$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe"
$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config"
$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum"
$ADDINS_PACKAGES_CONFIG = Join-Path $ADDINS_DIR "packages.config"
$MODULES_PACKAGES_CONFIG = Join-Path $MODULES_DIR "packages.config"
# Make sure tools folder exists
if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) {
Write-Verbose -Message "Creating tools directory..."
New-Item -Path $TOOLS_DIR -Type directory | out-null
}
# Make sure that packages.config exist.
if (!(Test-Path $PACKAGES_CONFIG)) {
Write-Verbose -Message "Downloading packages.config..."
try {
$wc = GetProxyEnabledWebClient
$wc.DownloadFile("https://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch {
Throw "Could not download packages.config."
}
}
# Try find NuGet.exe in path if not exists
if (!(Test-Path $NUGET_EXE)) {
Write-Verbose -Message "Trying to find nuget.exe in PATH..."
$existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_ -PathType Container) }
$NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1
if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) {
Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)."
$NUGET_EXE = $NUGET_EXE_IN_PATH.FullName
}
}
# Try download NuGet.exe if not exists
if (!(Test-Path $NUGET_EXE)) {
Write-Verbose -Message "Downloading NuGet.exe..."
try {
$wc = GetProxyEnabledWebClient
$wc.DownloadFile($NUGET_URL, $NUGET_EXE)
} catch {
Throw "Could not download NuGet.exe."
}
}
# Save nuget.exe path to environment to be available to child processed
$ENV:NUGET_EXE = $NUGET_EXE
# Restore tools from NuGet?
if(-Not $SkipToolPackageRestore.IsPresent) {
Push-Location
Set-Location $TOOLS_DIR
# Check for changes in packages.config and remove installed tools if true.
[string] $md5Hash = MD5HashFile($PACKAGES_CONFIG)
if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or
($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) {
Write-Verbose -Message "Missing or changed package.config hash..."
Remove-Item * -Recurse -Exclude packages.config,nuget.exe
}
Write-Verbose -Message "Restoring tools from NuGet..."
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`""
if ($LASTEXITCODE -ne 0) {
Throw "An error occured while restoring NuGet tools."
}
else
{
$md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII"
}
Write-Verbose -Message ($NuGetOutput | out-string)
Pop-Location
}
# Restore addins from NuGet
if (Test-Path $ADDINS_PACKAGES_CONFIG) {
Push-Location
Set-Location $ADDINS_DIR
Write-Verbose -Message "Restoring addins from NuGet..."
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$ADDINS_DIR`""
if ($LASTEXITCODE -ne 0) {
Throw "An error occured while restoring NuGet addins."
}
Write-Verbose -Message ($NuGetOutput | out-string)
Pop-Location
}
# Restore modules from NuGet
if (Test-Path $MODULES_PACKAGES_CONFIG) {
Push-Location
Set-Location $MODULES_DIR
Write-Verbose -Message "Restoring modules from NuGet..."
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$MODULES_DIR`""
if ($LASTEXITCODE -ne 0) {
Throw "An error occured while restoring NuGet modules."
}
Write-Verbose -Message ($NuGetOutput | out-string)
Pop-Location
}
# Make sure that Cake has been installed.
if (!(Test-Path $CAKE_EXE)) {
Throw "Could not find Cake.exe at $CAKE_EXE"
}
# Build Cake arguments
$cakeArguments = @("$Script");
if ($Target) { $cakeArguments += "-target=$Target" }
if ($Configuration) { $cakeArguments += "-configuration=$Configuration" }
if ($Verbosity) { $cakeArguments += "-verbosity=$Verbosity" }
if ($ShowDescription) { $cakeArguments += "-showdescription" }
if ($DryRun) { $cakeArguments += "-dryrun" }
if ($Experimental) { $cakeArguments += "-experimental" }
if ($Mono) { $cakeArguments += "-mono" }
$cakeArguments += $ScriptArgs
# Start Cake
Write-Host "Running build script..."
&$CAKE_EXE $cakeArguments
exit $LASTEXITCODE

View File

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

View File

@@ -1,275 +1,275 @@
body {
background-image: url("binding_dark.png");
background-repeat: repeat;
}
#page {
border-radius: 6px;
background-color: white;
max-width: 900px;
margin: 0 auto;
margin-top: 30px;
padding: 20px;
margin-bottom: 100px;
}
.container-fluid {
}
#templates {
display: none;
}
#indexers {
text-align: center;
margin-top: 30px;
}
.indexer-table {
text-align: left;
}
.test-success {
color: #449d44;
}
.test-error {
color: #c9302c;
}
.test-inprogress {
color: #286090;
}
.indexer-buttons {
text-align: center;
}
.indexer-buttons > .btn {
margin-bottom: 2px;
}
.indexer-button-test {
width: 60px;
}
.setup-item-inputstring {
max-width: 255px;
}
.setup-item-inputbool input {
max-width: 100px;
height: 20px;
}
.setup-item-inputselect {
max-width: 255px;
}
[data-type=hiddendata]{
display: none;
}
.spinner {
-webkit-animation: spin 2s infinite linear;
-moz-animation: spin 2s infinite linear;
-o-animation: spin 2s infinite linear;
animation: spin 2s infinite linear;
}
@-moz-keyframes spin {
from {
-moz-transform: rotate(0deg);
}
to {
-moz-transform: rotate(360deg);
}
}
@-webkit-keyframes spin {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
#setup-indexer-go {
width: 70px;
}
hr {
border-top-color: #cdcdcd;
}
.input-area {
margin: 4px 0px;
}
.input-area > * {
vertical-align: middle;
}
.input-area > p {
margin-top: 10px;
}
.input-header {
font-size: 18px;
width: 160px;
display: inline-block;
}
.input-right {
width: 300px;
display: inline-block;
font-family: monospace;
}
#sonarr-warning {
display: none;
}
#logo {
max-width: 50px;
}
#header-title {
font-size: 34px;
vertical-align: middle;
padding-left: 15px;
}
#footer {
color: #444444;
margin: 0 auto;
margin-top: 10px;
text-align: center;
}
#jackett-allowext, #jackett-allowupdate, #jackett-logging, #jackett-prerelease {
width: 25px;
}
.modal-fillwidth {
width: 1200px;
min-width:80%;
}
.indexer-caps {
padding: 0px 15px 15px 15px;
border-top: 1px solid #e5e5e5;
}
.indexer-caps table {
border-bottom: 1px solid #ddd;
}
.jackettlogWarn {
background-color: #FFFF8E !important;
}
.jackettlogError {
background-color: #FF6060 !important;
}
.jackettdownloaded {
color: blueviolet;
}
.jacketdownloadlocal {
padding-left: 10px;
}
.downloadcolumn {
text-align:center;
}
pre {
display: block;
padding: 3px;
margin: 0 0 0px;
font-size: 13px;
line-height: 1.42857143;
color: #333;
word-break: break-all;
word-wrap: break-word;
background-color: transparent;
border: 0px;
border-radius: 0px;
}
.modal-open .modal {
overflow-x: auto; /* Model can be bigger than the screen on mobiles */
}
.dataTables_filter input {
width: 400px
}
#unconfigured-indexers-template {
display: none;
}
.jackett-apikey{
margin-top: 10px;
}
.jackett-apikey .input-header{
width: 80px;
}
.setup-item-displayinfo:empty {
display: none;
}
table td.fit{
white-space: nowrap;
width: 1%;
}
.label-imdb {
background-color: #d0ab44;
}
.tooltip-inner {
max-width: 500px !important;
}
.tooltip-inner img {
max-width: 250px;
height: auto;
}
.type-public {
color: #449d44
}
.type-private {
color: #c9302c
}
.type-semi-private {
color: #ec971f
}
.dataTables_deadfilter {
float: right;
text-align: right;
margin-right: 1em;
}
input#searchquery{
width:400px;
}
body {
background-image: url("binding_dark.png");
background-repeat: repeat;
}
#page {
border-radius: 6px;
background-color: white;
max-width: 900px;
margin: 0 auto;
margin-top: 30px;
padding: 20px;
margin-bottom: 100px;
}
.container-fluid {
}
#templates {
display: none;
}
#indexers {
text-align: center;
margin-top: 30px;
}
.indexer-table {
text-align: left;
}
.test-success {
color: #449d44;
}
.test-error {
color: #c9302c;
}
.test-inprogress {
color: #286090;
}
.indexer-buttons {
text-align: center;
}
.indexer-buttons > .btn {
margin-bottom: 2px;
}
.indexer-button-test {
width: 60px;
}
.setup-item-inputstring {
max-width: 255px;
}
.setup-item-inputbool input {
max-width: 100px;
height: 20px;
}
.setup-item-inputselect {
max-width: 255px;
}
[data-type=hiddendata]{
display: none;
}
.spinner {
-webkit-animation: spin 2s infinite linear;
-moz-animation: spin 2s infinite linear;
-o-animation: spin 2s infinite linear;
animation: spin 2s infinite linear;
}
@-moz-keyframes spin {
from {
-moz-transform: rotate(0deg);
}
to {
-moz-transform: rotate(360deg);
}
}
@-webkit-keyframes spin {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
#setup-indexer-go {
width: 70px;
}
hr {
border-top-color: #cdcdcd;
}
.input-area {
margin: 4px 0px;
}
.input-area > * {
vertical-align: middle;
}
.input-area > p {
margin-top: 10px;
}
.input-header {
font-size: 18px;
width: 160px;
display: inline-block;
}
.input-right {
width: 300px;
display: inline-block;
font-family: monospace;
}
#sonarr-warning {
display: none;
}
#logo {
max-width: 50px;
}
#header-title {
font-size: 34px;
vertical-align: middle;
padding-left: 15px;
}
#footer {
color: #444444;
margin: 0 auto;
margin-top: 10px;
text-align: center;
}
#jackett-allowext, #jackett-allowupdate, #jackett-logging, #jackett-prerelease {
width: 25px;
}
.modal-fillwidth {
width: 1200px;
min-width:80%;
}
.indexer-caps {
padding: 0px 15px 15px 15px;
border-top: 1px solid #e5e5e5;
}
.indexer-caps table {
border-bottom: 1px solid #ddd;
}
.jackettlogWarn {
background-color: #FFFF8E !important;
}
.jackettlogError {
background-color: #FF6060 !important;
}
.jackettdownloaded {
color: blueviolet;
}
.jacketdownloadlocal {
padding-left: 10px;
}
.downloadcolumn {
text-align:center;
}
pre {
display: block;
padding: 3px;
margin: 0 0 0px;
font-size: 13px;
line-height: 1.42857143;
color: #333;
word-break: break-all;
word-wrap: break-word;
background-color: transparent;
border: 0px;
border-radius: 0px;
}
.modal-open .modal {
overflow-x: auto; /* Model can be bigger than the screen on mobiles */
}
.dataTables_filter input {
width: 400px
}
#unconfigured-indexers-template {
display: none;
}
.jackett-apikey{
margin-top: 10px;
}
.jackett-apikey .input-header{
width: 80px;
}
.setup-item-displayinfo:empty {
display: none;
}
table td.fit{
white-space: nowrap;
width: 1%;
}
.label-imdb {
background-color: #d0ab44;
}
.tooltip-inner {
max-width: 500px !important;
}
.tooltip-inner img {
max-width: 250px;
height: auto;
}
.type-public {
color: #449d44
}
.type-private {
color: #c9302c
}
.type-semi-private {
color: #ec971f
}
.dataTables_deadfilter {
float: right;
text-align: right;
margin-right: 1em;
}
input#searchquery{
width:400px;
}

View File

Before

Width:  |  Height:  |  Size: 361 KiB

After

Width:  |  Height:  |  Size: 361 KiB

View File

Before

Width:  |  Height:  |  Size: 306 KiB

After

Width:  |  Height:  |  Size: 306 KiB

View File

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 106 KiB

View File

Before

Width:  |  Height:  |  Size: 160 B

After

Width:  |  Height:  |  Size: 160 B

View File

Before

Width:  |  Height:  |  Size: 148 B

After

Width:  |  Height:  |  Size: 148 B

View File

Before

Width:  |  Height:  |  Size: 201 B

After

Width:  |  Height:  |  Size: 201 B

View File

Before

Width:  |  Height:  |  Size: 158 B

After

Width:  |  Height:  |  Size: 158 B

View File

Before

Width:  |  Height:  |  Size: 146 B

After

Width:  |  Height:  |  Size: 146 B

View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -1,6 +1,6 @@
/*
2015 Jason Mulligan
@version 3.1.2
*/
"use strict"; !function (a) { var b = /b$/, c = { bits: ["B", "kb", "Mb", "Gb", "Tb", "Pb", "Eb", "Zb", "Yb"], bytes: ["B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"] }, d = function (a) { var d = void 0 === arguments[1] ? {} : arguments[1], e = [], f = !1, g = 0, h = void 0, i = void 0, j = void 0, k = void 0, l = void 0, m = void 0, n = void 0, o = void 0, p = void 0, q = void 0, r = void 0; if (isNaN(a)) throw new Error("Invalid arguments"); return j = d.bits === !0, p = d.unix === !0, i = void 0 !== d.base ? d.base : 2, o = void 0 !== d.round ? d.round : p ? 1 : 2, q = void 0 !== d.spacer ? d.spacer : p ? "" : " ", r = void 0 !== d.suffixes ? d.suffixes : {}, n = void 0 !== d.output ? d.output : "string", h = void 0 !== d.exponent ? d.exponent : -1, m = Number(a), l = 0 > m, k = i > 2 ? 1e3 : 1024, l && (m = -m), 0 === m ? (e[0] = 0, e[1] = p ? "" : "B") : ((-1 === h || isNaN(h)) && (h = Math.floor(Math.log(m) / Math.log(k))), h > 8 && (g = 1e3 * g * (h - 8), h = 8), g = 2 === i ? m / Math.pow(2, 10 * h) : m / Math.pow(1e3, h), j && (g = 8 * g, g > k && (g /= k, h++)), e[0] = Number(g.toFixed(h > 0 ? o : 0)), e[1] = c[j ? "bits" : "bytes"][h], !f && p && (j && b.test(e[1]) && (e[1] = e[1].toLowerCase()), e[1] = e[1].charAt(0), "B" === e[1] ? (e[0] = Math.floor(e[0]), e[1] = "") : j || "k" !== e[1] || (e[1] = "K"))), l && (e[0] = -e[0]), e[1] = r[e[1]] || e[1], "array" === n ? e : "exponent" === n ? h : "object" === n ? { value: e[0], suffix: e[1] } : e.join(q) }; "undefined" != typeof exports ? module.exports = d : "function" == typeof define ? define(function () { return d }) : a.filesize = d }("undefined" != typeof global ? global : window);
/*
2015 Jason Mulligan
@version 3.1.2
*/
"use strict"; !function (a) { var b = /b$/, c = { bits: ["B", "kb", "Mb", "Gb", "Tb", "Pb", "Eb", "Zb", "Yb"], bytes: ["B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"] }, d = function (a) { var d = void 0 === arguments[1] ? {} : arguments[1], e = [], f = !1, g = 0, h = void 0, i = void 0, j = void 0, k = void 0, l = void 0, m = void 0, n = void 0, o = void 0, p = void 0, q = void 0, r = void 0; if (isNaN(a)) throw new Error("Invalid arguments"); return j = d.bits === !0, p = d.unix === !0, i = void 0 !== d.base ? d.base : 2, o = void 0 !== d.round ? d.round : p ? 1 : 2, q = void 0 !== d.spacer ? d.spacer : p ? "" : " ", r = void 0 !== d.suffixes ? d.suffixes : {}, n = void 0 !== d.output ? d.output : "string", h = void 0 !== d.exponent ? d.exponent : -1, m = Number(a), l = 0 > m, k = i > 2 ? 1e3 : 1024, l && (m = -m), 0 === m ? (e[0] = 0, e[1] = p ? "" : "B") : ((-1 === h || isNaN(h)) && (h = Math.floor(Math.log(m) / Math.log(k))), h > 8 && (g = 1e3 * g * (h - 8), h = 8), g = 2 === i ? m / Math.pow(2, 10 * h) : m / Math.pow(1e3, h), j && (g = 8 * g, g > k && (g /= k, h++)), e[0] = Number(g.toFixed(h > 0 ? o : 0)), e[1] = c[j ? "bits" : "bytes"][h], !f && p && (j && b.test(e[1]) && (e[1] = e[1].toLowerCase()), e[1] = e[1].charAt(0), "B" === e[1] ? (e[0] = Math.floor(e[0]), e[1] = "") : j || "k" !== e[1] || (e[1] = "K"))), l && (e[0] = -e[0]), e[1] = r[e[1]] || e[1], "array" === n ? e : "exponent" === n ? h : "object" === n ? { value: e[0], suffix: e[1] } : e.join(q) }; "undefined" != typeof exports ? module.exports = d : "function" == typeof define ? define(function () { return d }) : a.filesize = d }("undefined" != typeof global ? global : window);
//# sourceMappingURL=filesize.min.js.map

View File

@@ -1,37 +1,37 @@

Handlebars.registerHelper('dateFormat', function (context, block) {
if (window.moment) {
var f = block.hash.format || "MMM DD, YYYY hh:mm:ss A";
return moment(context).format(f); //had to remove Date(context)
} else {
return context; // moment plugin not available. return data as is.
};
});
Handlebars.registerHelper('jacketTimespan', function (context, block) {
var now = moment();
var from = moment(context);
var timeSpan = moment.duration(now.diff(from));
var minutes = timeSpan.asMinutes();
if (minutes < 120) {
return Math.round(minutes) + 'm ago';
}
var hours = timeSpan.asHours();
if (hours < 48) {
return Math.round(hours) + 'h ago';
}
var days = timeSpan.asDays();
if (days < 365) {
return Math.round(days) + 'd ago';
}
var years = timeSpan.asYears();
return Math.round(years) + 'y ago';
});
Handlebars.registerHelper('jacketSize', function (context, block) {
return filesize(context, { round: 1 });

Handlebars.registerHelper('dateFormat', function (context, block) {
if (window.moment) {
var f = block.hash.format || "MMM DD, YYYY hh:mm:ss A";
return moment(context).format(f); //had to remove Date(context)
} else {
return context; // moment plugin not available. return data as is.
};
});
Handlebars.registerHelper('jacketTimespan', function (context, block) {
var now = moment();
var from = moment(context);
var timeSpan = moment.duration(now.diff(from));
var minutes = timeSpan.asMinutes();
if (minutes < 120) {
return Math.round(minutes) + 'm ago';
}
var hours = timeSpan.asHours();
if (hours < 48) {
return Math.round(hours) + 'h ago';
}
var days = timeSpan.asDays();
if (days < 365) {
return Math.round(days) + 'd ago';
}
var years = timeSpan.asYears();
return Math.round(years) + 'y ago';
});
Handlebars.registerHelper('jacketSize', function (context, block) {
return filesize(context, { round: 1 });
});

View File

@@ -0,0 +1,214 @@
---
site: downloadville
name: Downloadville
description: "Downloadville is a FRENCH Private Torrent Tracker for MOVIES / TV / GENERAL"
language: fr-fr
type: private
encoding: UTF-8
links:
- https://downloadville.net/tracker/
caps:
categorymappings:
# Films
- {id: 1, cat: Movies, desc: "Films"}
- {id: 13, cat: Movies, desc: "Films BD-Rip / BRRip"}
- {id: 15, cat: Movies, desc: "Films DVD-Rip"}
- {id: 18, cat: Movies, desc: "Films HD 720p"}
- {id: 19, cat: Movies, desc: "Films WEB-DL / WEB-Rip"}
- {id: 20, cat: Movies, desc: "Films HD 1080p"}
- {id: 26, cat: Movies, desc: "Films mHD 720p"}
- {id: 27, cat: Movies, desc: "Films mHD 1080p"}
- {id: 28, cat: Movies, desc: "Films x265"}
- {id: 30, cat: Movies, desc: "Films Blu-Ray (complet)"}
- {id: 31, cat: Movies, desc: "Films 3D"}
- {id: 32, cat: Movies, desc: "Films 4K UHD"}
- {id: 33, cat: Movies, desc: "Films Québécois SD"}
- {id: 34, cat: Movies, desc: "Films Québécois HD"}
- {id: 35, cat: Movies, desc: "Films Québécois DVD-R"}
- {id: 37, cat: Movies, desc: "Films DVD-R"}
- {id: 38, cat: Movies, desc: "Films V.O.S.T. SD"}
- {id: 39, cat: Movies, desc: "Films V.O.S.T. HD"}
- {id: 40, cat: Movies, desc: "Films V.O. SD"}
- {id: 41, cat: Movies, desc: "Films V.O. HD"}
- {id: 42, cat: Movies, desc: "Films TV-Rip"}
# Séries-Télé
- {id: 16, cat: TV, desc: "Séries-Télé"}
- {id: 17, cat: TV, desc: "Séries-Télé TV Pack SD"}
- {id: 21, cat: TV, desc: "Séries-Télé SD"}
- {id: 22, cat: TV, desc: "Séries-Télé HD"}
- {id: 23, cat: TV, desc: "Séries-Télé TV Pack HD"}
- {id: 45, cat: TV, desc: "Séries-Télé Québécois SD"}
- {id: 46, cat: TV, desc: "Séries-Télé Québécois HD"}
- {id: 47, cat: TV, desc: "Séries-Télé V.O.S.T. SD"}
- {id: 48, cat: TV, desc: "Séries-TéléV.O.S.T. HD"}
- {id: 49, cat: TV, desc: "Séries-Télé Émissions TV SD"}
- {id: 50, cat: TV, desc: "Séries-Télé Émissions TV HD"}
- {id: 51, cat: TV, desc: "Séries-Télé Blu-Ray"}
- {id: 52, cat: TV, desc: "Séries-Télé DVD-R"}
- {id: 94, cat: TV, desc: "Séries-Télé x265 - TV"}
# Musique
- {id: 2, cat: Audio, desc: "Musique"}
- {id: 54, cat: Audio, desc: "Musique MP3"}
- {id: 55, cat: Audio, desc: "Musique FLAC"}
- {id: 56, cat: Audio, desc: "Musique DSD"}
- {id: 57, cat: Audio, desc: "Musique Karaoke"}
- {id: 58, cat: Audio, desc: "Musique Autres"}
# Jeux
- {id: 3, cat: PC/Games, desc: "Jeux"}
- {id: 59, cat: PC/Games, desc: "Jeux PC"}
- {id: 60, cat: PC/Games, desc: "Jeux Consoles"}
- {id: 84, cat: PC/Games, desc: "Jeux Android"}
# Livres
- {id: 6, cat: Books, desc: "Livres"}
- {id: 61, cat: Books, desc: "Livres epub"}
- {id: 62, cat: Books, desc: "Livres pdf"}
- {id: 63, cat: Books, desc: "Livres Journaux"}
- {id: 64, cat: Books, desc: "Livres Magazines"}
- {id: 65, cat: Books, desc: "Livres Bandes Dessinées"}
- {id: 66, cat: Books, desc: "Livres Multi-Format"}
- {id: 85, cat: Books, desc: "Livres Audio"}
# Logiciels
- {id: 67, cat: PC, desc: "Logiciels"}
- {id: 68, cat: PC, desc: "Logiciels Windows"}
- {id: 69, cat: PC, desc: "Logiciels Mac"}
- {id: 86, cat: PC, desc: "Logiciels Linux"}
- {id: 87, cat: PC, desc: "Logiciels Android"}
# Spectacles
- {id: 70, cat: TV/Other, desc: "Spectacles"}
- {id: 71, cat: TV/Other, desc: "Spectacles Humour"}
- {id: 72, cat: TV/Other, desc: "Spectacles Live"}
- {id: 88, cat: TV/Other, desc: "Spectacles Théatre"}
# Séries Animées
- {id: 73, cat: TV/Anime, desc: "Séries Animées"}
- {id: 83, cat: TV/Anime, desc: "Séries Animées"}
# Sports
- {id: 24, cat: TV/Sport, desc: "Sports"}
- {id: 74, cat: TV/Sport, desc: "Sports [Français]"}
- {id: 75, cat: TV/Sport, desc: "Sports [Anglais]"}
# Documentaires
- {id: 76, cat: TV/Documentary, desc: "Documentaires"}
- {id: 77, cat: TV/Documentary, desc: "Docu. SD"}
- {id: 78, cat: TV/Documentary, desc: "Docu. HD"}
- {id: 79, cat: TV/Documentary, desc: "Docu. V.O.S.T. SD"}
- {id: 80, cat: TV/Documentary, desc: "Docu. V.O.S.T. HD"}
# Autres / Inclassable
- {id: 81, cat: Other, desc: "Autres / Inclassable"}
- {id: 82, cat: Other, desc: "Autres / Inclassable"}
modes:
search: [q]
tv-search: [q, season, ep]
movie-search: [q]
settings:
- name: uid
type: text
label: Username
- name: pwd
type: password
label: Password
- name: active
type: select
label: Rechercher dans (Look at)
default: "0"
options:
"0" : "Tous (All)"
"1" : "Actif Seul. (Active Only)"
"2" : "Mort Seul. (Dead Only)"
- name: gold
type: select
label: FreeLeech
default: "0"
options:
"0" : "Tous (all)"
"1" : "Classic"
"2" : "Argent (Silver)"
"3" : "Or (Gold)"
"4" : "Argent & Or (Both)"
login:
path: index.php?page=login
method: post
form: form[action="index.php?page=login"]
inputs:
uid: "{{ .Config.uid }}"
pwd: "{{ .Config.pwd }}"
error:
- selector: form[action="index.php?page=login&returnto=index.php"] table tr:nth-of-type(2) td
message:
selector: form[action="index.php?page=login&returnto=index.php"] table tr:nth-of-type(2) td span
test:
path: index.php
select: a[href="logout.php"]
download:
before:
path: "thanks.php"
method: "post"
inputs:
infohash: "{{ .DownloadUri.Query.id }}"
thanks: "1"
rndval: "1487013827343"
selector: a[href^="download.php?id="]
search:
paths:
- path: index.php
inputs:
page: "torrents"
search: "{{ .Keywords }}"
category: "{{ range .Categories }}{{.}};{{end}}"
options: "0"
active: "{{ .Config.active }}"
gold: "{{ .Config.gold }}"
rows:
selector: table > tbody > tr > td > table.lista > tbody > tr:has(td[onmouseover="this.className='post'"])
fields:
title:
selector: a[onmouseover][href^="index.php?page=torrent-details&id="]
details:
selector: a[onmouseover][href^="index.php?page=torrent-details&id="]
attribute: href
download:
selector: a[onmouseover][href^="index.php?page=torrent-details&id="]
attribute: href
banner:
selector: a[onmouseover][href^="index.php?page=torrent-details&id="]
attribute: onmouseover
filters:
- name: regexp
args: "src=(.*?) "
category:
selector: a[href^="index.php?page=torrents&category="]
attribute: href
filters:
- name: querystring
args: "category"
date:
selector: td:nth-of-type(4)
filters:
- name: append
args: " -04:00"
- name: dateparse
args: "02/01/2006 15:04:05 -07:00"
seeders:
selector: td:nth-of-type(6)
leechers:
selector: td:nth-of-type(7)
grabs:
selector: td:nth-of-type(8)
filters:
- name: replace
args: ["---", "0"]
size:
selector: td:nth-of-type(10)
downloadvolumefactor:
case:
img[src="images/freeleech.gif"]: "0"
img[src="gold/gold.gif"]: "0"
img[src="gold/slver.gif"]: "0.5"
"*": "1"
uploadvolumefactor:
text: "1"

View File

@@ -0,0 +1,188 @@
---
site: elittracker
name: Elit Tracker
description: "Elit Tracker (ET) is a HUNGARIAN Private Torrent Tracker for 0DAY / GENERAL"
language: hu-hu
type: private
encoding: iso-8859-2
links:
- http://elittorent.us/
caps:
categorymappings:
- {id: 35, cat: Movies, desc: "BluRay-Egyéb (BluRay Other)"}
- {id: 30, cat: Movies, desc: "BluRay-Hun"}
- {id: 34, cat: Movies, desc: "Cam-Egyéb (Cam Other)"}
- {id: 33, cat: Movies, desc: "Cam-Hun"}
- {id: 36, cat: Movies, desc: "DVD-Egyéb (DVD Other)"}
- {id: 2, cat: Movies, desc: "DVD-Eng"}
- {id: 3, cat: Movies, desc: "DVD-Hun"}
- {id: 6, cat: Other, desc: "Egyéb (Other)"}
- {id: 10, cat: Console, desc: "Játék-Konzol (Games Console)"}
- {id: 7, cat: Console, desc: "Játék-PC (Games PC)"}
- {id: 8, cat: Console, desc: "Játék-PS (Games PS)"}
- {id: 9, cat: Console, desc: "Játék-Xbox (Games Xbox)"}
- {id: 11, cat: Other, desc: "Klip (Clips)"}
- {id: 4, cat: Books, desc: "Könyv-Eng (Book Eng)"}
- {id: 5, cat: Books, desc: "Könyv-Hun (Book Hun)"}
- {id: 12, cat: Books, desc: "Mese-Eng (Tale Eng)"}
- {id: 13, cat: Books, desc: "Mese-Hun (Tale Hun)"}
- {id: 14, cat: PC, desc: "Mobil (Mobile)"}
- {id: 15, cat: PC, desc: "Program (Software)"}
- {id: 16, cat: PC, desc: "Program-Linux (Software Linux)"}
- {id: 17, cat: TV, desc: "Sorozat-Eng (TV Eng)"}
- {id: 18, cat: TV, desc: "Sorozat-Hun (TV Hun)"}
- {id: 37, cat: Movies, desc: "XviD-Egyéb (Xvid Other)"}
- {id: 19, cat: Movies, desc: "XviD-Eng"}
- {id: 20, cat: Movies, desc: "XviD-Hun"}
- {id: 21, cat: XXX, desc: "XXX"}
- {id: 22, cat: XXX, desc: "XXX-Képek (XXX Pics)"}
- {id: 32, cat: Audio, desc: "Zene-Egyéb (Msuci Other)"}
- {id: 23, cat: Audio, desc: "Zene-Eng (Music Eng)"}
- {id: 24, cat: Audio, desc: "Zene-Hun (Music Hun)"}
modes:
search: [q]
tv-search: [q, season, ep]
movie-search: [q]
settings:
- name: username
type: text
label: Username
- name: password
type: password
label: Password
- name: category
type: select
label: Category
default: "0"
options:
"0" : "toate categoriile (All)"
"35" : "BluRay-Egyéb (BluRay Other)"
"30" : "BluRay-Hun"
"34" : "Cam-Egyéb (Cam Other)"
"33" : "Cam-Hun"
"36" : "DVD-Egyéb (DVD OTher)"
"2" : "DVD-Eng"
"3" : "DVD-Hun"
"6" : "Egyéb (Other)"
"10" : "Játék-Konzol (Games Console)"
"7" : "Játék-PC (Games PC)"
"8" : "Játék-PS (Games PS)"
"9" : "Játék-Xbox (Games Xbox)"
"11" : "Klip (Clips)"
"4" : "Könyv-Eng (Book Eng)"
"5" : "Könyv-Hun (Book Hun)"
"12" : "Mese-Eng (Tale Eng)"
"13" : "Mese-Hun (Tale Hun)"
"14" : "Mobil (Mobile)"
"15" : "Program (Software)"
"16" : "Program-Linux (Software Linux)"
"17" : "Sorozat-Eng (TV Eng)"
"18" : "Sorozat-Hun (TV Hun)"
"37" : "XviD-Egyéb (Xvid Other)"
"19" : "XviD-Eng"
"20" : "XviD-Hun"
"21" : "XXX"
"22" : "XXX-Képek (XXX Pics)"
"32" : "Zene-Egyéb (XXX Other)"
"23" : "Zene-Eng (Music Eng)"
"24" : "Zene-Hun (Music Hun)"
login:
path: login.php
method: form
form: form[action="takelogin.php"]
inputs:
username: "{{ .Config.username }}"
password: "{{ .Config.password }}"
error:
- selector: td:contains("Hiba:")
test:
path: browse.php
search:
paths:
- path: browse.php
method: post
inputs:
do: "search"
keywords: "{{ .Keywords }}"
search_type: "t_name"
# multi cat is not supported
category: "{{ .Config.category }}"
rows:
selector: table > tbody > tr:has(td a[href*="/browse.php?browse_categories&category="])
fields:
title:
# using attribute title from td(3) because the text from td(2) a(2) can be abbreviated
selector: td:nth-of-type(3) a
attribute: title
filters:
- name: replace
args: ["Torrent letöltése: ", ""]
details:
selector: td:nth-of-type(2) a:nth-of-type(2)
attribute: href
banner:
selector: td:nth-of-type(2) a:nth-of-type(2)
attribute: onmouseover
filters:
- name: regexp
args: src=([^\s]+)
download:
selector: td:nth-of-type(3) a
attribute: href
category:
selector: td:nth-of-type(1) a
attribute: href
filters:
- name: querystring
args: category
date:
selector: td:nth-of-type(2)
remove: b
filters:
- name: split
args: ["\xA0", 0]
- name: append
args: " +01:00"
- name: dateparse
args: "2006 2, January, 15:04:05 -07:00"
files:
selector: td:nth-of-type(4)
seeders:
selector: td:nth-of-type(6)
leechers:
selector: td:nth-of-type(7)
grabs:
selector: td:nth-of-type(9):has(a[href*="/viewsnatches.php?id="]) a b
optional: true
filters:
- name: replace
args: ["x", ""]
grabs:
selector: td:nth-of-type(9):not(a[href*="/viewsnatches.php?id="]) b
optional: true
filters:
- name: replace
args: ["x", ""]
size:
selector: td:nth-of-type(9)
remove: a, b
filters:
- name: replace
args: ["x", ""]
downloadvolumefactor:
case:
img[src$="pic/external.gif"]: "0"
img[src$="pic/freedownload.gif"]: "0"
img[src$="pic/silverdownload.gif"]: "0.5"
"*": "1"
uploadvolumefactor:
case:
img[src$="pic/external.gif"]: "0"
img[src$="pic/x2.gif"]: "2"
"*": "1"

View File

@@ -0,0 +1,79 @@
---
site: ettv
name: ETTV
description: "ETTV is a Public torrent site for TV / MOVIES, home of the ETTV, ETHD and DTOne groups."
language: en-us
type: public
encoding: UTF-8
links:
- https://www.ettv.tv
caps:
categorymappings:
- {id: 49, cat: Movies/3D, desc: "Movies - 3D"}
- {id: 1, cat: Movies/HD, desc: "Movies - HD 1080p"}
- {id: 2, cat: Movies/HD, desc: "Movies - HD 720p"}
- {id: 3, cat: Movies/HD, desc: "Movies - UltraHD/4K"}
- {id: 47, cat: Movies/SD, desc: "Movies - X264/H264"}
- {id: 42, cat: Movies/SD, desc: "Movies - XviD"}
- {id: 41, cat: TV/HD, desc: "TV - HD/X264/H264"}
- {id: 5, cat: TV/SD, desc: "TV - SD/X264/H264"}
- {id: 50, cat: TV/SD, desc: "TV - SD/XVID"}
- {id: 7, cat: TV, desc: "TV - TV Packs"}
modes:
search: [q]
tv-search: [q, season, ep]
movie-search: [q]
settings: []
download:
selector: a[href^="magnet:"]
search:
path: torrents-search.php
inputs:
$raw: "{{range .Categories}}c{{.}}=1&{{end}}"
search: "{{ .Keywords }}"
incldead: "1"
sort: id
order: desc
keywordsfilters:
- name: replace
args: ["-", " "] # remove special search character (negative search)
- name: replace
args: ["+", " "] # remove special search character (positive search)
- name: re_replace
args: ["(\\w+)", " +$1"] # prepend + to each word
rows:
selector: div.myFrame-content > div > table > tbody > tr[class]
fields:
download:
selector: a[href^="/torrent/"]
attribute: href
title:
selector: a[href^="/torrent/"][title]
attribute: title
category:
selector: a[href^="torrents.php?cat="]
attribute: href
filters:
- name: querystring
args: cat
details:
selector: a[href^="/torrent/"]
attribute: href
date:
selector: td:nth-child(3)
size:
selector: td:nth-child(4)
seeders:
selector: td:nth-child(6)
leechers:
selector: td:nth-child(7)
downloadvolumefactor:
text: "0"
uploadvolumefactor:
text: "1"

View File

@@ -6,7 +6,9 @@
type: private
encoding: UTF-8
links:
- http://shareisland.org
- https://shareisland.org/
legacylinks:
- http://shareisland.org/
caps:
categorymappings:

View File

@@ -60,7 +60,7 @@
incldead: 1
rows:
selector: p + table > tbody > tr:has(a[href^="details.php?id="]), p + table > tbody > tr[id^="kdescr"]
selector: p + table > tbody > tr:has(a[href^="download.php"]), p + table > tbody > tr:has(a[href^="download.php"]) + tr[id^="kdescr"] # sometimes an unexpected tr[id^="kdescr"] row shows up (for unpublished torrents?)
filters:
- name: andmatch
after: 1

View File

@@ -6,6 +6,8 @@
type: private
encoding: UTF-8
links:
- https://theplace.click/
legacylinks:
- http://theplace.click/
caps:

View File

@@ -24,6 +24,9 @@
settings: []
download:
selector: a[href^="magnet:"]
search:
paths:
- path: "{{if .Keywords}}/search/{{else}}/today/{{end}}"
@@ -41,9 +44,6 @@
download:
selector: p:nth-child(1) > a[href^="/torrent/"]
attribute: href
filters:
- name: replace
args: ["/torrent/", "/download/"]
size:
selector: span:nth-child(5)
seeders:

View File

@@ -10,44 +10,35 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http.Dependencies;
using Autofac.Integration.WebApi;
using Jackett.Services.Interfaces;
using Jacket.Common;
using Jackett.Models.Config;
using System.Reflection;
namespace Jackett
{
public class Engine
{
private static IContainer container = null;
static Engine()
{
BuildContainer();
}
public static void BuildContainer()
public static void BuildContainer(params Autofac.Module[] ApplicationSpecificModules)
{
var builder = new ContainerBuilder();
builder.RegisterModule<JackettModule>();
foreach(var module in ApplicationSpecificModules)
{
builder.RegisterModule(module);
}
SetupLogging(builder);
container = builder.Build();
// Register the container in itself to allow for late resolves
var secondaryBuilder = new ContainerBuilder();
secondaryBuilder.RegisterInstance(container).SingleInstance();
SetupLogging(secondaryBuilder);
secondaryBuilder.Update(container);
}
public static IDependencyResolver DependencyResolver()
public static IContainer GetContainer()
{
return new AutofacWebApiDependencyResolver(container);
return container;
}
public static IConfigurationService ConfigService
{
get

View File

@@ -257,8 +257,9 @@ Encoding = Encoding.UTF8;
var qDLLink = Row.QuerySelector("a[href^=\"torrents.php?action=download\"]");
var qSize = Row.QuerySelector("td:nth-last-child(4)");
var qSeeders = Row.QuerySelector("td:nth-last-child(3)");
var qLeechers = Row.QuerySelector("td:nth-last-child(2)");
var qGrabs = Row.QuerySelector("td:nth-last-child(3)");
var qSeeders = Row.QuerySelector("td:nth-last-child(2)");
var qLeechers = Row.QuerySelector("td:nth-last-child(1)");
var qFreeLeech = Row.QuerySelector("strong[title=\"Free\"]");
if (Row.ClassList.Contains("group_torrent")) // torrents belonging to a group
@@ -304,6 +305,7 @@ Encoding = Encoding.UTF8;
release.Comments = new Uri(SiteLink + qDetailsLink.GetAttribute("href"));
release.Guid = release.Link;
release.Grabs = ParseUtil.CoerceLong(qGrabs.TextContent);
release.Seeders = ParseUtil.CoerceInt(qSeeders.TextContent);
release.Peers = ParseUtil.CoerceInt(qLeechers.TextContent) + release.Seeders;

View File

@@ -286,6 +286,10 @@ namespace Jackett.Indexers
protected async Task<byte[]> Download(Uri link, RequestType method)
{
// return magnet link
if (link.Scheme == "magnet")
return Encoding.UTF8.GetBytes(link.OriginalString);
// do some extra escaping, needed for HD-Torrents
var requestLink = link.ToString()
.Replace("(", "%28")

View File

@@ -266,9 +266,11 @@ namespace Jackett.Indexers
var conditionResultState = false;
var value = variables[condition];
if (value is string)
if (value == null)
conditionResultState = false;
else if (value is string)
conditionResultState = !string.IsNullOrWhiteSpace((string)value);
else if(value is ICollection)
else if (value is ICollection)
conditionResultState = ((ICollection)value).Count > 0;
else
throw new Exception(string.Format("Unexpceted type for variable {0}: {1}", condition, value.GetType()));

View File

@@ -144,7 +144,6 @@ namespace Jackett.Indexers
release.BannerUrl = coverUri;
release.Imdb = movie_imdbid;
release.Comments = new Uri(string.Format("{0}?id={1}", SearchUrl, WebUtility.UrlEncode(movie_groupid)));
release.Guid = release.Comments;
release.Size = long.Parse((string)torrent["Size"]);
release.Grabs = long.Parse((string)torrent["Snatched"]);
release.Seeders = int.Parse((string)torrent["Seeders"]);
@@ -153,6 +152,7 @@ namespace Jackett.Indexers
CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToLocalTime();
release.Link = new Uri(string.Format("{0}?action=download&id={1}&authkey={2}&torrent_pass={3}",
SearchUrl, WebUtility.UrlEncode((string)torrent["Id"]), WebUtility.UrlEncode(AuthKey), WebUtility.UrlEncode(configData.Passkey.Value)));
release.Guid = release.Link;
release.MinimumRatio = 1;
release.MinimumSeedTime = 345600;
release.Category = new List<int> { 2000 };

View File

@@ -6,11 +6,115 @@
</PropertyGroup>
<ItemGroup>
<Content Include="Content\animate.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\binding_dark.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\bootstrap\bootstrap.min.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\bootstrap\bootstrap.min.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\common.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\congruent_outline.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\crissXcross.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\css\bootstrap-multiselect.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\css\font-awesome.min.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\css\jquery.dataTables.min.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\custom.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\custom.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\custom_mobile.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\favicon.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\fonts\fontawesome-webfont.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\fonts\glyphicons-halflings-regular.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\images\sort_asc.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\images\sort_asc_disabled.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\images\sort_both.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\images\sort_desc.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\images\sort_desc_disabled.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\index.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\jacket_medium.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\libs\api.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\libs\bootstrap-multiselect.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\libs\bootstrap-notify.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\libs\filesize.min.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\libs\handlebars.min.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\libs\handlebarsextend.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\libs\handlebarsmoment.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\libs\jquery.dataTables.min.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\libs\jquery.min.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\libs\moment.min.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\login.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Models\TorznabCatType.tt" />
<Content Include="Resources\validator_reply.xml" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AngleSharp" Version="0.9.9" />
<PackageReference Include="Autofac" Version="4.6.2" />
<PackageReference Include="AutoMapper" Version="6.1.1" />
<PackageReference Include="BencodeNET" Version="2.2.22" />
<PackageReference Include="CloudFlareUtilities" Version="0.4.0-alpha" />
@@ -39,9 +143,41 @@
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<None Update="Content\fonts\fontawesome-webfont.eot">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Content\fonts\fontawesome-webfont.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Content\fonts\fontawesome-webfont.woff">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Content\fonts\fontawesome-webfont.woff2">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Content\fonts\FontAwesome.otf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Content\fonts\glyphicons-halflings-regular.eot">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Content\fonts\glyphicons-halflings-regular.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Content\fonts\glyphicons-halflings-regular.woff">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Content\fonts\glyphicons-halflings-regular.woff2">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Models\TorznabCatType.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>TorznabCatType.generated.cs</LastGenOutput>
@@ -71,6 +207,13 @@
<Version>2.0.0</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>

View File

@@ -2,7 +2,6 @@
using System;
using System.Linq;
using System.Text;
using Autofac.Integration.WebApi;
using Jackett.Indexers;
using Jackett.Utils.Clients;
using AutoMapper;
@@ -16,6 +15,7 @@ using Jackett.Models.Config;
using System.IO;
using Newtonsoft.Json.Linq;
using Jackett.Utils;
using System.Collections.Generic;
namespace Jackett
{
@@ -24,10 +24,7 @@ namespace Jackett
protected override void Load(ContainerBuilder builder)
{
// Just register everything! TODO: Something better and more explicit than scanning everything.
var assembliesToScan = new Assembly[] { typeof(JackettModule).Assembly, typeof(JackettStartup).Assembly };
foreach (var assembly in assembliesToScan)
{
builder.RegisterAssemblyTypes(assembly)
builder.RegisterAssemblyTypes(typeof(JackettModule).Assembly)
.Except<IIndexer>()
.Except<IImdbResolver>()
.Except<OmdbResolver>()
@@ -43,8 +40,7 @@ namespace Jackett
.Except<AggregateIndexer>()
.Except<CardigannIndexer>()
.AsImplementedInterfaces().SingleInstance();
}
builder.RegisterApiControllers(typeof(JackettModule).Assembly).InstancePerRequest();
builder.Register(ctx =>
{
return BuildServerConfig(ctx);
@@ -135,14 +131,16 @@ namespace Jackett
{
cfg.CreateMap<WebClientByteResult, WebClientStringResult>().ForMember(x => x.Content, opt => opt.Ignore()).AfterMap((be, str) =>
{
str.Content = Encoding.UTF8.GetString(be.Content);
var encoding = be.Request.Encoding ?? Encoding.UTF8;
str.Content = encoding.GetString(be.Content);
});
cfg.CreateMap<WebClientStringResult, WebClientByteResult>().ForMember(x => x.Content, opt => opt.Ignore()).AfterMap((str, be) =>
{
if (!string.IsNullOrEmpty(str.Content))
{
be.Content = Encoding.UTF8.GetBytes(str.Content);
var encoding = str.Request.Encoding ?? Encoding.UTF8;
be.Content = encoding.GetBytes(str.Content);
}
});

View File

@@ -0,0 +1,101 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Jackett.Common.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Jackett.Common.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;
///&lt;rss version=&quot;1.0&quot; xmlns:atom=&quot;http://www.w3.org/2005/Atom&quot; xmlns:torznab=&quot;http://torznab.com/schemas/2015/feed&quot;&gt;
/// &lt;channel&gt;
/// &lt;atom:link href=&quot;https://hdaccess.net/api&quot; rel=&quot;self&quot; type=&quot;application/rss+xml&quot; /&gt;
/// &lt;title&gt;HDAccess&lt;/title&gt;
/// &lt;description&gt;HDAccess API&lt;/description&gt;
/// &lt;link&gt;https://hdaccess.net&lt;/link&gt;
/// &lt;language&gt;en-us&lt;/language&gt;
/// &lt;webMaster&gt;($email) (HDA Invites)&lt;/webMaster&gt;
/// &lt;category&gt;search&lt;/category&gt;
/// &lt;image&gt;
/// &lt;url&gt;h [rest of string was truncated]&quot;;.
/// </summary>
public static string test {
get {
return ResourceManager.GetString("test", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;
///&lt;rss version=&quot;1.0&quot; xmlns:atom=&quot;http://www.w3.org/2005/Atom&quot; xmlns:torznab=&quot;http://torznab.com/schemas/2015/feed&quot;&gt;
/// &lt;channel&gt;
/// &lt;item&gt;
/// &lt;link&gt;https://example.com&lt;/link&gt;
/// &lt;pubDate&gt;Sat, 14 Mar 2015 17:10:42 -0400&lt;/pubDate&gt;
/// &lt;enclosure url=&quot;https://example.com&quot; length=&quot;1&quot; type=&quot;application/x-bittorrent&quot; /&gt;
/// &lt;/item&gt;
/// &lt;/channel&gt;
///&lt;/rss&gt;.
/// </summary>
public static string validator_reply {
get {
return ResourceManager.GetString("validator_reply", resourceCulture);
}
}
}
}

View File

@@ -0,0 +1,127 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="test" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\test.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="validator_reply" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\validator_reply.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
</root>

View File

@@ -173,7 +173,7 @@ namespace Jackett.Services
#if DEBUG
// When we are running in debug use the source files
var sourcePath = Path.GetFullPath(Path.Combine(ApplicationFolder(), "..\\..\\..\\Jackett\\Content"));
var sourcePath = Path.GetFullPath(Path.Combine(ApplicationFolder(), "..\\..\\..\\Jackett.Common\\Content"));
if (Directory.Exists(sourcePath))
{
dir = sourcePath;
@@ -202,7 +202,7 @@ namespace Jackett.Services
#if DEBUG
// When we are running in debug use the source files
var sourcePath = Path.GetFullPath(Path.Combine(ApplicationFolder(), "..\\..\\..\\Jackett\\Definitions"));
var sourcePath = Path.GetFullPath(Path.Combine(ApplicationFolder(), "..\\..\\..\\Jackett.Common\\Definitions"));
if (Directory.Exists(sourcePath))
{
dir = sourcePath;

View File

@@ -10,7 +10,7 @@ namespace Jackett.Services.Interfaces
void Start();
void Stop();
void ReserveUrls(bool doInstall = true);
Uri ConvertToProxyLink(Uri link, string serverUrl, string indexerId, string action = "dl", string file = "t.torrent");
Uri ConvertToProxyLink(Uri link, string serverUrl, string indexerId, string action = "dl", string file = "t");
string BasePath();
string GetServerUrl(HttpRequestMessage Request);
List<string> notices { get; }

View File

@@ -21,6 +21,7 @@ namespace JackettConsole
{
public class Program
{
static void Main(string[] args)
{
try
@@ -32,7 +33,7 @@ namespace JackettConsole
{
var help = new HelpText();
var errors = help.RenderParsingErrorsText(options, 2); // indent with two spaces
Console.WriteLine("Jackett v" + Engine.ConfigService.GetVersion());
Console.WriteLine("Jackett v" + JackettStartup.JackettVersion);
Console.WriteLine("Switch error: " + errors);
Console.WriteLine("See --help for further details on switches.");
Environment.ExitCode = 1;
@@ -51,63 +52,38 @@ namespace JackettConsole
}
else
{
if (options.ListenPublic && options.ListenPrivate)
{
Console.WriteLine("You can only use listen private OR listen publicly.");
Environment.ExitCode = 1;
return;
}
/* ====== Options ===== */
// SSL Fix
JackettStartup.DoSSLFix = options.SSLFix;
// Use curl
if (options.Client != null)
JackettStartup.ClientOverride = options.Client.ToLowerInvariant();
// Use Proxy
if (options.ProxyConnection != null)
{
JackettStartup.ProxyConnection = options.ProxyConnection.ToLowerInvariant();
Engine.Logger.Info("Proxy enabled. " + JackettStartup.ProxyConnection);
}
// Logging
if (options.Logging)
JackettStartup.LogRequests = true;
// Tracing
if (options.Tracing)
JackettStartup.TracingEnabled = true;
// Log after the fact as using the logger will cause the options above to be used
SetJacketOptions(options);
// Initialize autofac, logger, etc. We cannot use any calls to Engine before the container is set up.
Engine.BuildContainer(new WebApi2Module());
if (options.Logging)
Engine.Logger.Info("Logging enabled.");
if (options.Tracing)
Engine.Logger.Info("Tracing enabled.");
if (options.SSLFix == true)
Engine.Logger.Info("SSL ECC workaround enabled.");
else if (options.SSLFix == false)
Engine.Logger.Info("SSL ECC workaround has been disabled.");
// Ignore SSL errors on Curl
JackettStartup.IgnoreSslErrors = options.IgnoreSslErrors;
if (options.IgnoreSslErrors == true)
{
Engine.Logger.Info("Jackett will ignore SSL certificate errors.");
}
if (options.SSLFix == true)
Engine.Logger.Info("SSL ECC workaround enabled.");
else if (options.SSLFix == false)
Engine.Logger.Info("SSL ECC workaround has been disabled.");
// Choose Data Folder
if (!string.IsNullOrWhiteSpace(options.DataFolder))
{
JackettStartup.CustomDataFolder = options.DataFolder.Replace("\"", string.Empty).Replace("'", string.Empty).Replace(@"\\", @"\");
Engine.Logger.Info("Jackett Data will be stored in: " + JackettStartup.CustomDataFolder);
}
// Use Proxy
if (options.ProxyConnection != null)
{
Engine.Logger.Info("Proxy enabled. " + JackettStartup.ProxyConnection);
}
/* ====== Actions ===== */
// Install service
@@ -218,8 +194,6 @@ namespace JackettConsole
Engine.SaveServerConfig();
}
}
JackettStartup.NoRestart = options.NoRestart;
}
Engine.Server.Initalize();
@@ -232,6 +206,48 @@ namespace JackettConsole
Engine.Logger.Error(e, "Top level exception");
}
}
static void SetJacketOptions(ConsoleOptions options)
{
// Logging
if (options.Logging)
JackettStartup.LogRequests = true;
// Tracing
if (options.Tracing)
JackettStartup.TracingEnabled = true;
if (options.ListenPublic && options.ListenPrivate)
{
Console.WriteLine("You can only use listen private OR listen publicly.");
Environment.ExitCode = 1;
return;
}
// SSL Fix
JackettStartup.DoSSLFix = options.SSLFix;
// Use curl
if (options.Client != null)
JackettStartup.ClientOverride = options.Client.ToLowerInvariant();
// Use Proxy
if (options.ProxyConnection != null)
{
JackettStartup.ProxyConnection = options.ProxyConnection.ToLowerInvariant();
}
// Ignore SSL errors on Curl
JackettStartup.IgnoreSslErrors = options.IgnoreSslErrors;
JackettStartup.NoRestart = options.NoRestart;
}
}
}

View File

@@ -66,7 +66,6 @@
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ServiceConfigService.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />

View File

@@ -19,6 +19,7 @@ namespace Jackett.Service
protected override void OnStart(string[] args)
{
Engine.BuildContainer(new WebApi2Module());
Engine.Logger.Info("Service starting");
Engine.Server.Initalize();
Engine.Server.Start();

View File

@@ -22,15 +22,11 @@ namespace Jackett.Test
{
var builder = new ContainerBuilder();
builder.RegisterModule<JackettModule>();
builder.RegisterModule<WebApi2Module>();
builder.RegisterType<TestWebClient>().As<WebClient>().SingleInstance();
builder.RegisterInstance<Logger>(LogManager.GetCurrentClassLogger()).SingleInstance();
builder.RegisterType<TestIndexerManagerServiceHelper>().As<IIndexerManagerService>().SingleInstance();
testContainer = builder.Build();
// Register the container in itself to allow for late resolves
var secondaryBuilder = new ContainerBuilder();
secondaryBuilder.RegisterInstance<IContainer>(testContainer).SingleInstance();
secondaryBuilder.Update(testContainer);
}
public static TestIndexerManagerServiceHelper IndexManager

View File

@@ -28,12 +28,13 @@ namespace JackettTray
toolStripMenuItemWebUI.Click += toolStripMenuItemWebUI_Click;
toolStripMenuItemShutdown.Click += toolStripMenuItemShutdown_Click;
#if __MonoCS__
// No shortcuts on linux
#else
toolStripMenuItemAutoStart.Visible = true;
#endif
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
toolStripMenuItemAutoStart.Visible = true;
}
Engine.BuildContainer(new WebApi2Module());
Engine.Server.Initalize();
if (!Engine.ServiceConfig.ServiceExists())
@@ -104,16 +105,15 @@ namespace JackettTray
private void CreateShortcut()
{
#if __MonoCS__
// No shortcuts on linux
#else
var appPath = Assembly.GetExecutingAssembly().Location;
var shell = new IWshRuntimeLibrary.WshShell();
var shortcut = (IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(ShortcutPath);
shortcut.Description = Assembly.GetExecutingAssembly().GetName().Name;
shortcut.TargetPath = appPath;
shortcut.Save();
#endif
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
var appPath = Assembly.GetExecutingAssembly().Location;
var shell = new IWshRuntimeLibrary.WshShell();
var shortcut = (IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(ShortcutPath);
shortcut.Description = Assembly.GetExecutingAssembly().GetName().Name;
shortcut.TargetPath = appPath;
shortcut.Save();
}
}
private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)

View File

@@ -10,12 +10,6 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
/*
// no supported by appveyor, disabeling for now
#if __MonoCS__
using Mono.Unix.Native;
#endif
*/
namespace Jackett.Updater
{
@@ -28,6 +22,7 @@ namespace Jackett.Updater
private void Run(string[] args)
{
Engine.BuildContainer();
Engine.SetupLogging(null, "updater.txt");
Engine.Logger.Info("Jackett Updater v" + GetCurrentVersion());
Engine.Logger.Info("Options \"" + string.Join("\" \"", args) + "\"");
@@ -68,13 +63,7 @@ namespace Jackett.Updater
var exited = proc.WaitForExit(5000);
if (!exited)
Engine.Logger.Info("Process " + pid.ToString() + " didn't exit within 5 seconds");
/*
// no supported by appveyor, disabeling for now
#if __MonoCS__
Engine.Logger.Info("Sending SIGKILL to process " + pid.ToString());
Syscall.kill(proc.Id, Signum.SIGKILL);
#endif
*/
}
catch (ArgumentException)
{

View File

@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27004.2006
VisualStudioVersion = 15.0.27004.2008
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jackett", "Jackett\Jackett.csproj", "{E636D5F8-68B4-4903-B4ED-CCFD9C9E899F}"
EndProject
@@ -9,6 +9,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{BE7B0C8A-6144-47CD-821E-B09BA1B7BADE}"
ProjectSection(SolutionItems) = preProject
..\appveyor.yml = ..\appveyor.yml
..\build.cake = ..\build.cake
..\Installer.iss = ..\Installer.iss
..\LICENSE = ..\LICENSE
..\README.md = ..\README.md

View File

@@ -50,8 +50,23 @@ namespace Jackett.Controllers
path = Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(path));
path = protectionService.UnProtect(path);
var remoteFile = new Uri(path, UriKind.RelativeOrAbsolute);
var fileExtension = ".torrent";
var downloadBytes = await indexer.Download(remoteFile);
// handle magnet URLs
if (downloadBytes.Length >= 7
&& downloadBytes[0] == 0x6d // m
&& downloadBytes[1] == 0x61 // a
&& downloadBytes[2] == 0x67 // g
&& downloadBytes[3] == 0x6e // n
&& downloadBytes[4] == 0x65 // e
&& downloadBytes[5] == 0x74 // t
&& downloadBytes[6] == 0x3a // :
)
{
fileExtension = ".magnet";
}
if (string.IsNullOrWhiteSpace(serverConfig.BlackholeDir))
{
throw new Exception("Blackhole directory not set!");
@@ -64,9 +79,9 @@ namespace Jackett.Controllers
var fileName = DateTime.Now.Ticks.ToString() + "-" + StringUtil.MakeValidFileName(indexer.DisplayName, '_', false);
if (string.IsNullOrWhiteSpace(file))
fileName += ".torrent";
fileName += fileExtension;
else
fileName += "-"+StringUtil.MakeValidFileName(file, '_', false); // call MakeValidFileName() again to avoid any possibility of path traversal attacks
fileName += "-"+StringUtil.MakeValidFileName(file + fileExtension, '_', false); // call MakeValidFileName() again to avoid any possibility of path traversal attacks
File.WriteAllBytes(Path.Combine(serverConfig.BlackholeDir, fileName), downloadBytes);
jsonReply["result"] = "success";

View File

@@ -53,6 +53,23 @@ namespace Jackett.Controllers
var target = new Uri(path, UriKind.RelativeOrAbsolute);
var downloadBytes = await indexer.Download(target);
// handle magnet URLs
if (downloadBytes.Length >= 7
&& downloadBytes[0] == 0x6d // m
&& downloadBytes[1] == 0x61 // a
&& downloadBytes[2] == 0x67 // g
&& downloadBytes[3] == 0x6e // n
&& downloadBytes[4] == 0x65 // e
&& downloadBytes[5] == 0x74 // t
&& downloadBytes[6] == 0x3a // :
)
{
var magneturi = Encoding.UTF8.GetString(downloadBytes);
var response = Request.CreateResponse(HttpStatusCode.Moved);
response.Headers.Location = new Uri(magneturi);
return response;
}
// This will fix torrents where the keys are not sorted, and thereby not supported by Sonarr.
var parser = new BencodeParser();
var torrentDictionary = parser.Parse(downloadBytes);
@@ -63,7 +80,7 @@ namespace Jackett.Controllers
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-bittorrent");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = StringUtil.MakeValidFileName(file, '_', false) // call MakeValidFileName again to avoid any kind of injection attack
FileName = StringUtil.MakeValidFileName(file, '_', false) + ".torrent" // call MakeValidFileName again to avoid any kind of injection attack
};
return result;
}

View File

@@ -156,7 +156,7 @@ namespace Jackett.Controllers.V20
foreach (var result in results)
{
var link = result.Link;
var file = StringUtil.MakeValidFileName(result.Title, '_', false) + ".torrent";
var file = StringUtil.MakeValidFileName(result.Title, '_', false);
result.Link = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "dl", file);
if (result.Link != null && result.Link.Scheme != "magnet" && !string.IsNullOrWhiteSpace(Engine.ServerConfig.BlackholeDir))
result.BlackholeLink = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "bh", file);

View File

@@ -319,7 +319,7 @@ namespace Jackett.Controllers.V20
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");
r.Link = serverService.ConvertToProxyLink(r.Link, serverUrl, r.Origin.ID, "dl", r.Title);
return r;
});
@@ -371,7 +371,7 @@ namespace Jackett.Controllers.V20
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");
release.Link = serverService.ConvertToProxyLink(release.Link, serverUrl, CurrentIndexer.ID, "dl", release.Title);
var item = new Models.DTO.TorrentPotatoResponseItem()
{
release_name = release.Title + "[" + CurrentIndexer.DisplayName + "]", // Suffix the indexer so we can see which tracker we are using in CPS as it just says torrentpotato >.>
@@ -403,7 +403,7 @@ namespace Jackett.Controllers.V20
foreach (var result in results)
{
var link = result.Link;
var file = StringUtil.MakeValidFileName(result.Title, '_', false) + ".torrent";
var file = StringUtil.MakeValidFileName(result.Title, '_', false);
result.Link = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "dl", file);
if (result.Link != null && result.Link.Scheme != "magnet" && !string.IsNullOrWhiteSpace(Engine.ServerConfig.BlackholeDir))
result.BlackholeLink = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "bh", file);

View File

@@ -168,7 +168,7 @@ namespace Jackett.Controllers.V20
{
Thread.Sleep(500);
serverService.Stop();
Engine.BuildContainer();
Engine.BuildContainer(new WebApi2Module());
Engine.Server.Initalize();
Engine.Server.Start();
})).Start();

View File

@@ -76,17 +76,13 @@
<Compile Include="CacheControlAttribute.cs" />
<Compile Include="Controllers\BlackholeController.cs" />
<Compile Include="Controllers\DownloadController.cs" />
<Compile Include="Engine.cs" />
<Compile Include="JackettProtectedAttribute.cs" />
<Compile Include="CookieContainerExtensions.cs" />
<Compile Include="HttpClientExtensions.cs" />
<Compile Include="JackettModule.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Services\ServiceConfigService.cs" />
<Compile Include="Services\ProtectionService.cs" />
<Compile Include="Services\SecuityService.cs" />
<Compile Include="Startup.cs" />
@@ -99,58 +95,12 @@
<Compile Include="Services\ServerService.cs" />
<Compile Include="Utils\WebAPIRequestLogger.cs" />
<Compile Include="Utils\WebAPIToNLogTracer.cs" />
<Compile Include="WebApi2Module.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config">
<SubType>Designer</SubType>
</None>
<None Include="Content\fonts\fontawesome-webfont.eot">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Content\fonts\fontawesome-webfont.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Content\fonts\fontawesome-webfont.woff">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Content\fonts\fontawesome-webfont.woff2">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Content\fonts\FontAwesome.otf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Content\fonts\glyphicons-halflings-regular.eot">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Content\fonts\glyphicons-halflings-regular.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Content\fonts\glyphicons-halflings-regular.woff2">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Content\fonts\glyphicons-halflings-regular.woff">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Content Include="Content\css\bootstrap-multiselect.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\custom_mobile.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="Resources\test.xml" />
<Content Include="Content\libs\api.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Content Include="Content\libs\bootstrap-multiselect.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\libs\handlebarsextend.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Properties\Resources.resx">
@@ -158,96 +108,6 @@
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Content Include="Content\css\font-awesome.min.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\css\jquery.dataTables.min.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\custom.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\custom.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\libs\filesize.min.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\fonts\fontawesome-webfont.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\fonts\glyphicons-halflings-regular.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\images\sort_asc.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\images\sort_asc_disabled.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\images\sort_both.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\images\sort_desc.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\images\sort_desc_disabled.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\libs\handlebars.min.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\libs\handlebarsmoment.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\libs\jquery.dataTables.min.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\libs\jquery.min.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\libs\moment.min.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\login.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\animate.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\binding_dark.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\libs\bootstrap-notify.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\congruent_outline.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\crissXcross.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\favicon.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\jacket_medium.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\bootstrap\bootstrap.min.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\bootstrap\bootstrap.min.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\common.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\index.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Resources\validator_reply.xml" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.5.1">
<Visible>False</Visible>
@@ -269,8 +129,8 @@
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Autofac.WebApi2.Owin">
<Version>4.0.0</Version>
<PackageReference Include="Autofac.WebApi2">
<Version>4.1.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.AspNet.WebApi.OwinSelfHost">
<Version>5.2.3</Version>

View File

@@ -59,43 +59,5 @@ namespace Jackett.Properties {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;
///&lt;rss version=&quot;1.0&quot; xmlns:atom=&quot;http://www.w3.org/2005/Atom&quot; xmlns:torznab=&quot;http://torznab.com/schemas/2015/feed&quot;&gt;
/// &lt;channel&gt;
/// &lt;atom:link href=&quot;https://hdaccess.net/api&quot; rel=&quot;self&quot; type=&quot;application/rss+xml&quot; /&gt;
/// &lt;title&gt;HDAccess&lt;/title&gt;
/// &lt;description&gt;HDAccess API&lt;/description&gt;
/// &lt;link&gt;https://hdaccess.net&lt;/link&gt;
/// &lt;language&gt;en-us&lt;/language&gt;
/// &lt;webMaster&gt;($email) (HDA Invites)&lt;/webMaster&gt;
/// &lt;category&gt;search&lt;/category&gt;
/// &lt;image&gt;
/// &lt;url&gt;h [rest of string was truncated]&quot;;.
/// </summary>
internal static string test {
get {
return ResourceManager.GetString("test", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;
///&lt;rss version=&quot;1.0&quot; xmlns:atom=&quot;http://www.w3.org/2005/Atom&quot; xmlns:torznab=&quot;http://torznab.com/schemas/2015/feed&quot;&gt;
/// &lt;channel&gt;
/// &lt;item&gt;
/// &lt;link&gt;https://example.com&lt;/link&gt;
/// &lt;pubDate&gt;Sat, 14 Mar 2015 17:10:42 -0400&lt;/pubDate&gt;
/// &lt;enclosure url=&quot;https://example.com&quot; length=&quot;1&quot; type=&quot;application/x-bittorrent&quot; /&gt;
/// &lt;/item&gt;
/// &lt;/channel&gt;
///&lt;/rss&gt;.
/// </summary>
internal static string validator_reply {
get {
return ResourceManager.GetString("validator_reply", resourceCulture);
}
}
}
}

View File

@@ -117,11 +117,4 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="test" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\test.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="validator_reply" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\validator_reply.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
</root>

View File

@@ -59,7 +59,7 @@ namespace Jackett.Services
}
}
public Uri ConvertToProxyLink(Uri link, string serverUrl, string indexerId, string action = "dl", string file = "t.torrent")
public Uri ConvertToProxyLink(Uri link, string serverUrl, string indexerId, string action = "dl", string file = "t")
{
if (link == null || (link.IsAbsoluteUri && link.Scheme == "magnet"))
return link;

View File

@@ -15,6 +15,7 @@ using System.Web.Http.Filters;
using Newtonsoft.Json.Linq;
using Jacket.Common;
using System.Text;
using Autofac.Integration.WebApi;
[assembly: OwinStartup(typeof(Startup))]
namespace Jackett
@@ -134,7 +135,9 @@ namespace Jackett
if (JackettStartup.LogRequests)
config.MessageHandlers.Add(new WebAPIRequestLogger());
config.DependencyResolver = Engine.DependencyResolver();
config.DependencyResolver = new AutofacWebApiDependencyResolver(Engine.GetContainer());
config.MapHttpAttributeRoutes();
// Sonarr appends /api by default to all Torznab indexers, so we need that "ignored"

View File

@@ -0,0 +1,19 @@
using Autofac;
using Autofac.Integration.WebApi;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Jackett
{
public class WebApi2Module : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterAssemblyTypes(typeof(WebApi2Module).Assembly).AsImplementedInterfaces().SingleInstance();
builder.RegisterApiControllers(typeof(WebApi2Module).Assembly).InstancePerRequest();
}
}
}