quasarr 1.20.8__py3-none-any.whl → 1.21.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.
- quasarr/__init__.py +7 -0
- quasarr/api/arr/__init__.py +4 -1
- quasarr/downloads/__init__.py +93 -27
- quasarr/downloads/sources/dl.py +196 -0
- quasarr/downloads/sources/wx.py +127 -0
- quasarr/providers/html_images.py +2 -0
- quasarr/providers/myjd_api.py +35 -4
- quasarr/providers/sessions/dl.py +175 -0
- quasarr/providers/shared_state.py +21 -5
- quasarr/providers/version.py +1 -1
- quasarr/search/__init__.py +9 -0
- quasarr/search/sources/dl.py +316 -0
- quasarr/search/sources/wx.py +342 -0
- quasarr/storage/config.py +7 -1
- quasarr/storage/setup.py +10 -2
- {quasarr-1.20.8.dist-info → quasarr-1.21.0.dist-info}/METADATA +3 -1
- {quasarr-1.20.8.dist-info → quasarr-1.21.0.dist-info}/RECORD +21 -16
- {quasarr-1.20.8.dist-info → quasarr-1.21.0.dist-info}/WHEEL +0 -0
- {quasarr-1.20.8.dist-info → quasarr-1.21.0.dist-info}/entry_points.txt +0 -0
- {quasarr-1.20.8.dist-info → quasarr-1.21.0.dist-info}/licenses/LICENSE +0 -0
- {quasarr-1.20.8.dist-info → quasarr-1.21.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Quasarr
|
|
3
|
+
# Project by https://github.com/rix1337
|
|
4
|
+
|
|
5
|
+
import html
|
|
6
|
+
import time
|
|
7
|
+
import traceback
|
|
8
|
+
import warnings
|
|
9
|
+
from base64 import urlsafe_b64encode
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
|
|
12
|
+
import requests
|
|
13
|
+
from bs4 import BeautifulSoup
|
|
14
|
+
from bs4 import XMLParsedAsHTMLWarning
|
|
15
|
+
|
|
16
|
+
from quasarr.providers.imdb_metadata import get_localized_title
|
|
17
|
+
from quasarr.providers.log import info, debug
|
|
18
|
+
|
|
19
|
+
warnings.filterwarnings("ignore", category=XMLParsedAsHTMLWarning) # we dont want to use lxml
|
|
20
|
+
|
|
21
|
+
hostname = "wx"
|
|
22
|
+
supported_mirrors = []
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def wx_feed(shared_state, start_time, request_from, mirror=None):
|
|
26
|
+
"""
|
|
27
|
+
Fetch latest releases from RSS feed.
|
|
28
|
+
"""
|
|
29
|
+
releases = []
|
|
30
|
+
host = shared_state.values["config"]("Hostnames").get(hostname)
|
|
31
|
+
|
|
32
|
+
if "lazylibrarian" in request_from.lower():
|
|
33
|
+
debug(f'Skipping {request_from} search on "{hostname.upper()}" (unsupported media type)!')
|
|
34
|
+
return releases
|
|
35
|
+
|
|
36
|
+
rss_url = f'https://{host}/rss'
|
|
37
|
+
headers = {
|
|
38
|
+
'User-Agent': shared_state.values["user_agent"],
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
response = requests.get(rss_url, headers=headers, timeout=10)
|
|
43
|
+
|
|
44
|
+
if response.status_code != 200:
|
|
45
|
+
info(f"{hostname.upper()}: RSS feed returned status {response.status_code}")
|
|
46
|
+
return releases
|
|
47
|
+
|
|
48
|
+
soup = BeautifulSoup(response.content, 'html.parser')
|
|
49
|
+
items = soup.find_all('entry')
|
|
50
|
+
|
|
51
|
+
if not items:
|
|
52
|
+
items = soup.find_all('item')
|
|
53
|
+
|
|
54
|
+
if not items:
|
|
55
|
+
debug(f"{hostname.upper()}: No entries found in RSS feed")
|
|
56
|
+
return releases
|
|
57
|
+
|
|
58
|
+
max_releases = 100
|
|
59
|
+
if len(items) > max_releases:
|
|
60
|
+
debug(f"{hostname.upper()}: Found {len(items)} entries, limiting to {max_releases}")
|
|
61
|
+
items = items[:max_releases]
|
|
62
|
+
else:
|
|
63
|
+
debug(f"{hostname.upper()}: Found {len(items)} entries in RSS feed")
|
|
64
|
+
|
|
65
|
+
for item in items:
|
|
66
|
+
try:
|
|
67
|
+
title_tag = item.find('title')
|
|
68
|
+
if not title_tag:
|
|
69
|
+
continue
|
|
70
|
+
|
|
71
|
+
title = title_tag.get_text(strip=True)
|
|
72
|
+
if not title:
|
|
73
|
+
continue
|
|
74
|
+
|
|
75
|
+
title = html.unescape(title)
|
|
76
|
+
title = title.replace(']]>', '').replace('<![CDATA[', '')
|
|
77
|
+
title = title.replace(' ', '.')
|
|
78
|
+
|
|
79
|
+
link_tag = item.find('link', rel='alternate')
|
|
80
|
+
if link_tag and link_tag.has_attr('href'):
|
|
81
|
+
source = link_tag['href']
|
|
82
|
+
else:
|
|
83
|
+
link_tag = item.find('link')
|
|
84
|
+
if not link_tag:
|
|
85
|
+
continue
|
|
86
|
+
source = link_tag.get_text(strip=True)
|
|
87
|
+
|
|
88
|
+
if not source:
|
|
89
|
+
continue
|
|
90
|
+
|
|
91
|
+
pub_date = item.find('updated') or item.find('pubDate')
|
|
92
|
+
if pub_date:
|
|
93
|
+
published = pub_date.get_text(strip=True)
|
|
94
|
+
else:
|
|
95
|
+
# Fallback: use current time if no pubDate found
|
|
96
|
+
published = datetime.now().strftime("%a, %d %b %Y %H:%M:%S +0000")
|
|
97
|
+
|
|
98
|
+
mb = 0
|
|
99
|
+
size = 0
|
|
100
|
+
imdb_id = None
|
|
101
|
+
password = host.upper()
|
|
102
|
+
|
|
103
|
+
payload = urlsafe_b64encode(
|
|
104
|
+
f"{title}|{source}|{mirror}|{mb}|{password}|{imdb_id or ''}".encode("utf-8")
|
|
105
|
+
).decode("utf-8")
|
|
106
|
+
link = f"{shared_state.values['internal_address']}/download/?payload={payload}"
|
|
107
|
+
|
|
108
|
+
releases.append({
|
|
109
|
+
"details": {
|
|
110
|
+
"title": title,
|
|
111
|
+
"hostname": hostname,
|
|
112
|
+
"imdb_id": imdb_id,
|
|
113
|
+
"link": link,
|
|
114
|
+
"mirror": mirror,
|
|
115
|
+
"size": size,
|
|
116
|
+
"date": published,
|
|
117
|
+
"source": source
|
|
118
|
+
},
|
|
119
|
+
"type": "protected"
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
except Exception as e:
|
|
123
|
+
debug(f"{hostname.upper()}: error parsing RSS entry: {e}")
|
|
124
|
+
continue
|
|
125
|
+
|
|
126
|
+
except Exception as e:
|
|
127
|
+
info(f"Error loading {hostname.upper()} feed: {e}")
|
|
128
|
+
return releases
|
|
129
|
+
|
|
130
|
+
elapsed_time = time.time() - start_time
|
|
131
|
+
debug(f"Time taken: {elapsed_time:.2f}s ({hostname})")
|
|
132
|
+
|
|
133
|
+
return releases
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def wx_search(shared_state, start_time, request_from, search_string, mirror=None, season=None, episode=None):
|
|
137
|
+
"""
|
|
138
|
+
Search using internal API.
|
|
139
|
+
"""
|
|
140
|
+
releases = []
|
|
141
|
+
host = shared_state.values["config"]("Hostnames").get(hostname)
|
|
142
|
+
|
|
143
|
+
if "lazylibrarian" in request_from.lower():
|
|
144
|
+
debug(f'Skipping {request_from} search on "{hostname.upper()}" (unsupported media type)!')
|
|
145
|
+
return releases
|
|
146
|
+
|
|
147
|
+
imdb_id = shared_state.is_imdb_id(search_string)
|
|
148
|
+
if imdb_id:
|
|
149
|
+
info(f"{hostname.upper()}: Received IMDb ID: {imdb_id}")
|
|
150
|
+
title = get_localized_title(shared_state, imdb_id, 'de')
|
|
151
|
+
if not title:
|
|
152
|
+
info(f"{hostname.upper()}: no title for IMDb {imdb_id}")
|
|
153
|
+
return releases
|
|
154
|
+
info(f"{hostname.upper()}: Translated IMDb {imdb_id} to German title: '{title}'")
|
|
155
|
+
search_string = html.unescape(title)
|
|
156
|
+
else:
|
|
157
|
+
info(f"{hostname.upper()}: Using search string directly: '{search_string}'")
|
|
158
|
+
|
|
159
|
+
api_url = f'https://api.{host}/start/search'
|
|
160
|
+
|
|
161
|
+
headers = {
|
|
162
|
+
'User-Agent': shared_state.values["user_agent"],
|
|
163
|
+
'Accept': 'application/json, text/plain, */*',
|
|
164
|
+
'Referer': f'https://{host}/search'
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
params = {
|
|
168
|
+
'__LOAD_P': '',
|
|
169
|
+
'per_page': 50,
|
|
170
|
+
'q': search_string,
|
|
171
|
+
'selectedTypes': '',
|
|
172
|
+
'selectedGenres': '',
|
|
173
|
+
'types': 'movie,series,anime',
|
|
174
|
+
'genres': '',
|
|
175
|
+
'years': '',
|
|
176
|
+
'ratings': '',
|
|
177
|
+
'page': 1,
|
|
178
|
+
'sortBy': 'latest',
|
|
179
|
+
'sortOrder': 'desc'
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if "sonarr" in request_from.lower():
|
|
183
|
+
params['types'] = 'series,anime'
|
|
184
|
+
elif "radarr" in request_from.lower():
|
|
185
|
+
params['types'] = 'movie'
|
|
186
|
+
|
|
187
|
+
info(f"{hostname.upper()}: Searching: '{search_string}'")
|
|
188
|
+
|
|
189
|
+
try:
|
|
190
|
+
response = requests.get(api_url, headers=headers, params=params, timeout=10)
|
|
191
|
+
|
|
192
|
+
if response.status_code != 200:
|
|
193
|
+
info(f"{hostname.upper()}: Search API returned status {response.status_code}")
|
|
194
|
+
return releases
|
|
195
|
+
|
|
196
|
+
data = response.json()
|
|
197
|
+
|
|
198
|
+
if 'items' in data and 'data' in data['items']:
|
|
199
|
+
items = data['items']['data']
|
|
200
|
+
elif 'data' in data:
|
|
201
|
+
items = data['data']
|
|
202
|
+
elif 'results' in data:
|
|
203
|
+
items = data['results']
|
|
204
|
+
else:
|
|
205
|
+
items = data if isinstance(data, list) else []
|
|
206
|
+
|
|
207
|
+
info(f"{hostname.upper()}: Found {len(items)} items in search results")
|
|
208
|
+
|
|
209
|
+
for item in items:
|
|
210
|
+
try:
|
|
211
|
+
uid = item.get('uid')
|
|
212
|
+
if not uid:
|
|
213
|
+
debug(f"{hostname.upper()}: Item has no UID, skipping")
|
|
214
|
+
continue
|
|
215
|
+
|
|
216
|
+
info(f"{hostname.upper()}: Fetching details for UID: {uid}")
|
|
217
|
+
|
|
218
|
+
detail_url = f'https://api.{host}/start/d/{uid}'
|
|
219
|
+
detail_response = requests.get(detail_url, headers=headers, timeout=10)
|
|
220
|
+
|
|
221
|
+
if detail_response.status_code != 200:
|
|
222
|
+
debug(f"{hostname.upper()}: Detail API returned {detail_response.status_code} for {uid}")
|
|
223
|
+
continue
|
|
224
|
+
|
|
225
|
+
detail_data = detail_response.json()
|
|
226
|
+
|
|
227
|
+
if 'item' in detail_data:
|
|
228
|
+
detail_item = detail_data['item']
|
|
229
|
+
else:
|
|
230
|
+
detail_item = detail_data
|
|
231
|
+
|
|
232
|
+
item_imdb_id = imdb_id
|
|
233
|
+
if not item_imdb_id:
|
|
234
|
+
item_imdb_id = detail_item.get('imdb_id') or detail_item.get('imdbid')
|
|
235
|
+
if not item_imdb_id and 'options' in detail_item:
|
|
236
|
+
item_imdb_id = detail_item['options'].get('imdb_id')
|
|
237
|
+
|
|
238
|
+
source = f"https://{host}/detail/{uid}"
|
|
239
|
+
|
|
240
|
+
main_title = detail_item.get('fulltitle') or detail_item.get('title') or detail_item.get('name')
|
|
241
|
+
if main_title:
|
|
242
|
+
title = html.unescape(main_title)
|
|
243
|
+
title = title.replace(' ', '.')
|
|
244
|
+
|
|
245
|
+
if shared_state.is_valid_release(title, request_from, search_string, season, episode):
|
|
246
|
+
published = detail_item.get('updated_at') or detail_item.get('created_at')
|
|
247
|
+
if not published:
|
|
248
|
+
published = datetime.now().strftime("%a, %d %b %Y %H:%M:%S +0000")
|
|
249
|
+
password = f"www.{host}"
|
|
250
|
+
|
|
251
|
+
payload = urlsafe_b64encode(
|
|
252
|
+
f"{title}|{source}|{mirror}|0|{password}|{item_imdb_id or ''}".encode("utf-8")
|
|
253
|
+
).decode("utf-8")
|
|
254
|
+
link = f"{shared_state.values['internal_address']}/download/?payload={payload}"
|
|
255
|
+
|
|
256
|
+
releases.append({
|
|
257
|
+
"details": {
|
|
258
|
+
"title": title,
|
|
259
|
+
"hostname": hostname,
|
|
260
|
+
"imdb_id": item_imdb_id,
|
|
261
|
+
"link": link,
|
|
262
|
+
"mirror": mirror,
|
|
263
|
+
"size": 0,
|
|
264
|
+
"date": published,
|
|
265
|
+
"source": source
|
|
266
|
+
},
|
|
267
|
+
"type": "protected"
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
if 'releases' in detail_item and isinstance(detail_item['releases'], list):
|
|
271
|
+
info(f"{hostname.upper()}: Found {len(detail_item['releases'])} releases for {uid}")
|
|
272
|
+
|
|
273
|
+
for release in detail_item['releases']:
|
|
274
|
+
try:
|
|
275
|
+
release_title = release.get('fulltitle')
|
|
276
|
+
if not release_title:
|
|
277
|
+
continue
|
|
278
|
+
|
|
279
|
+
release_title = html.unescape(release_title)
|
|
280
|
+
release_title = release_title.replace(' ', '.')
|
|
281
|
+
|
|
282
|
+
if not shared_state.is_valid_release(release_title, request_from, search_string, season,
|
|
283
|
+
episode):
|
|
284
|
+
debug(f"{hostname.upper()}: ✗ Release filtered out: {release_title}")
|
|
285
|
+
continue
|
|
286
|
+
|
|
287
|
+
release_uid = release.get('uid')
|
|
288
|
+
if release_uid:
|
|
289
|
+
release_source = f"https://{host}/detail/{uid}?release={release_uid}"
|
|
290
|
+
else:
|
|
291
|
+
release_source = source
|
|
292
|
+
|
|
293
|
+
release_published = release.get('updated_at') or release.get(
|
|
294
|
+
'created_at') or detail_item.get('updated_at')
|
|
295
|
+
if not release_published:
|
|
296
|
+
release_published = datetime.now().strftime("%a, %d %b %Y %H:%M:%S +0000")
|
|
297
|
+
release_size = release.get('size', 0)
|
|
298
|
+
password = f"www.{host}"
|
|
299
|
+
|
|
300
|
+
payload = urlsafe_b64encode(
|
|
301
|
+
f"{release_title}|{release_source}|{mirror}|{release_size}|{password}|{item_imdb_id or ''}".encode(
|
|
302
|
+
"utf-8")
|
|
303
|
+
).decode("utf-8")
|
|
304
|
+
link = f"{shared_state.values['internal_address']}/download/?payload={payload}"
|
|
305
|
+
|
|
306
|
+
releases.append({
|
|
307
|
+
"details": {
|
|
308
|
+
"title": release_title,
|
|
309
|
+
"hostname": hostname,
|
|
310
|
+
"imdb_id": item_imdb_id,
|
|
311
|
+
"link": link,
|
|
312
|
+
"mirror": mirror,
|
|
313
|
+
"size": release_size,
|
|
314
|
+
"date": release_published,
|
|
315
|
+
"source": release_source
|
|
316
|
+
},
|
|
317
|
+
"type": "protected"
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
except Exception as e:
|
|
321
|
+
debug(f"{hostname.upper()}: Error parsing release: {e}")
|
|
322
|
+
continue
|
|
323
|
+
else:
|
|
324
|
+
debug(f"{hostname.upper()}: No releases array found for {uid}")
|
|
325
|
+
|
|
326
|
+
except Exception as e:
|
|
327
|
+
debug(f"{hostname.upper()}: Error processing item: {e}")
|
|
328
|
+
debug(f"{hostname.upper()}: {traceback.format_exc()}")
|
|
329
|
+
continue
|
|
330
|
+
|
|
331
|
+
info(f"{hostname.upper()}: Returning {len(releases)} total releases")
|
|
332
|
+
|
|
333
|
+
except Exception as e:
|
|
334
|
+
info(f"Error in {hostname.upper()} search: {e}")
|
|
335
|
+
|
|
336
|
+
debug(f"{hostname.upper()}: {traceback.format_exc()}")
|
|
337
|
+
return releases
|
|
338
|
+
|
|
339
|
+
elapsed_time = time.time() - start_time
|
|
340
|
+
debug(f"Time taken: {elapsed_time:.2f}s ({hostname})")
|
|
341
|
+
|
|
342
|
+
return releases
|
quasarr/storage/config.py
CHANGED
|
@@ -30,6 +30,7 @@ class Config(object):
|
|
|
30
30
|
("by", "secret", ""),
|
|
31
31
|
("dd", "secret", ""),
|
|
32
32
|
("dj", "secret", ""),
|
|
33
|
+
("dl", "secret", ""),
|
|
33
34
|
("dt", "secret", ""),
|
|
34
35
|
("dw", "secret", ""),
|
|
35
36
|
("fx", "secret", ""),
|
|
@@ -40,7 +41,8 @@ class Config(object):
|
|
|
40
41
|
("sf", "secret", ""),
|
|
41
42
|
("sj", "secret", ""),
|
|
42
43
|
("sl", "secret", ""),
|
|
43
|
-
("wd", "secret", "")
|
|
44
|
+
("wd", "secret", ""),
|
|
45
|
+
("wx", "secret", "")
|
|
44
46
|
],
|
|
45
47
|
'FlareSolverr': [
|
|
46
48
|
("url", "str", ""),
|
|
@@ -53,6 +55,10 @@ class Config(object):
|
|
|
53
55
|
("user", "secret", ""),
|
|
54
56
|
("password", "secret", "")
|
|
55
57
|
],
|
|
58
|
+
'DL': [
|
|
59
|
+
("user", "secret", ""),
|
|
60
|
+
("password", "secret", "")
|
|
61
|
+
],
|
|
56
62
|
'NX': [
|
|
57
63
|
("user", "secret", ""),
|
|
58
64
|
("password", "secret", "")
|
quasarr/storage/setup.py
CHANGED
|
@@ -12,6 +12,7 @@ import quasarr
|
|
|
12
12
|
import quasarr.providers.html_images as images
|
|
13
13
|
import quasarr.providers.sessions.al
|
|
14
14
|
import quasarr.providers.sessions.dd
|
|
15
|
+
import quasarr.providers.sessions.dl
|
|
15
16
|
import quasarr.providers.sessions.nx
|
|
16
17
|
from quasarr.providers.html_templates import render_button, render_form, render_success, render_fail
|
|
17
18
|
from quasarr.providers.log import info
|
|
@@ -263,14 +264,21 @@ def hostname_credentials_config(shared_state, shorthand, domain):
|
|
|
263
264
|
if quasarr.providers.sessions.al.create_and_persist_session(shared_state):
|
|
264
265
|
quasarr.providers.web_server.temp_server_success = True
|
|
265
266
|
return render_success(f"{sh} credentials set successfully", 5)
|
|
266
|
-
|
|
267
|
+
elif sh.lower() == "dd":
|
|
267
268
|
if quasarr.providers.sessions.dd.create_and_persist_session(shared_state):
|
|
268
269
|
quasarr.providers.web_server.temp_server_success = True
|
|
269
270
|
return render_success(f"{sh} credentials set successfully", 5)
|
|
270
|
-
|
|
271
|
+
elif sh.lower() == "dl":
|
|
272
|
+
if quasarr.providers.sessions.dl.create_and_persist_session(shared_state):
|
|
273
|
+
quasarr.providers.web_server.temp_server_success = True
|
|
274
|
+
return render_success(f"{sh} credentials set successfully", 5)
|
|
275
|
+
elif sh.lower() == "nx":
|
|
271
276
|
if quasarr.providers.sessions.nx.create_and_persist_session(shared_state):
|
|
272
277
|
quasarr.providers.web_server.temp_server_success = True
|
|
273
278
|
return render_success(f"{sh} credentials set successfully", 5)
|
|
279
|
+
else:
|
|
280
|
+
quasarr.providers.web_server.temp_server_success = False
|
|
281
|
+
return render_fail(f"Unknown site shorthand! ({sh})")
|
|
274
282
|
|
|
275
283
|
config.save("user", "")
|
|
276
284
|
config.save("password", "")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quasarr
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.21.0
|
|
4
4
|
Summary: Quasarr connects JDownloader with Radarr, Sonarr and LazyLibrarian. It also decrypts links protected by CAPTCHAs.
|
|
5
5
|
Home-page: https://github.com/rix1337/Quasarr
|
|
6
6
|
Author: rix1337
|
|
@@ -151,6 +151,7 @@ docker run -d \
|
|
|
151
151
|
-e 'HOSTNAMES'='https://pastebin.com/raw/eX4Mpl3'
|
|
152
152
|
-e 'SILENT'='True' \
|
|
153
153
|
-e 'DEBUG'='' \
|
|
154
|
+
-e 'TZ'='Europe/Berlin' \
|
|
154
155
|
ghcr.io/rix1337/quasarr:latest
|
|
155
156
|
```
|
|
156
157
|
|
|
@@ -163,6 +164,7 @@ docker run -d \
|
|
|
163
164
|
* Must contain at least one valid Hostname per line `ab = xyz`
|
|
164
165
|
* `SILENT` is optional and silences all discord notifications except for error messages from SponsorsHelper if `True`.
|
|
165
166
|
* `DEBUG` is optional and enables debug logging if `True`.
|
|
167
|
+
* `TZ` is optional, wrong timezone can cause HTTPS/SSL issues
|
|
166
168
|
|
|
167
169
|
# Manual setup
|
|
168
170
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
quasarr/__init__.py,sha256=
|
|
1
|
+
quasarr/__init__.py,sha256=4-EVvIdDjMqidqp3xpXfcDl-fSe0J_B415ueZDAKBss,18137
|
|
2
2
|
quasarr/api/__init__.py,sha256=9Y_DTNYsHeimrXL3mAli8OUg0zqo7QGLF2ft40d3R-c,6822
|
|
3
|
-
quasarr/api/arr/__init__.py,sha256=
|
|
3
|
+
quasarr/api/arr/__init__.py,sha256=Un2mi_z8aHHhE8ks4Dq50FO3PFHUmBWggrDvU39TVaU,16711
|
|
4
4
|
quasarr/api/captcha/__init__.py,sha256=2qlcJn_Kp_PWP8-_MJvIlPkRlZitH4B58QbdcFZ6xqU,49765
|
|
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=AGZcafQG7ZKLadYaWmR0HR3lljt-l00llWw3G39Y9vA,13345
|
|
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
|
|
@@ -16,6 +16,7 @@ quasarr/downloads/sources/al.py,sha256=Ulc4fTuX8_gOHeTJzZYEAgUCiFPoyczIdbZh6qA3j
|
|
|
16
16
|
quasarr/downloads/sources/by.py,sha256=VzytGYyy81vjsvNJabohoK8PkjYTKCwXM1TjeD3Ker0,3695
|
|
17
17
|
quasarr/downloads/sources/dd.py,sha256=EQ823wrVusVCVJhh9Rdf67-Yae9XYio8Uj_HW_y5qO0,2841
|
|
18
18
|
quasarr/downloads/sources/dj.py,sha256=b_RR_dqd4Zc9lbZbZbwZijDkXCb42OaU7eOAI4lX9EE,214
|
|
19
|
+
quasarr/downloads/sources/dl.py,sha256=nCSDQpa3X7b6Q1M7sxv6GgZ7FJQfJ50dWv43u8ozdjc,7475
|
|
19
20
|
quasarr/downloads/sources/dt.py,sha256=fzAyJy8nmqTAFRObvaRbvsXdBkCo5JuojCJYQMYuPOs,2108
|
|
20
21
|
quasarr/downloads/sources/dw.py,sha256=15UH-kBZt06GS5CDi-TTJGV_H59mQO0Nl-y3nYA5kOk,2504
|
|
21
22
|
quasarr/downloads/sources/he.py,sha256=EZ42WIHE8rwvpvwesaWeG__1dUBq75OQzJ1n7Lgrx1g,3450
|
|
@@ -26,29 +27,32 @@ quasarr/downloads/sources/sf.py,sha256=PDBuWgJmEYmD1b-5blS3YWgrqIhJjfwz91IuiMy6r
|
|
|
26
27
|
quasarr/downloads/sources/sj.py,sha256=d2HC52SFYXUXAr7AIaipthVvL-WpvJaD-8AuN-5Z-I8,214
|
|
27
28
|
quasarr/downloads/sources/sl.py,sha256=w6Mo1dphrZRlXfhBfAhFV8KcPfHINuTiFSNu3BYd46k,2851
|
|
28
29
|
quasarr/downloads/sources/wd.py,sha256=NOilEZIF9rumU2LMtfRfXyet3Mzn2shCs8NFCEC3CHY,3747
|
|
30
|
+
quasarr/downloads/sources/wx.py,sha256=lufMZYNniKWj2x2mfYsEkGw_Qqi3TWg66EgU3uP9TiI,4769
|
|
29
31
|
quasarr/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
32
|
quasarr/providers/cloudflare.py,sha256=mJxTYM7JjwIjdO6U_GyVj-dyug6XdD0-ObkYTaPtFVg,7028
|
|
31
|
-
quasarr/providers/html_images.py,sha256=
|
|
33
|
+
quasarr/providers/html_images.py,sha256=CvJgBs_M5ziTI-ccSQheI7FC1pZWY52R9Elq5WuBwfY,46481
|
|
32
34
|
quasarr/providers/html_templates.py,sha256=90O9RGwlpJB7jC8NZ0ggh9aD6LNM34IRSVsHCa9vSls,7825
|
|
33
35
|
quasarr/providers/imdb_metadata.py,sha256=10L4kZkt6Fg0HGdNcc6KCtIQHRYEqdarLyaMVN6mT8w,4843
|
|
34
36
|
quasarr/providers/log.py,sha256=_g5RwtfuksARXnvryhsngzoJyFcNzj6suqd3ndqZM0Y,313
|
|
35
|
-
quasarr/providers/myjd_api.py,sha256=
|
|
37
|
+
quasarr/providers/myjd_api.py,sha256=Z3PEiO3c3UfDSr4Up5rgwTAnjloWHb-H1RkJ6BLKZv8,34140
|
|
36
38
|
quasarr/providers/notifications.py,sha256=bohT-6yudmFnmZMc3BwCGX0n1HdzSVgQG_LDZm_38dI,4630
|
|
37
39
|
quasarr/providers/obfuscated.py,sha256=YydQJHrZ485pHaXK0DHHRW3eLZygGr6c0xnUKD6mcCE,236502
|
|
38
|
-
quasarr/providers/shared_state.py,sha256=
|
|
40
|
+
quasarr/providers/shared_state.py,sha256=1NUKtm9YXWPvN64By2O2OYH5ke5TmBkJSbSxiNczgtU,29849
|
|
39
41
|
quasarr/providers/statistics.py,sha256=cEQixYnDMDqtm5wWe40E_2ucyo4mD0n3SrfelhQi1L8,6452
|
|
40
|
-
quasarr/providers/version.py,sha256=
|
|
42
|
+
quasarr/providers/version.py,sha256=8JL_ohKOlHRsgfE_9gi7SYPfyd2pMk1L1sREQrMUV6I,4004
|
|
41
43
|
quasarr/providers/web_server.py,sha256=XPj98T-axxgotovuB-rVw1IPCkJiNdXBlEeFvM_zSlM,1432
|
|
42
44
|
quasarr/providers/sessions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
43
45
|
quasarr/providers/sessions/al.py,sha256=mlP6SWfCY2HyOSV40uyotQ5T4eSBNYG9A5GWOEAdz-c,9589
|
|
44
46
|
quasarr/providers/sessions/dd.py,sha256=JdXjqmjuyY32w0cIlwphRm8Sy43EK8nEEFwyXUkEGb4,2596
|
|
47
|
+
quasarr/providers/sessions/dl.py,sha256=8toAHn5C9FbjHuhjfQEeKR1Fz5tRENrIgFxdjUuXCIU,5381
|
|
45
48
|
quasarr/providers/sessions/nx.py,sha256=qfW12AB_0nNsAoKOaSF4z0T9DCxMQleWCYf3fqJtF2A,2688
|
|
46
|
-
quasarr/search/__init__.py,sha256=
|
|
49
|
+
quasarr/search/__init__.py,sha256=V59LIiC75mQvasDdTjiWZRbPD1jXO1lhXlKeNVX0iOc,5726
|
|
47
50
|
quasarr/search/sources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
48
51
|
quasarr/search/sources/al.py,sha256=yr6wx-VcSOFYK_o3N1bepC4t6Gvt9eDvcG9fQBFg0bg,17203
|
|
49
52
|
quasarr/search/sources/by.py,sha256=OPoAqS5kSSNrRVsPlALhX59h3lEZWGA7LlFfL4vH2-o,7914
|
|
50
53
|
quasarr/search/sources/dd.py,sha256=pVpdHLZlw2CYklBf_YLkeDWbCNsDLR2iecccR2c2RyI,4889
|
|
51
54
|
quasarr/search/sources/dj.py,sha256=2HIdg5ddXP4DtjHlyXmuQ8QVhOPt3Hh2kL4uxhFJK-8,7074
|
|
55
|
+
quasarr/search/sources/dl.py,sha256=-CY3dSbzGwZ4t1Z0B0Q1dBQg1jStrUpqF6jG_-BytSs,11379
|
|
52
56
|
quasarr/search/sources/dt.py,sha256=m1kQ7mC43QlWZyVIkw-OXJGjWiT9IbQuFtHWiR8CjhA,9580
|
|
53
57
|
quasarr/search/sources/dw.py,sha256=-daUTBTA5izeatrE7TITVlnzNCQ5HfovYMMZ8UTM-2o,7636
|
|
54
58
|
quasarr/search/sources/fx.py,sha256=JAyD727yDAFIP14bzfi2SkX9paysXGkQdIybShYtdko,8596
|
|
@@ -60,13 +64,14 @@ quasarr/search/sources/sf.py,sha256=3z_fvcafOh7U4D_vgq9yC8ktKeazI9fiAi96hCeXb5Q,
|
|
|
60
64
|
quasarr/search/sources/sj.py,sha256=JRzoCDohClmGH7aXOz82KVUt6pZsZoBDBXvwvQrAijM,7074
|
|
61
65
|
quasarr/search/sources/sl.py,sha256=5e5S7JvdbNOc2EthyOkfC4aTpG8O7fn4WS2O3_EXjnM,9463
|
|
62
66
|
quasarr/search/sources/wd.py,sha256=O02j3irSlVw2qES82g_qHuavAk-njjSRH1dHSCnOUas,7540
|
|
67
|
+
quasarr/search/sources/wx.py,sha256=B6Ra0Wie9Ii96Kiz4Zdpb_qUmBwWkyA0rIoA7XdNNYo,13118
|
|
63
68
|
quasarr/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
64
|
-
quasarr/storage/config.py,sha256=
|
|
65
|
-
quasarr/storage/setup.py,sha256=
|
|
69
|
+
quasarr/storage/config.py,sha256=hOI7vvIo1YaML3dtAkTmp0HSedWF6brVhRk3d8pJtXI,6300
|
|
70
|
+
quasarr/storage/setup.py,sha256=Sv5piyCnCfAfOLErHQGZS91HwTgbmLcW7K51kR6235g,18255
|
|
66
71
|
quasarr/storage/sqlite_database.py,sha256=yMqFQfKf0k7YS-6Z3_7pj4z1GwWSXJ8uvF4IydXsuTE,3554
|
|
67
|
-
quasarr-1.
|
|
68
|
-
quasarr-1.
|
|
69
|
-
quasarr-1.
|
|
70
|
-
quasarr-1.
|
|
71
|
-
quasarr-1.
|
|
72
|
-
quasarr-1.
|
|
72
|
+
quasarr-1.21.0.dist-info/licenses/LICENSE,sha256=QQFCAfDgt7lSA8oSWDHIZ9aTjFbZaBJdjnGOHkuhK7k,1060
|
|
73
|
+
quasarr-1.21.0.dist-info/METADATA,sha256=Nsl4ztdogzEu2h9xb6T7dSIGWitdMAmskj0Xt4vxl8M,12743
|
|
74
|
+
quasarr-1.21.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
75
|
+
quasarr-1.21.0.dist-info/entry_points.txt,sha256=gXi8mUKsIqKVvn-bOc8E5f04sK_KoMCC-ty6b2Hf-jc,40
|
|
76
|
+
quasarr-1.21.0.dist-info/top_level.txt,sha256=dipJdaRda5ruTZkoGfZU60bY4l9dtPlmOWwxK_oGSF0,8
|
|
77
|
+
quasarr-1.21.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|