mirror of https://github.com/Jackett/Jackett
Compare commits
21 Commits
79a5804cbe
...
33a2bf6062
Author | SHA1 | Date |
---|---|---|
Boris Gerretzen | 33a2bf6062 | |
Garfield69 | fadff9584d | |
Garfield69 | b4b337ac90 | |
Garfield69 | 4db2fe5da1 | |
ilike2burnthing | 84d2b5f1d1 | |
ilike2burnthing | b8dc1f2ca3 | |
Cedric | b92d15d9a2 | |
Garfield69 | 6cf2285abe | |
Garfield69 | 8da3684a19 | |
Garfield69 | e5e0f1d2b0 | |
Garfield69 | a22fed3e32 | |
Garfield69 | fc8af644e2 | |
Garfield69 | dbb16a3deb | |
Garfield69 | 9faf972410 | |
Garfield69 | d9fdf31452 | |
Boris | 8d3dfd43d4 | |
Boris Gerretzen | 4eaacaeb94 | |
Bogdan | 86f5e5abce | |
Boris | e4911054e3 | |
Boris | 533a25da54 | |
Boris | 23b62c2fa6 |
|
@ -33,11 +33,16 @@ on:
|
|||
- '!src/Jackett.Test/**'
|
||||
schedule:
|
||||
- cron: '00 00 * * 5'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: windows-2022
|
||||
if: github.repository == 'Jackett/Jackett'
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
|
|
|
@ -16,6 +16,7 @@ jobs:
|
|||
redeliver-failed-deliveries:
|
||||
name: Redeliver failed deliveries
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'Jackett/Jackett'
|
||||
steps:
|
||||
# This workflow will run a script that is stored in the repository. This step checks out the repository contents so that the workflow can access the script.
|
||||
- name: Check out repo content
|
||||
|
|
|
@ -105,6 +105,13 @@ search:
|
|||
selector: category_id
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
|
@ -133,8 +140,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -173,9 +178,4 @@ search:
|
|||
minimumseedtime:
|
||||
# 5 days (as seconds = 5 x 24 x 60 x 60)
|
||||
text: 432000
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
# json UNIT3D 8.0.2
|
||||
|
|
|
@ -89,9 +89,6 @@ settings:
|
|||
asc: asc
|
||||
|
||||
search:
|
||||
# https://bigfangroup.org/browse.php?search=black+lightning&cat=0&incldead=0&year=0&format=0
|
||||
headers:
|
||||
Referer: ["{{ .Config.sitelink }}browse.php{{ if .Keywords }}?search={{ .Keywords }}&cat=0&incldead=1&year=0&format=0{{ else }}{{ end }}"]
|
||||
paths:
|
||||
# https://bigfangroup.org/browse.php?ajax=1&search=the+librarian&cat=0&incldead=0&year=0&format=0
|
||||
- path: browse.php
|
||||
|
@ -101,7 +98,7 @@ search:
|
|||
cat: "{{ if .Keywords }}0{{ else }}{{ end }}"
|
||||
# 0 active, 1 incldead, 2 onlydead, 3 gold, 4 noseed, 5 silver, 7 BFG
|
||||
incldead: "{{ if .Keywords }}1{{ else }}{{ end }}"
|
||||
year: "{{ if .Keywords }}0{{ else }}{{ end }}"
|
||||
year: "{{ if .Keywords }}0{{ else }}1{{ end }}"
|
||||
format: "{{ if .Keywords }}0{{ else }}{{ end }}"
|
||||
s: "{{ if .Keywords }}{{ .Config.sort }}{{ else }}{{ end }}"
|
||||
d: "{{ if .Keywords }}{{ .Config.type }}{{ else }}{{ end }}"
|
||||
|
|
|
@ -105,6 +105,13 @@ search:
|
|||
selector: category_id
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
|
@ -133,8 +140,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -173,9 +178,4 @@ search:
|
|||
minimumseedtime:
|
||||
# 7 day (as seconds = 7 x 24 x 60 x 60)
|
||||
text: 604800
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
# json UNIT3D 8.0.2
|
||||
|
|
|
@ -39,10 +39,10 @@ settings:
|
|||
type: checkbox
|
||||
label: Search freeleech only
|
||||
default: false
|
||||
- name: single_file_release_use_filename
|
||||
- name: use_single_file_release_use_filename
|
||||
type: checkbox
|
||||
label: Use filename as title for single file releases
|
||||
default: true
|
||||
label: Use filename as the title for single file releases
|
||||
default: false
|
||||
- name: sort
|
||||
type: select
|
||||
label: Sort requested from site
|
||||
|
@ -110,6 +110,13 @@ search:
|
|||
selector: category_id
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title:
|
||||
text: "{{ if and (.Config.use_single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
|
@ -138,8 +145,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -178,9 +183,4 @@ search:
|
|||
minimumseedtime:
|
||||
# 7 days (as seconds = 7 x 24 x 60 x 60)
|
||||
text: 604800
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
# json UNIT3D 8.0.2
|
||||
# json UNIT3D 8.0.2 (custom)
|
||||
|
|
|
@ -107,6 +107,13 @@ search:
|
|||
selector: category_id
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
|
@ -135,8 +142,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -175,9 +180,4 @@ search:
|
|||
minimumseedtime:
|
||||
# 3 days (as seconds = 3 x 24 x 60 x 60)
|
||||
text: 259200
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
# json UNIT3D 8.0.1
|
||||
# json UNIT3D 8.0.2
|
||||
|
|
|
@ -105,6 +105,13 @@ search:
|
|||
selector: category_id
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
|
@ -133,8 +140,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -170,9 +175,4 @@ search:
|
|||
# Maintain global ratio above 0.5 or downloads will get disabled. No MST.
|
||||
minimumratio:
|
||||
text: 0.51
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
# json UNIT3D 8.0.2
|
||||
|
|
|
@ -6,8 +6,6 @@ language: es-ES
|
|||
type: public
|
||||
encoding: UTF-8
|
||||
requestDelay: 2
|
||||
certificates:
|
||||
- b738ae9ae55c5553b1ff7d3004d807229be3a091 # Expired 4 Dec 2023
|
||||
links:
|
||||
- https://www.frozen-layer.com/
|
||||
|
||||
|
|
|
@ -104,6 +104,13 @@ search:
|
|||
selector: category_id
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
|
@ -132,8 +139,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -169,9 +174,4 @@ search:
|
|||
minimumseedtime:
|
||||
# 3 days (as seconds = 3 x 24 x 60 x 60)
|
||||
text: 259200
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
# json UNIT3D 8.0.2
|
||||
|
|
|
@ -103,6 +103,20 @@ search:
|
|||
selector: category_id
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
filters:
|
||||
- name: re_replace
|
||||
args: ["\\.", " "]
|
||||
- name: re_replace # Stagione X --> S0X
|
||||
args: ["(?i)\\bStagion[ei]\\s?(\\d{1})\\b|\\bSeason'?s?\\s?(\\d{1})\\b", "S0$1$2"]
|
||||
- name: re_replace # Stagione XX --> SXX
|
||||
args: ["(?i)\\bStagion[ei]\\s?(\\d{2,})\\b|\\bSeason'?s?\\s?(\\d{2,})\\b", "S$1$2"]
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
|
@ -131,8 +145,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -166,16 +178,4 @@ search:
|
|||
False: 1 # normal
|
||||
True: 2 # double
|
||||
# as a pay site there is no MR or MST
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
filters:
|
||||
- name: re_replace
|
||||
args: ["\\.", " "]
|
||||
- name: re_replace # Stagione X --> S0X
|
||||
args: ["(?i)\\bStagion[ei]\\s?(\\d{1})\\b|\\bSeason'?s?\\s?(\\d{1})\\b", "S0$1$2"]
|
||||
- name: re_replace # Stagione XX --> SXX
|
||||
args: ["(?i)\\bStagion[ei]\\s?(\\d{2,})\\b|\\bSeason'?s?\\s?(\\d{2,})\\b", "S$1$2"]
|
||||
# json UNIT3D 8.0.2 (custom)
|
||||
|
|
|
@ -113,6 +113,20 @@ search:
|
|||
selector: category_id
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
filters:
|
||||
- name: re_replace
|
||||
args: ["\\.", " "]
|
||||
- name: re_replace # Stagione X --> S0X
|
||||
args: ["(?i)\\bStagion[ei]\\s?(\\d{1})\\b|\\bSeason'?s?\\s?(\\d{1})\\b", "S0$1$2"]
|
||||
- name: re_replace # Stagione XX --> SXX
|
||||
args: ["(?i)\\bStagion[ei]\\s?(\\d{2,})\\b|\\bSeason'?s?\\s?(\\d{2,})\\b", "S$1$2"]
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
|
@ -139,8 +153,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -176,16 +188,4 @@ search:
|
|||
minimumseedtime:
|
||||
# 7 days (as seconds = 7 x 24 x 60 x 60)
|
||||
text: 604800
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
filters:
|
||||
- name: re_replace
|
||||
args: ["\\.", " "]
|
||||
- name: re_replace # Stagione X --> S0X
|
||||
args: ["(?i)\\bStagion[ei]\\s?(\\d{1})\\b|\\bSeason'?s?\\s?(\\d{1})\\b", "S0$1$2"]
|
||||
- name: re_replace # Stagione XX --> SXX
|
||||
args: ["(?i)\\bStagion[ei]\\s?(\\d{2,})\\b|\\bSeason'?s?\\s?(\\d{2,})\\b", "S$1$2"]
|
||||
# json UNIT3D 8.0.2 (custom)
|
||||
|
|
|
@ -5,8 +5,6 @@ description: "KrazyZone is a Private Torrent Tracker for MOVIES / TV / GENERAL"
|
|||
language: en-US
|
||||
type: private
|
||||
encoding: UTF-8
|
||||
certificates:
|
||||
- 2e88b1a9031288c50f942201634b6d1484aca612 # expired 11 Apr 2024
|
||||
links:
|
||||
- https://krazyzone.net/
|
||||
legacylinks:
|
||||
|
|
|
@ -130,6 +130,13 @@ search:
|
|||
selector: category_id
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
|
@ -158,8 +165,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -198,9 +203,4 @@ search:
|
|||
minimumseedtime:
|
||||
# 7 day (as seconds = 7 x 24 x 60 x 60)
|
||||
text: 604800
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
# json UNIT3D 8.0.1
|
||||
|
|
|
@ -113,6 +113,18 @@ search:
|
|||
selector: category_id
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title_phase1:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
title_vose:
|
||||
selector: name:contains(VOSE)
|
||||
optional: true
|
||||
title:
|
||||
text: "{{ .Result.title_phase1 }}{{ if .Result.title_vose }} ENGLiSH{{ else }} SPANiSH{{ end }}"
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
|
@ -141,8 +153,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -181,14 +191,4 @@ search:
|
|||
minimumseedtime:
|
||||
# 3 days (as seconds = 3 x 24 x 60 x 60)
|
||||
text: 259200
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
title_phase1:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
title_vose:
|
||||
selector: name:contains(VOSE)
|
||||
optional: true
|
||||
title:
|
||||
text: "{{ .Result.title_phase1 }}{{ if .Result.title_vose }} ENGLiSH{{ else }} SPANiSH{{ end }}"
|
||||
# json UNIT3D 8.0.2 (custom)
|
||||
|
|
|
@ -11,15 +11,21 @@ links:
|
|||
caps:
|
||||
categorymappings:
|
||||
- {id: 1, cat: Movies, desc: "MOVIES"}
|
||||
- {id: 20, cat: Movies/Foreign, desc: "MOVIES-FOREIGN"}
|
||||
- {id: 2, cat: TV, desc: "TV"}
|
||||
- {id: 3, cat: Audio, desc: "MUSIC"}
|
||||
- {id: 19, cat: TV/Foreign, desc: "TV-FOREIGN"}
|
||||
- {id: 4, cat: PC, desc: "APPS"}
|
||||
- {id: 5, cat: Audio, desc: "MUSIC"}
|
||||
- {id: 6, cat: XXX, desc: "XXX"}
|
||||
- {id: 7, cat: Console, desc: "GAMES"}
|
||||
- {id: 8, cat: Books, desc: "EBOOKS"}
|
||||
|
||||
modes:
|
||||
search: [q]
|
||||
tv-search: [q, season, ep, imdbid, tvdbid, tmdbid]
|
||||
movie-search: [q, imdbid, tmdbid]
|
||||
music-search: [q]
|
||||
# book-search: [q]
|
||||
book-search: [q]
|
||||
|
||||
settings:
|
||||
- name: apikey
|
||||
|
@ -100,6 +106,13 @@ search:
|
|||
selector: category_id
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
|
@ -124,8 +137,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -164,9 +175,4 @@ search:
|
|||
minimumseedtime:
|
||||
# 7 days (as seconds = 7 x 24 x 60 x 60)
|
||||
text: 604800
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
# json UNIT3D 8.0.2
|
||||
|
|
|
@ -109,6 +109,13 @@ search:
|
|||
selector: category_id
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
|
@ -137,8 +144,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -177,9 +182,4 @@ search:
|
|||
minimumseedtime:
|
||||
# 7 days (as seconds = 7 x 24 x 60 x 60)
|
||||
text: 604800
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
# json UNIT3D 8.0.2
|
||||
|
|
|
@ -182,6 +182,8 @@ caps:
|
|||
- {id: 365, cat: Books, desc: "History of Naval Shipbuilding-Aircraft carriers"}
|
||||
- {id: 366, cat: Books, desc: "History of Naval Shipbuilding-Destroyers"}
|
||||
- {id: 367, cat: Books, desc: "History of Naval Shipbuilding-Frigates"}
|
||||
- {id: 371, cat: Books, desc: "History of Naval Shipbuilding-Combat boats"}
|
||||
- {id: 372, cat: Books, desc: "History of Naval Shipbuilding-Coastal defense ships"}
|
||||
- {id: 262, cat: Books, desc: "History of Naval Shipbuilding-The history of sailing ships"}
|
||||
- {id: 323, cat: Books, desc: "History of Naval Shipbuilding-History of Submarines"}
|
||||
- {id: 198, cat: Books, desc: "Navy"}
|
||||
|
|
|
@ -107,6 +107,13 @@ search:
|
|||
selector: category_id
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
filters:
|
||||
- name: re_replace
|
||||
args: ["\\.", " "]
|
||||
|
@ -138,8 +145,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -175,9 +180,4 @@ search:
|
|||
minimumseedtime:
|
||||
# 7 day (as seconds = 7 x 24 x 60 x 60)
|
||||
text: 604800
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
# json UNIT3D 8.0.2
|
||||
|
|
|
@ -35,6 +35,10 @@ settings:
|
|||
type: checkbox
|
||||
label: Search freeleech only
|
||||
default: false
|
||||
- name: single_file_release_use_filename
|
||||
type: checkbox
|
||||
label: Use filename as title for single file releases
|
||||
default: true
|
||||
- name: sort
|
||||
type: select
|
||||
label: Sort requested from site
|
||||
|
@ -100,8 +104,15 @@ search:
|
|||
fields:
|
||||
category:
|
||||
selector: category_id
|
||||
title:
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
|
@ -122,8 +133,6 @@ search:
|
|||
genre:
|
||||
selector: meta.genres
|
||||
filters:
|
||||
- name: re_replace
|
||||
args: ["(?i)^None$", ""]
|
||||
- name: re_replace
|
||||
args: ["(?i)(Science Fiction)", "Science_Fiction"]
|
||||
- name: re_replace
|
||||
|
@ -132,8 +141,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -172,4 +179,4 @@ search:
|
|||
minimumseedtime:
|
||||
# 7 day (as seconds = 7 x 24 x 60 x 60)
|
||||
text: 604800
|
||||
# json UNIT3D 7.2.5
|
||||
# json UNIT3D 8.0.2
|
||||
|
|
|
@ -101,6 +101,13 @@ search:
|
|||
selector: category_id
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
|
@ -129,8 +136,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -169,9 +174,4 @@ search:
|
|||
minimumseedtime:
|
||||
# 2 days (as seconds = 2 x 24 x 60 x 60)
|
||||
text: 172800
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
# json UNIT3D 8.0.2
|
||||
|
|
|
@ -132,6 +132,22 @@ search:
|
|||
selector: category_id
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title_phase1:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
title_multilang:
|
||||
text: "{{ .Result.title_phase1 }}"
|
||||
filters:
|
||||
- name: re_replace
|
||||
args: ["(?i)\\b(MULTI(?!.*(?:POLISH|ENGLISH|\\bPL\\b)))\\b", "{{ .Config.multilanguage }}"]
|
||||
- name: re_replace
|
||||
args: ["(?i)\\b(pl)\\b", "POLISH"]
|
||||
title:
|
||||
text: "{{ if .Config.multilang }}{{ .Result.title_multilang }}{{ else }}{{ .Result.title_phase1 }}{{ end }}"
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
|
@ -160,8 +176,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -197,18 +211,4 @@ search:
|
|||
minimumseedtime:
|
||||
# 7 day (as seconds = 7 x 24 x 60 x 60)
|
||||
text: 604800
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
title_phase1:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
title_multilang:
|
||||
text: "{{ .Result.title_phase1 }}"
|
||||
filters:
|
||||
- name: re_replace
|
||||
args: ["(?i)\\b(MULTI(?!.*(?:POLISH|ENGLISH|\\bPL\\b)))\\b", "{{ .Config.multilanguage }}"]
|
||||
- name: re_replace
|
||||
args: ["(?i)\\b(pl)\\b", "POLISH"]
|
||||
title:
|
||||
text: "{{ if .Config.multilang }}{{ .Result.title_multilang }}{{ else }}{{ .Result.title_phase1 }}{{ end }}"
|
||||
# json UNIT3D 8.0.1 (custom)
|
||||
|
|
|
@ -104,6 +104,13 @@ search:
|
|||
selector: category_id
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
|
@ -132,8 +139,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -168,9 +173,4 @@ search:
|
|||
True: 2 # double
|
||||
minimumratio:
|
||||
text: 1.0
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
# json UNIT3D 8.0.2
|
||||
|
|
|
@ -97,6 +97,13 @@ search:
|
|||
selector: category_id
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
|
@ -123,8 +130,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -163,9 +168,4 @@ search:
|
|||
minimumseedtime:
|
||||
# 5 days (as seconds = 5 x 24 x 60 x 60)
|
||||
text: 432000
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
# json UNIT3D 8.0.2
|
||||
|
|
|
@ -7,7 +7,7 @@ type: semi-private
|
|||
encoding: windows-1251
|
||||
followredirect: true
|
||||
links:
|
||||
- https://26april.rudub.online/
|
||||
- https://27april.rudub.online/
|
||||
legacylinks:
|
||||
- https://rudub.online/
|
||||
- https://06april.rudub.online/
|
||||
|
@ -31,6 +31,7 @@ legacylinks:
|
|||
- https://24april.rudub.online/
|
||||
- https://25pril.rudub.online/ # typo
|
||||
- https://25april.rudub.online/
|
||||
- https://26april.rudub.online/
|
||||
|
||||
caps:
|
||||
categorymappings:
|
||||
|
|
|
@ -119,6 +119,37 @@ search:
|
|||
selector: category_id
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
filters:
|
||||
- name: re_replace # replace special characters with " " (space)
|
||||
args: ["[\\[!\"#$%&'()*+,\\-.\\/:;<=>?@[\\]^_`{|}~]", " "]
|
||||
- name: diacritics
|
||||
args: replace
|
||||
- name: re_replace # replace multiple spaces
|
||||
args: ["[ ]{2,}", " "]
|
||||
# normalize to SXXEYY format
|
||||
- name: re_replace # S01 E01 to S01E01
|
||||
args: ["(?i)\\bS(\\d+)\\sE(\\d+)\\b", "S$1E$2"]
|
||||
- name: re_replace # 01x01 to S01E01
|
||||
args: ["(?i)(\\d{2})x(\\d+)", "S$1E$2"]
|
||||
- name: re_replace # 1x01 to S01E01
|
||||
args: ["(?i)\\b(\\d{1})x(\\d+)", "S0$1E$2"]
|
||||
- name: re_replace # Stagione X --> S0X
|
||||
args: ["(?i)\\bStagion[ei]\\s?(\\d{1})\\b|\\bSeason'?s?\\s?(\\d{1})\\b", "S0$1$2"]
|
||||
- name: re_replace # Stagione XX --> SXX
|
||||
args: ["(?i)\\bStagion[ei]\\s?(\\d{2,})\\b|\\bSeason'?s?\\s?(\\d{2,})\\b", "S$1$2"]
|
||||
- name: re_replace # Episodio 4 to E4
|
||||
args: ["(?i)\\b(?:[\\/\\|]?Episodio\\s?(\\d+)|Puntata\\s?(\\d+))", "E$1$2"]
|
||||
- name: re_replace # Episodi 4 5 to E04-05
|
||||
args: ["(?i)\\b(?:Puntate\\s*)(\\d+)\\s?(\\d+)", "E0$1-0$2"]
|
||||
- name: re_replace # rimozioni varie
|
||||
args: ["(?i)(Serie completa|Completat?a?|in pausa)", ""]
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
|
@ -145,8 +176,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -185,33 +214,4 @@ search:
|
|||
minimumseedtime:
|
||||
# 6 day (as seconds = 6 x 24 x 60 x 60)
|
||||
text: 518400
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
filters:
|
||||
- name: re_replace # replace special characters with " " (space)
|
||||
args: ["[\\[!\"#$%&'()*+,\\-.\\/:;<=>?@[\\]^_`{|}~]", " "]
|
||||
- name: diacritics
|
||||
args: replace
|
||||
- name: re_replace # replace multiple spaces
|
||||
args: ["[ ]{2,}", " "]
|
||||
# normalize to SXXEYY format
|
||||
- name: re_replace # S01 E01 to S01E01
|
||||
args: ["(?i)\\bS(\\d+)\\sE(\\d+)\\b", "S$1E$2"]
|
||||
- name: re_replace # 01x01 to S01E01
|
||||
args: ["(?i)(\\d{2})x(\\d+)", "S$1E$2"]
|
||||
- name: re_replace # 1x01 to S01E01
|
||||
args: ["(?i)\\b(\\d{1})x(\\d+)", "S0$1E$2"]
|
||||
- name: re_replace # Stagione X --> S0X
|
||||
args: ["(?i)\\bStagion[ei]\\s?(\\d{1})\\b|\\bSeason'?s?\\s?(\\d{1})\\b", "S0$1$2"]
|
||||
- name: re_replace # Stagione XX --> SXX
|
||||
args: ["(?i)\\bStagion[ei]\\s?(\\d{2,})\\b|\\bSeason'?s?\\s?(\\d{2,})\\b", "S$1$2"]
|
||||
- name: re_replace # Episodio 4 to E4
|
||||
args: ["(?i)\\b(?:[\\/\\|]?Episodio\\s?(\\d+)|Puntata\\s?(\\d+))", "E$1$2"]
|
||||
- name: re_replace # Episodi 4 5 to E04-05
|
||||
args: ["(?i)\\b(?:Puntate\\s*)(\\d+)\\s?(\\d+)", "E0$1-0$2"]
|
||||
- name: re_replace # rimozioni varie
|
||||
args: ["(?i)(Serie completa|Completat?a?|in pausa)", ""]
|
||||
# json UNIT3D 8.0.2 (custom)
|
||||
|
|
|
@ -101,6 +101,13 @@ search:
|
|||
selector: category_id
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
|
@ -129,8 +136,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -166,9 +171,4 @@ search:
|
|||
minimumseedtime:
|
||||
# 7 days (as seconds = 7 x 24 x 60 x 60)
|
||||
text: 604800
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
# json UNIT3D 8.0.2
|
||||
|
|
|
@ -100,6 +100,13 @@ search:
|
|||
selector: category_id
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
|
@ -128,8 +135,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -165,9 +170,4 @@ search:
|
|||
minimumseedtime:
|
||||
# 7 days (as seconds = 7 x 24 x 60 x 60)
|
||||
text: 604800
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
# json UNIT3D 8.0.1
|
||||
# json UNIT3D 8.0.2
|
||||
|
|
|
@ -113,6 +113,13 @@ search:
|
|||
selector: category_id
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
|
@ -141,8 +148,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -181,9 +186,4 @@ search:
|
|||
minimumseedtime:
|
||||
# 5 days (as seconds = 5 x 24 x 60 x 60)
|
||||
text: 432000
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
# json UNIT3D 8.0.2
|
||||
|
|
|
@ -97,6 +97,13 @@ search:
|
|||
selector: category_id
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
|
@ -125,8 +132,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -165,9 +170,4 @@ search:
|
|||
minimumseedtime:
|
||||
# 7 days (as seconds = 7 x 24 x 60 x 60)
|
||||
text: 604800
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
# json UNIT3D 8.0.2
|
||||
|
|
|
@ -101,6 +101,13 @@ search:
|
|||
selector: category_id
|
||||
title_optional:
|
||||
selector: name
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
files:
|
||||
selector: num_file
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
details:
|
||||
selector: details_link
|
||||
download:
|
||||
|
@ -129,8 +136,6 @@ search:
|
|||
args: [" & ", "_&_"]
|
||||
description:
|
||||
text: "{{ .Result.genre }}"
|
||||
files:
|
||||
selector: num_file
|
||||
seeders:
|
||||
selector: seeders
|
||||
leechers:
|
||||
|
@ -169,9 +174,4 @@ search:
|
|||
minimumseedtime:
|
||||
# 2 day (as seconds = 2 x 24 x 60 x 60)
|
||||
text: 172800
|
||||
title_filename:
|
||||
selector: "files[0].name"
|
||||
optional: true
|
||||
title:
|
||||
text: "{{ if and (.Config.single_file_release_use_filename) (eq .Result.files \"1\") (.Result.title_filename) }}{{ .Result.title_filename }}{{ else }}{{ .Result.title_optional }}{{ end }}"
|
||||
# json UNIT3D 8.0.2
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace Jackett.Common.Helpers
|
||||
{
|
||||
public class LowerCaseNamingStrategy : NamingStrategy
|
||||
{
|
||||
protected override string ResolvePropertyName(string name) => name.ToLowerInvariant();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Jackett.Common.Extensions;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Jackett.Common.Helpers
|
||||
{
|
||||
public static class XmlToJsonConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts an XML element to a JSON object.
|
||||
/// Attributes are stored in an @attributes object.
|
||||
/// </summary>
|
||||
public static JToken XmlToJson(XElement element)
|
||||
{
|
||||
var obj = new JObject();
|
||||
|
||||
// Build @attributes object from element attributes
|
||||
if (element.Attributes().Any())
|
||||
{
|
||||
var attributes = element.Attributes()
|
||||
.ToDictionary(
|
||||
attribute => GetName(attribute.Name, attribute.Parent?.Document),
|
||||
attribute => (JToken)attribute.Value
|
||||
);
|
||||
obj.Add("@attributes", JObject.FromObject(attributes));
|
||||
}
|
||||
|
||||
foreach (var childElement in element.Elements())
|
||||
{
|
||||
var childObj = XmlToJson(childElement);
|
||||
var childName = GetName(childElement.Name, element.Document);
|
||||
|
||||
// If the child name already exists, convert it to an array
|
||||
if (obj.ContainsKey(childName))
|
||||
{
|
||||
if (obj[childName] is JArray existingArray)
|
||||
{
|
||||
existingArray.Add(childObj);
|
||||
}
|
||||
else
|
||||
{
|
||||
obj[childName] = new JArray(obj[childName]!, childObj);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
obj.Add(childName, childObj);
|
||||
}
|
||||
}
|
||||
|
||||
if (!element.Elements().Any() && !element.Value.IsNullOrWhiteSpace())
|
||||
{
|
||||
return element.Value;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static string GetName(XName name, XDocument document)
|
||||
{
|
||||
if (document == null)
|
||||
{
|
||||
return name.LocalName;
|
||||
}
|
||||
|
||||
var prefix = document.Root?.GetPrefixOfNamespace(name.Namespace);
|
||||
return prefix != null ? $"{prefix}:{name.LocalName}" : name.LocalName;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ namespace Jackett.Common.Models.DTO
|
|||
public string imdbid { get; set; }
|
||||
public string ep { get; set; }
|
||||
public string t { get; set; }
|
||||
public string o { get; set; }
|
||||
public string extended { get; set; }
|
||||
public string limit { get; set; }
|
||||
public string offset { get; set; }
|
||||
|
|
|
@ -5,6 +5,8 @@ using System.Linq;
|
|||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Xml.Linq;
|
||||
using Jackett.Common.Helpers;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Jackett.Common.Models
|
||||
{
|
||||
|
@ -52,7 +54,7 @@ namespace Jackett.Common.Models
|
|||
return new XElement(_TorznabNs + "attr", new XAttribute("name", name), new XAttribute("value", value));
|
||||
}
|
||||
|
||||
public string ToXml(Uri selfAtom)
|
||||
private XDocument GetXDocument(Uri selfAtom)
|
||||
{
|
||||
// IMPORTANT: We can't use Uri.ToString(), because it generates URLs without URL encode (links with unicode
|
||||
// characters are broken). We must use Uri.AbsoluteUri instead that handles encoding correctly
|
||||
|
@ -127,7 +129,19 @@ namespace Jackett.Common.Models
|
|||
)
|
||||
);
|
||||
|
||||
return xdoc;
|
||||
}
|
||||
|
||||
public string ToXml(Uri selfAtom)
|
||||
{
|
||||
var xdoc = GetXDocument(selfAtom);
|
||||
return xdoc.Declaration + Environment.NewLine + xdoc;
|
||||
}
|
||||
|
||||
public string ToJson(Uri selfAtom, JsonSerializerSettings serializerSettings = null)
|
||||
{
|
||||
var jsonObject = XmlToJsonConverter.XmlToJson(GetXDocument(selfAtom).Root);
|
||||
return JsonConvert.SerializeObject(jsonObject, serializerSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Jackett.Common.Helpers;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Jackett.Common.Models
|
||||
{
|
||||
|
@ -352,6 +354,12 @@ namespace Jackett.Common.Models
|
|||
public string ToXml() =>
|
||||
GetXDocument().Declaration + Environment.NewLine + GetXDocument();
|
||||
|
||||
public string ToJson(JsonSerializerSettings serializerSettings = null)
|
||||
{
|
||||
var jsonObject = XmlToJsonConverter.XmlToJson(GetXDocument().Root);
|
||||
return JsonConvert.SerializeObject(jsonObject, serializerSettings);
|
||||
}
|
||||
|
||||
public static TorznabCapabilities Concat(TorznabCapabilities lhs, TorznabCapabilities rhs)
|
||||
{
|
||||
lhs.SearchAvailable = lhs.SearchAvailable || rhs.SearchAvailable;
|
||||
|
|
|
@ -48,6 +48,8 @@ namespace Jackett.Common.Models
|
|||
|
||||
public bool IsTest { get; set; }
|
||||
|
||||
public bool IsJson { get; set; }
|
||||
|
||||
public string ImdbIDShort => ImdbID?.TrimStart('t');
|
||||
|
||||
protected string[] QueryStringParts;
|
||||
|
|
|
@ -8,6 +8,7 @@ using System.Threading.Tasks;
|
|||
using System.Xml.Linq;
|
||||
using Jackett.Common;
|
||||
using Jackett.Common.Exceptions;
|
||||
using Jackett.Common.Helpers;
|
||||
using Jackett.Common.Indexers;
|
||||
using Jackett.Common.Indexers.Meta;
|
||||
using Jackett.Common.Models;
|
||||
|
@ -20,6 +21,9 @@ using Microsoft.AspNetCore.Mvc;
|
|||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
|
||||
namespace Jackett.Server.Controllers
|
||||
|
@ -175,6 +179,17 @@ namespace Jackett.Server.Controllers
|
|||
private readonly IServerService serverService;
|
||||
private readonly ICacheService cacheService;
|
||||
private readonly Common.Models.Config.ServerConfig serverConfig;
|
||||
private static readonly JsonSerializerSettings _JsonSerializerSettings = new JsonSerializerSettings
|
||||
{
|
||||
Converters = new List<JsonConverter>
|
||||
{
|
||||
new StringEnumConverter
|
||||
{
|
||||
NamingStrategy = new LowerCaseNamingStrategy()
|
||||
}
|
||||
},
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
};
|
||||
|
||||
public ResultsController(IIndexerManagerService indexerManagerService, IServerService ss, ICacheService c, Logger logger, Common.Models.Config.ServerConfig sConfig)
|
||||
{
|
||||
|
@ -339,9 +354,16 @@ namespace Jackett.Server.Controllers
|
|||
[HttpGet]
|
||||
public async Task<IActionResult> Torznab([FromQuery] TorznabRequest request)
|
||||
{
|
||||
if (string.Equals(request.o, "json", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
CurrentQuery.IsJson = true;
|
||||
}
|
||||
|
||||
if (string.Equals(CurrentQuery.QueryType, "caps", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return Content(CurrentIndexer.TorznabCaps.ToXml(), "application/rss+xml", Encoding.UTF8);
|
||||
return CurrentQuery.IsJson ?
|
||||
Content(CurrentIndexer.TorznabCaps.ToJson(_JsonSerializerSettings), "application/json", Encoding.UTF8) :
|
||||
Content(CurrentIndexer.TorznabCaps.ToXml(), "application/rss+xml", Encoding.UTF8);
|
||||
}
|
||||
|
||||
// indexers - returns a list of all included indexers (meta indexers only)
|
||||
|
@ -350,7 +372,7 @@ namespace Jackett.Server.Controllers
|
|||
if (!(CurrentIndexer is BaseMetaIndexer)) // shouldn't be needed because CanHandleQuery should return false
|
||||
{
|
||||
logger.Warn($"A search request with t=indexers from {Request.HttpContext.Connection.RemoteIpAddress} was made but the indexer {CurrentIndexer.Name} isn't a meta indexer.");
|
||||
return GetErrorXML(203, "Function Not Available: this isn't a meta indexer");
|
||||
return GetError(203, "Function Not Available: this isn't a meta indexer");
|
||||
}
|
||||
var CurrentBaseMetaIndexer = (BaseMetaIndexer)CurrentIndexer;
|
||||
var indexers = CurrentBaseMetaIndexer.Indexers;
|
||||
|
@ -376,6 +398,11 @@ namespace Jackett.Server.Controllers
|
|||
)
|
||||
);
|
||||
|
||||
if (CurrentQuery.IsJson)
|
||||
{
|
||||
return Json(XmlToJsonConverter.XmlToJson(xdoc.Root), _JsonSerializerSettings);
|
||||
}
|
||||
|
||||
return Content(xdoc.Declaration.ToString() + Environment.NewLine + xdoc.ToString(), "application/xml", Encoding.UTF8);
|
||||
}
|
||||
|
||||
|
@ -395,19 +422,19 @@ namespace Jackett.Server.Controllers
|
|||
if (CurrentQuery.ImdbID == null)
|
||||
{
|
||||
logger.Warn($"A search request from {Request.HttpContext.Connection.RemoteIpAddress} was made with an invalid imdbid.");
|
||||
return GetErrorXML(201, "Incorrect parameter: invalid imdbid format");
|
||||
return GetError(201, "Incorrect parameter: invalid imdbid format");
|
||||
}
|
||||
|
||||
if (CurrentQuery.IsMovieSearch && !CurrentIndexer.TorznabCaps.MovieSearchImdbAvailable)
|
||||
{
|
||||
logger.Warn($"A search request with imdbid from {Request.HttpContext.Connection.RemoteIpAddress} was made but the indexer {CurrentIndexer.Name} doesn't support it.");
|
||||
return GetErrorXML(203, "Function Not Available: imdbid is not supported for movie search by this indexer");
|
||||
return GetError(203, "Function Not Available: imdbid is not supported for movie search by this indexer");
|
||||
}
|
||||
|
||||
if (CurrentQuery.IsTVSearch && !CurrentIndexer.TorznabCaps.TvSearchImdbAvailable)
|
||||
{
|
||||
logger.Warn($"A search request with imdbid from {Request.HttpContext.Connection.RemoteIpAddress} was made but the indexer {CurrentIndexer.Name} doesn't support it.");
|
||||
return GetErrorXML(203, "Function Not Available: imdbid is not supported for TV search by this indexer");
|
||||
return GetError(203, "Function Not Available: imdbid is not supported for TV search by this indexer");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -416,13 +443,13 @@ namespace Jackett.Server.Controllers
|
|||
if (CurrentQuery.IsMovieSearch && !CurrentIndexer.TorznabCaps.MovieSearchTmdbAvailable)
|
||||
{
|
||||
logger.Warn($"A search request with tmdbid from {Request.HttpContext.Connection.RemoteIpAddress} was made but the indexer {CurrentIndexer.Name} doesn't support it.");
|
||||
return GetErrorXML(203, "Function Not Available: tmdbid is not supported for movie search by this indexer");
|
||||
return GetError(203, "Function Not Available: tmdbid is not supported for movie search by this indexer");
|
||||
}
|
||||
|
||||
if (CurrentQuery.IsTVSearch && !CurrentIndexer.TorznabCaps.TvSearchTmdbAvailable)
|
||||
{
|
||||
logger.Warn($"A search request with tmdbid from {Request.HttpContext.Connection.RemoteIpAddress} was made but the indexer {CurrentIndexer.Name} doesn't support it.");
|
||||
return GetErrorXML(203, "Function Not Available: tmdbid is not supported for TV search by this indexer");
|
||||
return GetError(203, "Function Not Available: tmdbid is not supported for TV search by this indexer");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -431,7 +458,7 @@ namespace Jackett.Server.Controllers
|
|||
if (CurrentQuery.IsTVSearch && !CurrentIndexer.TorznabCaps.TvSearchAvailable)
|
||||
{
|
||||
logger.Warn($"A search request with tvdbid from {Request.HttpContext.Connection.RemoteIpAddress} was made but the indexer {CurrentIndexer.Name} doesn't support it.");
|
||||
return GetErrorXML(203, "Function Not Available: tvdbid is not supported for movie search by this indexer");
|
||||
return GetError(203, "Function Not Available: tvdbid is not supported for movie search by this indexer");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -465,7 +492,14 @@ namespace Jackett.Server.Controllers
|
|||
else
|
||||
logger.Info($"Torznab search in {CurrentIndexer.Name} for {CurrentQuery.GetQueryString()} => Found {result.Releases.Count()} releases{cacheStr} [{stopwatch.ElapsedMilliseconds:0}ms]");
|
||||
|
||||
var xml = resultPage.ToXml(new Uri(serverUrl));
|
||||
var serverUri = new Uri(serverUrl);
|
||||
if (CurrentQuery.IsJson)
|
||||
{
|
||||
var json = resultPage.ToJson(serverUri);
|
||||
return Content(json, "application/json", Encoding.UTF8);
|
||||
}
|
||||
|
||||
var xml = resultPage.ToXml(serverUri);
|
||||
|
||||
// Force the return as XML
|
||||
return Content(xml, "application/rss+xml", Encoding.UTF8);
|
||||
|
@ -485,25 +519,29 @@ namespace Jackett.Server.Controllers
|
|||
}
|
||||
}
|
||||
|
||||
return GetErrorXML(900, ex.Message, StatusCodes.Status429TooManyRequests);
|
||||
return GetError(900, ex.Message, StatusCodes.Status429TooManyRequests);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error(e);
|
||||
return GetErrorXML(900, e.ToString());
|
||||
return GetError(900, e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
[Route("[action]/{ignored?}")]
|
||||
public IActionResult GetErrorXML(int code, string description, int statusCode = StatusCodes.Status400BadRequest)
|
||||
public IActionResult GetError(int code, string description, int statusCode = StatusCodes.Status400BadRequest)
|
||||
{
|
||||
var mediaTypeHeaderValue = MediaTypeHeaderValue.Parse("application/xml");
|
||||
var mediaTypeHeaderValue = CurrentQuery.IsJson ?
|
||||
MediaTypeHeaderValue.Parse("application/json") :
|
||||
MediaTypeHeaderValue.Parse("application/xml");
|
||||
mediaTypeHeaderValue.Encoding = Encoding.UTF8;
|
||||
|
||||
return new ContentResult
|
||||
{
|
||||
StatusCode = statusCode,
|
||||
Content = CreateErrorXML(code, description),
|
||||
Content = CurrentQuery.IsJson ?
|
||||
CreateErrorJson(code, description) :
|
||||
CreateErrorXML(code, description),
|
||||
ContentType = mediaTypeHeaderValue.ToString()
|
||||
};
|
||||
}
|
||||
|
@ -520,6 +558,19 @@ namespace Jackett.Server.Controllers
|
|||
return xdoc.Declaration + Environment.NewLine + xdoc;
|
||||
}
|
||||
|
||||
public static string CreateErrorJson(int code, string description)
|
||||
{
|
||||
return new JObject
|
||||
{
|
||||
{ "error", new JObject
|
||||
{
|
||||
{ "code", code },
|
||||
{ "description", description }
|
||||
}
|
||||
}
|
||||
}.ToString();
|
||||
}
|
||||
|
||||
public static IActionResult GetErrorActionResult(RouteData routeData, HttpStatusCode status, int torznabCode, string description)
|
||||
{
|
||||
var isTorznab = routeData.Values["action"].ToString().Equals("torznab", StringComparison.OrdinalIgnoreCase);
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
using System.Xml.Linq;
|
||||
using Jackett.Common.Helpers;
|
||||
using Newtonsoft.Json;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Jackett.Test.Common.Helpers
|
||||
{
|
||||
[TestFixture]
|
||||
public class XmlToJsonConverterTests
|
||||
{
|
||||
[Test]
|
||||
public void XmlToJsonConverter_XmlToJson_Empty()
|
||||
{
|
||||
var element = new XElement("test");
|
||||
var json = XmlToJsonConverter.XmlToJson(element);
|
||||
Assert.AreEqual("{}", json.ToString(Formatting.None));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void XmlToJsonConverter_XmlToJson_WithAttributes()
|
||||
{
|
||||
var element = new XElement("test", new XAttribute("attr1", "value1"), new XAttribute("attr2", "value2"));
|
||||
var json = XmlToJsonConverter.XmlToJson(element);
|
||||
Assert.AreEqual("{\"@attributes\":{\"attr1\":\"value1\",\"attr2\":\"value2\"}}", json.ToString(Formatting.None));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void XmlToJsonConverter_XmlToJson_WithChildElement()
|
||||
{
|
||||
var element = new XElement("test", new XElement("child"));
|
||||
var json = XmlToJsonConverter.XmlToJson(element);
|
||||
Assert.AreEqual("{\"child\":{}}", json.ToString(Formatting.None));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void XmlToJsonConverter_XmlToJson_WithChildElement_WithAttributes()
|
||||
{
|
||||
var element = new XElement("test", new XElement("child", new XAttribute("attr1", "value1"), new XAttribute("attr2", "value2")));
|
||||
var json = XmlToJsonConverter.XmlToJson(element);
|
||||
Assert.AreEqual("{\"child\":{\"@attributes\":{\"attr1\":\"value1\",\"attr2\":\"value2\"}}}", json.ToString(Formatting.None));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void XmlToJsonConverter_XmlToJson_WithChildElement_WithText()
|
||||
{
|
||||
var element = new XElement("test", new XElement("child", new XElement("subchild", "text")));
|
||||
var json = XmlToJsonConverter.XmlToJson(element);
|
||||
Assert.AreEqual("{\"child\":{\"subchild\":\"text\"}}", json.ToString(Formatting.None));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void XmlToJsonConverter_XmlToJson_WithChildElementArray()
|
||||
{
|
||||
var element = new XElement("test", new XElement("child"), new XElement("child"));
|
||||
var json = XmlToJsonConverter.XmlToJson(element);
|
||||
Assert.AreEqual("{\"child\":[{},{}]}", json.ToString(Formatting.None));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void XmlToJsonConverter_XmlToJson_WithChildElementArray_WithText()
|
||||
{
|
||||
var element = new XElement("test", new XElement("child", "text1"), new XElement("child", "text2"));
|
||||
var json = XmlToJsonConverter.XmlToJson(element);
|
||||
Assert.AreEqual("{\"child\":[\"text1\",\"text2\"]}", json.ToString(Formatting.None));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void XmlToJsonConverter_XmlToJson_HandlesNamespaces()
|
||||
{
|
||||
var document = new XDocument(
|
||||
new XElement("root",
|
||||
new XAttribute(XNamespace.Xmlns + "ns1", "http://example.com/ns1"),
|
||||
new XAttribute(XNamespace.Xmlns + "ns2", "http://example.com/ns2"),
|
||||
new XElement("{http://example.com/ns1}child1"),
|
||||
new XElement("{http://example.com/ns2}child2")
|
||||
)
|
||||
);
|
||||
|
||||
var json = XmlToJsonConverter.XmlToJson(document.Root);
|
||||
Assert.AreEqual("{\"@attributes\":{\"xmlns:ns1\":\"http://example.com/ns1\",\"xmlns:ns2\":\"http://example.com/ns2\"},\"ns1:child1\":{},\"ns2:child2\":{}}", json.ToString(Formatting.None));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue