Compare commits

...

21 Commits

Author SHA1 Message Date
Boris Gerretzen 33a2bf6062
Merge 8d3dfd43d4 into fadff9584d 2024-04-27 02:49:01 +01:00
Garfield69 fadff9584d Update capybarabr.yml 2024-04-27 13:33:25 +12:00
Garfield69 b4b337ac90 bigfangroup: drop referer and fix keywordless resolves #6275 2024-04-27 13:21:37 +12:00
Garfield69 4db2fe5da1 capybarabr: default single_file_release_use_filename to false #15278 2024-04-27 13:20:21 +12:00
ilike2burnthing 84d2b5f1d1
krazyzone: remove old cert exception 2024-04-26 23:57:10 +01:00
ilike2burnthing b8dc1f2ca3
frozenlayer: remove old cert exception 2024-04-26 23:57:06 +01:00
Cedric b92d15d9a2
actions: fix potential github action smells (#15274)
Co-authored-by: ilike2burnthing <59480337+ilike2burnthing@users.noreply.github.com>
2024-04-26 23:57:00 +01:00
Garfield69 6cf2285abe capybarabr: remove single_file_release_use_filename support. resolves #15278 2024-04-27 06:17:20 +12:00
Garfield69 8da3684a19 oldtoonsworld: -> 8.0.2 2024-04-27 06:16:19 +12:00
Garfield69 e5e0f1d2b0 rudub: bump domain 2024-04-27 05:44:30 +12:00
Garfield69 a22fed3e32 marinetracker: new cats 2024-04-27 05:44:14 +12:00
Garfield69 fc8af644e2 fix dbb16a3deb 2024-04-26 17:30:42 +12:00
Garfield69 dbb16a3deb fix 9faf972410 2024-04-26 17:29:34 +12:00
Garfield69 9faf972410 assorted unit3d v8.0.2: tidyup 2024-04-26 17:16:39 +12:00
Garfield69 d9fdf31452 lilleskyorg: all the previous cats are back 2024-04-26 16:49:40 +12:00
Boris 8d3dfd43d4 Redid xml to json conversion 2024-03-10 22:36:17 +01:00
Boris Gerretzen 4eaacaeb94
Merge branch 'Jackett:master' into master 2024-03-10 22:09:13 +01:00
Bogdan 86f5e5abce
Merge branch 'master' into master 2024-02-08 20:56:00 +02:00
Boris e4911054e3 Better formatting of caps as json 2024-02-08 18:48:02 +01:00
Boris 533a25da54 Fix linter error 2024-02-03 20:42:30 +01:00
Boris 23b62c2fa6 [enhancement]: support Torznab o=JSON 2024-02-03 20:33:09 +01:00
39 changed files with 505 additions and 251 deletions

View File

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

View File

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

View File

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

View File

@ -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 }}"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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"}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,9 @@
using Newtonsoft.Json.Serialization;
namespace Jackett.Common.Helpers
{
public class LowerCaseNamingStrategy : NamingStrategy
{
protected override string ResolvePropertyName(string name) => name.ToLowerInvariant();
}
}

View File

@ -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;
}
}
}

View File

@ -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; }

View File

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

View File

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

View File

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

View File

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

View File

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