quasarr 1.19.0__py3-none-any.whl → 1.20.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of quasarr might be problematic. Click here for more details.
- quasarr/api/captcha/__init__.py +157 -16
- quasarr/downloads/__init__.py +6 -0
- quasarr/downloads/sources/dj.py +7 -0
- quasarr/downloads/sources/sj.py +7 -0
- quasarr/providers/html_images.py +2 -0
- quasarr/providers/html_templates.py +1 -1
- quasarr/providers/obfuscated.py +18 -1
- quasarr/providers/version.py +1 -1
- quasarr/search/__init__.py +8 -0
- quasarr/search/sources/dj.py +213 -0
- quasarr/search/sources/sj.py +213 -0
- quasarr/storage/config.py +2 -0
- {quasarr-1.19.0.dist-info → quasarr-1.20.0.dist-info}/METADATA +1 -1
- {quasarr-1.19.0.dist-info → quasarr-1.20.0.dist-info}/RECORD +18 -14
- {quasarr-1.19.0.dist-info → quasarr-1.20.0.dist-info}/WHEEL +0 -0
- {quasarr-1.19.0.dist-info → quasarr-1.20.0.dist-info}/entry_points.txt +0 -0
- {quasarr-1.19.0.dist-info → quasarr-1.20.0.dist-info}/licenses/LICENSE +0 -0
- {quasarr-1.19.0.dist-info → quasarr-1.20.0.dist-info}/top_level.txt +0 -0
quasarr/search/__init__.py
CHANGED
|
@@ -9,6 +9,7 @@ from quasarr.providers.log import info, debug
|
|
|
9
9
|
from quasarr.search.sources.al import al_feed, al_search
|
|
10
10
|
from quasarr.search.sources.by import by_feed, by_search
|
|
11
11
|
from quasarr.search.sources.dd import dd_search, dd_feed
|
|
12
|
+
from quasarr.search.sources.dj import dj_search, dj_feed
|
|
12
13
|
from quasarr.search.sources.dt import dt_feed, dt_search
|
|
13
14
|
from quasarr.search.sources.dw import dw_feed, dw_search
|
|
14
15
|
from quasarr.search.sources.fx import fx_feed, fx_search
|
|
@@ -17,6 +18,7 @@ from quasarr.search.sources.mb import mb_feed, mb_search
|
|
|
17
18
|
from quasarr.search.sources.nk import nk_feed, nk_search
|
|
18
19
|
from quasarr.search.sources.nx import nx_feed, nx_search
|
|
19
20
|
from quasarr.search.sources.sf import sf_feed, sf_search
|
|
21
|
+
from quasarr.search.sources.sj import sj_search, sj_feed
|
|
20
22
|
from quasarr.search.sources.sl import sl_feed, sl_search
|
|
21
23
|
from quasarr.search.sources.wd import wd_feed, wd_search
|
|
22
24
|
|
|
@@ -33,6 +35,7 @@ def get_search_results(shared_state, request_from, imdb_id="", search_phrase="",
|
|
|
33
35
|
by = shared_state.values["config"]("Hostnames").get("by")
|
|
34
36
|
dd = shared_state.values["config"]("Hostnames").get("dd")
|
|
35
37
|
dt = shared_state.values["config"]("Hostnames").get("dt")
|
|
38
|
+
dj = shared_state.values["config"]("Hostnames").get("dj")
|
|
36
39
|
dw = shared_state.values["config"]("Hostnames").get("dw")
|
|
37
40
|
fx = shared_state.values["config"]("Hostnames").get("fx")
|
|
38
41
|
he = shared_state.values["config"]("Hostnames").get("he")
|
|
@@ -40,6 +43,7 @@ def get_search_results(shared_state, request_from, imdb_id="", search_phrase="",
|
|
|
40
43
|
nk = shared_state.values["config"]("Hostnames").get("nk")
|
|
41
44
|
nx = shared_state.values["config"]("Hostnames").get("nx")
|
|
42
45
|
sf = shared_state.values["config"]("Hostnames").get("sf")
|
|
46
|
+
sj = shared_state.values["config"]("Hostnames").get("sj")
|
|
43
47
|
sl = shared_state.values["config"]("Hostnames").get("sl")
|
|
44
48
|
wd = shared_state.values["config"]("Hostnames").get("wd")
|
|
45
49
|
|
|
@@ -53,6 +57,7 @@ def get_search_results(shared_state, request_from, imdb_id="", search_phrase="",
|
|
|
53
57
|
(by, by_search),
|
|
54
58
|
(dd, dd_search),
|
|
55
59
|
(dt, dt_search),
|
|
60
|
+
(dj, dj_search),
|
|
56
61
|
(dw, dw_search),
|
|
57
62
|
(fx, fx_search),
|
|
58
63
|
(he, he_search),
|
|
@@ -60,6 +65,7 @@ def get_search_results(shared_state, request_from, imdb_id="", search_phrase="",
|
|
|
60
65
|
(nk, nk_search),
|
|
61
66
|
(nx, nx_search),
|
|
62
67
|
(sf, sf_search),
|
|
68
|
+
(sj, sj_search),
|
|
63
69
|
(sl, sl_search),
|
|
64
70
|
(wd, wd_search),
|
|
65
71
|
]
|
|
@@ -78,6 +84,7 @@ def get_search_results(shared_state, request_from, imdb_id="", search_phrase="",
|
|
|
78
84
|
(al, al_feed),
|
|
79
85
|
(by, by_feed),
|
|
80
86
|
(dd, dd_feed),
|
|
87
|
+
(dj, dj_feed),
|
|
81
88
|
(dt, dt_feed),
|
|
82
89
|
(dw, dw_feed),
|
|
83
90
|
(fx, fx_feed),
|
|
@@ -86,6 +93,7 @@ def get_search_results(shared_state, request_from, imdb_id="", search_phrase="",
|
|
|
86
93
|
(nk, nk_feed),
|
|
87
94
|
(nx, nx_feed),
|
|
88
95
|
(sf, sf_feed),
|
|
96
|
+
(sj, sj_feed),
|
|
89
97
|
(sl, sl_feed),
|
|
90
98
|
(wd, wd_feed),
|
|
91
99
|
]
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Quasarr
|
|
3
|
+
# Project by https://github.com/rix1337
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import re
|
|
7
|
+
import time
|
|
8
|
+
from base64 import urlsafe_b64encode
|
|
9
|
+
from datetime import datetime, timedelta
|
|
10
|
+
|
|
11
|
+
import requests
|
|
12
|
+
from bs4 import BeautifulSoup
|
|
13
|
+
|
|
14
|
+
from quasarr.providers.imdb_metadata import get_localized_title
|
|
15
|
+
from quasarr.providers.log import info, debug
|
|
16
|
+
|
|
17
|
+
hostname = "dj"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def convert_to_rss_date(date_str):
|
|
21
|
+
try:
|
|
22
|
+
return datetime.fromisoformat(
|
|
23
|
+
date_str.replace("Z", "+00:00")
|
|
24
|
+
).strftime("%a, %d %b %Y %H:%M:%S +0000")
|
|
25
|
+
except Exception:
|
|
26
|
+
return ""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def dj_feed(shared_state, start_time, request_from, mirror=None):
|
|
30
|
+
releases = []
|
|
31
|
+
|
|
32
|
+
if "sonarr" not in request_from.lower():
|
|
33
|
+
debug(f'Skipping {request_from} search on "{hostname.upper()}" (unsupported media type)!')
|
|
34
|
+
return releases
|
|
35
|
+
|
|
36
|
+
sj_host = shared_state.values["config"]("Hostnames").get(hostname)
|
|
37
|
+
password = sj_host
|
|
38
|
+
|
|
39
|
+
url = f"https://{sj_host}/api/releases/latest/0"
|
|
40
|
+
headers = {"User-Agent": shared_state.values["user_agent"]}
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
r = requests.get(url, headers=headers, timeout=10)
|
|
44
|
+
data = json.loads(r.content)
|
|
45
|
+
except Exception as e:
|
|
46
|
+
info(f"{hostname.upper()}: feed load error: {e}")
|
|
47
|
+
return releases
|
|
48
|
+
|
|
49
|
+
for release in data:
|
|
50
|
+
try:
|
|
51
|
+
title = release.get("name").rstrip(".")
|
|
52
|
+
if not title:
|
|
53
|
+
continue
|
|
54
|
+
|
|
55
|
+
published = convert_to_rss_date(release.get("createdAt"))
|
|
56
|
+
if not published:
|
|
57
|
+
continue
|
|
58
|
+
|
|
59
|
+
media = release.get("_media", {})
|
|
60
|
+
slug = media.get("slug")
|
|
61
|
+
if not slug:
|
|
62
|
+
continue
|
|
63
|
+
|
|
64
|
+
series_url = f"https://{sj_host}/serie/{slug}"
|
|
65
|
+
|
|
66
|
+
mb = 0
|
|
67
|
+
size = 0
|
|
68
|
+
imdb_id = None
|
|
69
|
+
|
|
70
|
+
payload = urlsafe_b64encode(
|
|
71
|
+
f"{title}|{series_url}|{mirror}|{mb}|{password}|{imdb_id}".encode("utf-8")
|
|
72
|
+
).decode("utf-8")
|
|
73
|
+
|
|
74
|
+
link = f"{shared_state.values['internal_address']}/download/?payload={payload}"
|
|
75
|
+
|
|
76
|
+
releases.append({
|
|
77
|
+
"details": {
|
|
78
|
+
"title": title,
|
|
79
|
+
"hostname": hostname,
|
|
80
|
+
"imdb_id": imdb_id,
|
|
81
|
+
"link": link,
|
|
82
|
+
"mirror": mirror,
|
|
83
|
+
"size": size,
|
|
84
|
+
"date": published,
|
|
85
|
+
"source": series_url
|
|
86
|
+
},
|
|
87
|
+
"type": "protected"
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
except Exception as e:
|
|
91
|
+
debug(f"{hostname.upper()}: feed parse error: {e}")
|
|
92
|
+
continue
|
|
93
|
+
|
|
94
|
+
debug(f"Time taken: {time.time() - start_time:.2f}s ({hostname})")
|
|
95
|
+
return releases
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def dj_search(shared_state, start_time, request_from, search_string, mirror=None, season=None, episode=None):
|
|
99
|
+
releases = []
|
|
100
|
+
|
|
101
|
+
if "sonarr" not in request_from.lower():
|
|
102
|
+
debug(f'Skipping {request_from} search on "{hostname.upper()}" (unsupported media type)!')
|
|
103
|
+
return releases
|
|
104
|
+
|
|
105
|
+
sj_host = shared_state.values["config"]("Hostnames").get(hostname)
|
|
106
|
+
password = sj_host
|
|
107
|
+
|
|
108
|
+
imdb_id = shared_state.is_imdb_id(search_string)
|
|
109
|
+
if not imdb_id:
|
|
110
|
+
return releases
|
|
111
|
+
|
|
112
|
+
localized_title = get_localized_title(shared_state, imdb_id, "de")
|
|
113
|
+
if not localized_title:
|
|
114
|
+
info(f"{hostname.upper()}: no localized title for IMDb {imdb_id}")
|
|
115
|
+
return releases
|
|
116
|
+
|
|
117
|
+
headers = {"User-Agent": shared_state.values["user_agent"]}
|
|
118
|
+
search_url = f"https://{sj_host}/serie/search"
|
|
119
|
+
params = {"q": localized_title}
|
|
120
|
+
|
|
121
|
+
try:
|
|
122
|
+
r = requests.get(search_url, headers=headers, params=params, timeout=10)
|
|
123
|
+
soup = BeautifulSoup(r.content, "html.parser")
|
|
124
|
+
results = soup.find_all("a", href=re.compile(r"^/serie/"))
|
|
125
|
+
except Exception as e:
|
|
126
|
+
info(f"{hostname.upper()}: search load error: {e}")
|
|
127
|
+
return releases
|
|
128
|
+
|
|
129
|
+
one_hour_ago = (datetime.now() - timedelta(hours=1)).strftime('%Y-%m-%d %H:%M:%S')
|
|
130
|
+
sanitized_search_string = shared_state.sanitize_string(localized_title)
|
|
131
|
+
|
|
132
|
+
for result in results:
|
|
133
|
+
try:
|
|
134
|
+
result_title = result.get_text(strip=True)
|
|
135
|
+
|
|
136
|
+
sanitized_title = shared_state.sanitize_string(result_title)
|
|
137
|
+
|
|
138
|
+
if not re.search(
|
|
139
|
+
rf"\b{re.escape(sanitized_search_string)}\b",
|
|
140
|
+
sanitized_title
|
|
141
|
+
):
|
|
142
|
+
debug(
|
|
143
|
+
f"Search string '{localized_title}' doesn't match '{result_title}'"
|
|
144
|
+
)
|
|
145
|
+
continue
|
|
146
|
+
|
|
147
|
+
debug(
|
|
148
|
+
f"Matched search string '{localized_title}' with result '{result_title}'"
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
series_url = f"https://{sj_host}{result['href']}"
|
|
152
|
+
|
|
153
|
+
r = requests.get(series_url, headers=headers, timeout=10)
|
|
154
|
+
media_id_match = re.search(r'data-mediaid="([^"]+)"', r.text)
|
|
155
|
+
if not media_id_match:
|
|
156
|
+
debug(f"{hostname.upper()}: no media id for {result_title}")
|
|
157
|
+
continue
|
|
158
|
+
|
|
159
|
+
media_id = media_id_match.group(1)
|
|
160
|
+
api_url = f"https://{sj_host}/api/media/{media_id}/releases"
|
|
161
|
+
|
|
162
|
+
r = requests.get(api_url, headers=headers, timeout=10)
|
|
163
|
+
data = json.loads(r.content)
|
|
164
|
+
|
|
165
|
+
for season_block in data.values():
|
|
166
|
+
for item in season_block.get("items", []):
|
|
167
|
+
title = item.get("name").rstrip(".")
|
|
168
|
+
if not title:
|
|
169
|
+
continue
|
|
170
|
+
|
|
171
|
+
if not shared_state.is_valid_release(
|
|
172
|
+
title,
|
|
173
|
+
request_from,
|
|
174
|
+
search_string,
|
|
175
|
+
season,
|
|
176
|
+
episode
|
|
177
|
+
):
|
|
178
|
+
continue
|
|
179
|
+
|
|
180
|
+
published = convert_to_rss_date(item.get("createdAt"))
|
|
181
|
+
if not published:
|
|
182
|
+
debug(f"{hostname.upper()}: no published date for {title}")
|
|
183
|
+
published = one_hour_ago
|
|
184
|
+
|
|
185
|
+
mb = 0
|
|
186
|
+
size = 0
|
|
187
|
+
|
|
188
|
+
payload = urlsafe_b64encode(
|
|
189
|
+
f"{title}|{series_url}|{mirror}|{mb}|{password}|{imdb_id}".encode("utf-8")
|
|
190
|
+
).decode("utf-8")
|
|
191
|
+
|
|
192
|
+
link = f"{shared_state.values['internal_address']}/download/?payload={payload}"
|
|
193
|
+
|
|
194
|
+
releases.append({
|
|
195
|
+
"details": {
|
|
196
|
+
"title": title,
|
|
197
|
+
"hostname": hostname,
|
|
198
|
+
"imdb_id": imdb_id,
|
|
199
|
+
"link": link,
|
|
200
|
+
"mirror": mirror,
|
|
201
|
+
"size": size,
|
|
202
|
+
"date": published,
|
|
203
|
+
"source": series_url
|
|
204
|
+
},
|
|
205
|
+
"type": "protected"
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
except Exception as e:
|
|
209
|
+
debug(f"{hostname.upper()}: search parse error: {e}")
|
|
210
|
+
continue
|
|
211
|
+
|
|
212
|
+
debug(f"Time taken: {time.time() - start_time:.2f}s ({hostname})")
|
|
213
|
+
return releases
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Quasarr
|
|
3
|
+
# Project by https://github.com/rix1337
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import re
|
|
7
|
+
import time
|
|
8
|
+
from base64 import urlsafe_b64encode
|
|
9
|
+
from datetime import datetime, timedelta
|
|
10
|
+
|
|
11
|
+
import requests
|
|
12
|
+
from bs4 import BeautifulSoup
|
|
13
|
+
|
|
14
|
+
from quasarr.providers.imdb_metadata import get_localized_title
|
|
15
|
+
from quasarr.providers.log import info, debug
|
|
16
|
+
|
|
17
|
+
hostname = "sj"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def convert_to_rss_date(date_str):
|
|
21
|
+
try:
|
|
22
|
+
return datetime.fromisoformat(
|
|
23
|
+
date_str.replace("Z", "+00:00")
|
|
24
|
+
).strftime("%a, %d %b %Y %H:%M:%S +0000")
|
|
25
|
+
except Exception:
|
|
26
|
+
return ""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def sj_feed(shared_state, start_time, request_from, mirror=None):
|
|
30
|
+
releases = []
|
|
31
|
+
|
|
32
|
+
if "sonarr" not in request_from.lower():
|
|
33
|
+
debug(f'Skipping {request_from} search on "{hostname.upper()}" (unsupported media type)!')
|
|
34
|
+
return releases
|
|
35
|
+
|
|
36
|
+
sj_host = shared_state.values["config"]("Hostnames").get(hostname)
|
|
37
|
+
password = sj_host
|
|
38
|
+
|
|
39
|
+
url = f"https://{sj_host}/api/releases/latest/0"
|
|
40
|
+
headers = {"User-Agent": shared_state.values["user_agent"]}
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
r = requests.get(url, headers=headers, timeout=10)
|
|
44
|
+
data = json.loads(r.content)
|
|
45
|
+
except Exception as e:
|
|
46
|
+
info(f"{hostname.upper()}: feed load error: {e}")
|
|
47
|
+
return releases
|
|
48
|
+
|
|
49
|
+
for release in data:
|
|
50
|
+
try:
|
|
51
|
+
title = release.get("name").rstrip(".")
|
|
52
|
+
if not title:
|
|
53
|
+
continue
|
|
54
|
+
|
|
55
|
+
published = convert_to_rss_date(release.get("createdAt"))
|
|
56
|
+
if not published:
|
|
57
|
+
continue
|
|
58
|
+
|
|
59
|
+
media = release.get("_media", {})
|
|
60
|
+
slug = media.get("slug")
|
|
61
|
+
if not slug:
|
|
62
|
+
continue
|
|
63
|
+
|
|
64
|
+
series_url = f"https://{sj_host}/serie/{slug}"
|
|
65
|
+
|
|
66
|
+
mb = 0
|
|
67
|
+
size = 0
|
|
68
|
+
imdb_id = None
|
|
69
|
+
|
|
70
|
+
payload = urlsafe_b64encode(
|
|
71
|
+
f"{title}|{series_url}|{mirror}|{mb}|{password}|{imdb_id}".encode("utf-8")
|
|
72
|
+
).decode("utf-8")
|
|
73
|
+
|
|
74
|
+
link = f"{shared_state.values['internal_address']}/download/?payload={payload}"
|
|
75
|
+
|
|
76
|
+
releases.append({
|
|
77
|
+
"details": {
|
|
78
|
+
"title": title,
|
|
79
|
+
"hostname": hostname,
|
|
80
|
+
"imdb_id": imdb_id,
|
|
81
|
+
"link": link,
|
|
82
|
+
"mirror": mirror,
|
|
83
|
+
"size": size,
|
|
84
|
+
"date": published,
|
|
85
|
+
"source": series_url
|
|
86
|
+
},
|
|
87
|
+
"type": "protected"
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
except Exception as e:
|
|
91
|
+
debug(f"{hostname.upper()}: feed parse error: {e}")
|
|
92
|
+
continue
|
|
93
|
+
|
|
94
|
+
debug(f"Time taken: {time.time() - start_time:.2f}s ({hostname})")
|
|
95
|
+
return releases
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def sj_search(shared_state, start_time, request_from, search_string, mirror=None, season=None, episode=None):
|
|
99
|
+
releases = []
|
|
100
|
+
|
|
101
|
+
if "sonarr" not in request_from.lower():
|
|
102
|
+
debug(f'Skipping {request_from} search on "{hostname.upper()}" (unsupported media type)!')
|
|
103
|
+
return releases
|
|
104
|
+
|
|
105
|
+
sj_host = shared_state.values["config"]("Hostnames").get(hostname)
|
|
106
|
+
password = sj_host
|
|
107
|
+
|
|
108
|
+
imdb_id = shared_state.is_imdb_id(search_string)
|
|
109
|
+
if not imdb_id:
|
|
110
|
+
return releases
|
|
111
|
+
|
|
112
|
+
localized_title = get_localized_title(shared_state, imdb_id, "de")
|
|
113
|
+
if not localized_title:
|
|
114
|
+
info(f"{hostname.upper()}: no localized title for IMDb {imdb_id}")
|
|
115
|
+
return releases
|
|
116
|
+
|
|
117
|
+
headers = {"User-Agent": shared_state.values["user_agent"]}
|
|
118
|
+
search_url = f"https://{sj_host}/serie/search"
|
|
119
|
+
params = {"q": localized_title}
|
|
120
|
+
|
|
121
|
+
try:
|
|
122
|
+
r = requests.get(search_url, headers=headers, params=params, timeout=10)
|
|
123
|
+
soup = BeautifulSoup(r.content, "html.parser")
|
|
124
|
+
results = soup.find_all("a", href=re.compile(r"^/serie/"))
|
|
125
|
+
except Exception as e:
|
|
126
|
+
info(f"{hostname.upper()}: search load error: {e}")
|
|
127
|
+
return releases
|
|
128
|
+
|
|
129
|
+
one_hour_ago = (datetime.now() - timedelta(hours=1)).strftime('%Y-%m-%d %H:%M:%S')
|
|
130
|
+
sanitized_search_string = shared_state.sanitize_string(localized_title)
|
|
131
|
+
|
|
132
|
+
for result in results:
|
|
133
|
+
try:
|
|
134
|
+
result_title = result.get_text(strip=True)
|
|
135
|
+
|
|
136
|
+
sanitized_title = shared_state.sanitize_string(result_title)
|
|
137
|
+
|
|
138
|
+
if not re.search(
|
|
139
|
+
rf"\b{re.escape(sanitized_search_string)}\b",
|
|
140
|
+
sanitized_title
|
|
141
|
+
):
|
|
142
|
+
debug(
|
|
143
|
+
f"Search string '{localized_title}' doesn't match '{result_title}'"
|
|
144
|
+
)
|
|
145
|
+
continue
|
|
146
|
+
|
|
147
|
+
debug(
|
|
148
|
+
f"Matched search string '{localized_title}' with result '{result_title}'"
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
series_url = f"https://{sj_host}{result['href']}"
|
|
152
|
+
|
|
153
|
+
r = requests.get(series_url, headers=headers, timeout=10)
|
|
154
|
+
media_id_match = re.search(r'data-mediaid="([^"]+)"', r.text)
|
|
155
|
+
if not media_id_match:
|
|
156
|
+
debug(f"{hostname.upper()}: no media id for {result_title}")
|
|
157
|
+
continue
|
|
158
|
+
|
|
159
|
+
media_id = media_id_match.group(1)
|
|
160
|
+
api_url = f"https://{sj_host}/api/media/{media_id}/releases"
|
|
161
|
+
|
|
162
|
+
r = requests.get(api_url, headers=headers, timeout=10)
|
|
163
|
+
data = json.loads(r.content)
|
|
164
|
+
|
|
165
|
+
for season_block in data.values():
|
|
166
|
+
for item in season_block.get("items", []):
|
|
167
|
+
title = item.get("name").rstrip(".")
|
|
168
|
+
if not title:
|
|
169
|
+
continue
|
|
170
|
+
|
|
171
|
+
if not shared_state.is_valid_release(
|
|
172
|
+
title,
|
|
173
|
+
request_from,
|
|
174
|
+
search_string,
|
|
175
|
+
season,
|
|
176
|
+
episode
|
|
177
|
+
):
|
|
178
|
+
continue
|
|
179
|
+
|
|
180
|
+
published = convert_to_rss_date(item.get("createdAt"))
|
|
181
|
+
if not published:
|
|
182
|
+
debug(f"{hostname.upper()}: no published date for {title}")
|
|
183
|
+
published = one_hour_ago
|
|
184
|
+
|
|
185
|
+
mb = 0
|
|
186
|
+
size = 0
|
|
187
|
+
|
|
188
|
+
payload = urlsafe_b64encode(
|
|
189
|
+
f"{title}|{series_url}|{mirror}|{mb}|{password}|{imdb_id}".encode("utf-8")
|
|
190
|
+
).decode("utf-8")
|
|
191
|
+
|
|
192
|
+
link = f"{shared_state.values['internal_address']}/download/?payload={payload}"
|
|
193
|
+
|
|
194
|
+
releases.append({
|
|
195
|
+
"details": {
|
|
196
|
+
"title": title,
|
|
197
|
+
"hostname": hostname,
|
|
198
|
+
"imdb_id": imdb_id,
|
|
199
|
+
"link": link,
|
|
200
|
+
"mirror": mirror,
|
|
201
|
+
"size": size,
|
|
202
|
+
"date": published,
|
|
203
|
+
"source": series_url
|
|
204
|
+
},
|
|
205
|
+
"type": "protected"
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
except Exception as e:
|
|
209
|
+
debug(f"{hostname.upper()}: search parse error: {e}")
|
|
210
|
+
continue
|
|
211
|
+
|
|
212
|
+
debug(f"Time taken: {time.time() - start_time:.2f}s ({hostname})")
|
|
213
|
+
return releases
|
quasarr/storage/config.py
CHANGED
|
@@ -29,6 +29,7 @@ class Config(object):
|
|
|
29
29
|
("al", "secret", ""),
|
|
30
30
|
("by", "secret", ""),
|
|
31
31
|
("dd", "secret", ""),
|
|
32
|
+
("dj", "secret", ""),
|
|
32
33
|
("dt", "secret", ""),
|
|
33
34
|
("dw", "secret", ""),
|
|
34
35
|
("fx", "secret", ""),
|
|
@@ -37,6 +38,7 @@ class Config(object):
|
|
|
37
38
|
("nk", "secret", ""),
|
|
38
39
|
("nx", "secret", ""),
|
|
39
40
|
("sf", "secret", ""),
|
|
41
|
+
("sj", "secret", ""),
|
|
40
42
|
("sl", "secret", ""),
|
|
41
43
|
("wd", "secret", "")
|
|
42
44
|
],
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
quasarr/__init__.py,sha256=_WoDFvqXXilQynsiPrY-SXyADy1OwhAjQkdaJFqqHo0,17873
|
|
2
2
|
quasarr/api/__init__.py,sha256=9Y_DTNYsHeimrXL3mAli8OUg0zqo7QGLF2ft40d3R-c,6822
|
|
3
3
|
quasarr/api/arr/__init__.py,sha256=HrzyavxsCmQkdV2SMqQSoJq3KgrsPBnQJdo5iyovmG8,16626
|
|
4
|
-
quasarr/api/captcha/__init__.py,sha256=
|
|
4
|
+
quasarr/api/captcha/__init__.py,sha256=GSxwqS-Hle3B_RkJa4iXueRHw5MlaniXyexsMt0lOX4,49501
|
|
5
5
|
quasarr/api/config/__init__.py,sha256=0K7zqC9dt39Ul1RIJt0zNVdh1b9ARnfC6QFPa2D9FCw,819
|
|
6
6
|
quasarr/api/sponsors_helper/__init__.py,sha256=kAZabPlplPYRG6Uw7ZHTk5uypualwvhs-NoTOjQhhhA,6369
|
|
7
7
|
quasarr/api/statistics/__init__.py,sha256=NrBAjjHkIUE95HhPUGIfNqh2IqBqJ_zm00S90Y-Qnus,7038
|
|
8
|
-
quasarr/downloads/__init__.py,sha256=
|
|
8
|
+
quasarr/downloads/__init__.py,sha256=2jveOXh165lb-W1CesdS_CVDlrtDV66Gx11OMGTHPXI,11254
|
|
9
9
|
quasarr/downloads/linkcrypters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
10
|
quasarr/downloads/linkcrypters/al.py,sha256=pM3NDan8x0WU8OS1GV3HuuV4B6Nm0a-ATrVORvLHt9M,8487
|
|
11
11
|
quasarr/downloads/linkcrypters/filecrypt.py,sha256=GT51x_MG_hW4IpOF6OvL5r-2mTnMijI8K7_1D5Bfn4U,18884
|
|
@@ -15,6 +15,7 @@ quasarr/downloads/sources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
|
|
|
15
15
|
quasarr/downloads/sources/al.py,sha256=Ulc4fTuX8_gOHeTJzZYEAgUCiFPoyczIdbZh6qA3jzM,26180
|
|
16
16
|
quasarr/downloads/sources/by.py,sha256=VzytGYyy81vjsvNJabohoK8PkjYTKCwXM1TjeD3Ker0,3695
|
|
17
17
|
quasarr/downloads/sources/dd.py,sha256=EQ823wrVusVCVJhh9Rdf67-Yae9XYio8Uj_HW_y5qO0,2841
|
|
18
|
+
quasarr/downloads/sources/dj.py,sha256=b_RR_dqd4Zc9lbZbZbwZijDkXCb42OaU7eOAI4lX9EE,214
|
|
18
19
|
quasarr/downloads/sources/dt.py,sha256=fzAyJy8nmqTAFRObvaRbvsXdBkCo5JuojCJYQMYuPOs,2108
|
|
19
20
|
quasarr/downloads/sources/dw.py,sha256=15UH-kBZt06GS5CDi-TTJGV_H59mQO0Nl-y3nYA5kOk,2504
|
|
20
21
|
quasarr/downloads/sources/he.py,sha256=EZ42WIHE8rwvpvwesaWeG__1dUBq75OQzJ1n7Lgrx1g,3450
|
|
@@ -22,30 +23,32 @@ quasarr/downloads/sources/mb.py,sha256=IS5_RdACD3yterFEAj_N7RIH4TVK-VEauZqfya23h
|
|
|
22
23
|
quasarr/downloads/sources/nk.py,sha256=rFdAf9ewfl5ELIFtlZWQ8Z3VjyCSxGwLX92szzwjvz0,1429
|
|
23
24
|
quasarr/downloads/sources/nx.py,sha256=nI0c-oM1g_EyW06_o2wFgn_jm_Zh1XMy3kbRCN0hw1E,3211
|
|
24
25
|
quasarr/downloads/sources/sf.py,sha256=PDBuWgJmEYmD1b-5blS3YWgrqIhJjfwz91IuiMy6rX8,6224
|
|
26
|
+
quasarr/downloads/sources/sj.py,sha256=d2HC52SFYXUXAr7AIaipthVvL-WpvJaD-8AuN-5Z-I8,214
|
|
25
27
|
quasarr/downloads/sources/sl.py,sha256=w6Mo1dphrZRlXfhBfAhFV8KcPfHINuTiFSNu3BYd46k,2851
|
|
26
28
|
quasarr/downloads/sources/wd.py,sha256=NOilEZIF9rumU2LMtfRfXyet3Mzn2shCs8NFCEC3CHY,3747
|
|
27
29
|
quasarr/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
30
|
quasarr/providers/cloudflare.py,sha256=mJxTYM7JjwIjdO6U_GyVj-dyug6XdD0-ObkYTaPtFVg,7028
|
|
29
|
-
quasarr/providers/html_images.py,sha256=
|
|
30
|
-
quasarr/providers/html_templates.py,sha256=
|
|
31
|
+
quasarr/providers/html_images.py,sha256=ZvSzG5Mbjol1I_exFHcb4BZ2eUQ3CqquY_MwRBlr-HU,45609
|
|
32
|
+
quasarr/providers/html_templates.py,sha256=90O9RGwlpJB7jC8NZ0ggh9aD6LNM34IRSVsHCa9vSls,7825
|
|
31
33
|
quasarr/providers/imdb_metadata.py,sha256=10L4kZkt6Fg0HGdNcc6KCtIQHRYEqdarLyaMVN6mT8w,4843
|
|
32
34
|
quasarr/providers/log.py,sha256=_g5RwtfuksARXnvryhsngzoJyFcNzj6suqd3ndqZM0Y,313
|
|
33
35
|
quasarr/providers/myjd_api.py,sha256=1R4uL8Zb8wp1VGcvaO0yMXt2NVGmu6Kn9-GIF4x7vU0,32054
|
|
34
36
|
quasarr/providers/notifications.py,sha256=bohT-6yudmFnmZMc3BwCGX0n1HdzSVgQG_LDZm_38dI,4630
|
|
35
|
-
quasarr/providers/obfuscated.py,sha256=
|
|
37
|
+
quasarr/providers/obfuscated.py,sha256=YydQJHrZ485pHaXK0DHHRW3eLZygGr6c0xnUKD6mcCE,236502
|
|
36
38
|
quasarr/providers/shared_state.py,sha256=4nswf5AuA4c1DWqSXsX0HXwlDt5e-UUUvQSy-vryCRE,28987
|
|
37
39
|
quasarr/providers/statistics.py,sha256=cEQixYnDMDqtm5wWe40E_2ucyo4mD0n3SrfelhQi1L8,6452
|
|
38
|
-
quasarr/providers/version.py,sha256=
|
|
40
|
+
quasarr/providers/version.py,sha256=hICLetkRcBjcm_DHSkjerq19eYDlz2XV7GoVJ2gfrZ8,4004
|
|
39
41
|
quasarr/providers/web_server.py,sha256=XPj98T-axxgotovuB-rVw1IPCkJiNdXBlEeFvM_zSlM,1432
|
|
40
42
|
quasarr/providers/sessions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
41
43
|
quasarr/providers/sessions/al.py,sha256=mlP6SWfCY2HyOSV40uyotQ5T4eSBNYG9A5GWOEAdz-c,9589
|
|
42
44
|
quasarr/providers/sessions/dd.py,sha256=JdXjqmjuyY32w0cIlwphRm8Sy43EK8nEEFwyXUkEGb4,2596
|
|
43
45
|
quasarr/providers/sessions/nx.py,sha256=qfW12AB_0nNsAoKOaSF4z0T9DCxMQleWCYf3fqJtF2A,2688
|
|
44
|
-
quasarr/search/__init__.py,sha256=
|
|
46
|
+
quasarr/search/__init__.py,sha256=yDk_Mx4QEBLODqfFZaRBfbiOGlntuVb22VN63EJdRrk,5367
|
|
45
47
|
quasarr/search/sources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
46
48
|
quasarr/search/sources/al.py,sha256=yr6wx-VcSOFYK_o3N1bepC4t6Gvt9eDvcG9fQBFg0bg,17203
|
|
47
49
|
quasarr/search/sources/by.py,sha256=OPoAqS5kSSNrRVsPlALhX59h3lEZWGA7LlFfL4vH2-o,7914
|
|
48
50
|
quasarr/search/sources/dd.py,sha256=pVpdHLZlw2CYklBf_YLkeDWbCNsDLR2iecccR2c2RyI,4889
|
|
51
|
+
quasarr/search/sources/dj.py,sha256=2HIdg5ddXP4DtjHlyXmuQ8QVhOPt3Hh2kL4uxhFJK-8,7074
|
|
49
52
|
quasarr/search/sources/dt.py,sha256=m1kQ7mC43QlWZyVIkw-OXJGjWiT9IbQuFtHWiR8CjhA,9580
|
|
50
53
|
quasarr/search/sources/dw.py,sha256=-daUTBTA5izeatrE7TITVlnzNCQ5HfovYMMZ8UTM-2o,7636
|
|
51
54
|
quasarr/search/sources/fx.py,sha256=JAyD727yDAFIP14bzfi2SkX9paysXGkQdIybShYtdko,8596
|
|
@@ -54,15 +57,16 @@ quasarr/search/sources/mb.py,sha256=owwH5T0Yh7dwYRqMVQ0ecAdDlQ5CwLwWkTcig2ePggI,
|
|
|
54
57
|
quasarr/search/sources/nk.py,sha256=x84zckK8eG64X3oaPHYhNbK0aoSuVW8xp_n_mlE__NI,6427
|
|
55
58
|
quasarr/search/sources/nx.py,sha256=JdRLA2pWS05m5_ARU-RxAoaBW-8YWEoUN2RebyD2ejo,6981
|
|
56
59
|
quasarr/search/sources/sf.py,sha256=3z_fvcafOh7U4D_vgq9yC8ktKeazI9fiAi96hCeXb5Q,14869
|
|
60
|
+
quasarr/search/sources/sj.py,sha256=JRzoCDohClmGH7aXOz82KVUt6pZsZoBDBXvwvQrAijM,7074
|
|
57
61
|
quasarr/search/sources/sl.py,sha256=5e5S7JvdbNOc2EthyOkfC4aTpG8O7fn4WS2O3_EXjnM,9463
|
|
58
62
|
quasarr/search/sources/wd.py,sha256=O02j3irSlVw2qES82g_qHuavAk-njjSRH1dHSCnOUas,7540
|
|
59
63
|
quasarr/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
60
|
-
quasarr/storage/config.py,sha256=
|
|
64
|
+
quasarr/storage/config.py,sha256=a0JAeiSqMQYBvfZTyYtOxDZvuLGP5lZhMHb7nX9azPc,6130
|
|
61
65
|
quasarr/storage/setup.py,sha256=gpHOsc5qtt-M72saZoMJFLE2YlCrjv7FWZknh-iVKsk,17766
|
|
62
66
|
quasarr/storage/sqlite_database.py,sha256=yMqFQfKf0k7YS-6Z3_7pj4z1GwWSXJ8uvF4IydXsuTE,3554
|
|
63
|
-
quasarr-1.
|
|
64
|
-
quasarr-1.
|
|
65
|
-
quasarr-1.
|
|
66
|
-
quasarr-1.
|
|
67
|
-
quasarr-1.
|
|
68
|
-
quasarr-1.
|
|
67
|
+
quasarr-1.20.0.dist-info/licenses/LICENSE,sha256=QQFCAfDgt7lSA8oSWDHIZ9aTjFbZaBJdjnGOHkuhK7k,1060
|
|
68
|
+
quasarr-1.20.0.dist-info/METADATA,sha256=AbZO84u4V8ndc4_3p-gVhYaJUTogndLIe7BaboozfRE,12249
|
|
69
|
+
quasarr-1.20.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
70
|
+
quasarr-1.20.0.dist-info/entry_points.txt,sha256=gXi8mUKsIqKVvn-bOc8E5f04sK_KoMCC-ty6b2Hf-jc,40
|
|
71
|
+
quasarr-1.20.0.dist-info/top_level.txt,sha256=dipJdaRda5ruTZkoGfZU60bY4l9dtPlmOWwxK_oGSF0,8
|
|
72
|
+
quasarr-1.20.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|