quasarr 1.21.1__tar.gz → 1.21.2__tar.gz
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-1.21.1 → quasarr-1.21.2}/PKG-INFO +1 -1
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/api/arr/__init__.py +11 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/providers/version.py +1 -1
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/search/sources/by.py +2 -1
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/search/sources/dl.py +38 -28
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr.egg-info/PKG-INFO +1 -1
- {quasarr-1.21.1 → quasarr-1.21.2}/LICENSE +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/README.md +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/__init__.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/api/__init__.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/api/captcha/__init__.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/api/config/__init__.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/api/sponsors_helper/__init__.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/api/statistics/__init__.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/downloads/__init__.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/downloads/linkcrypters/__init__.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/downloads/linkcrypters/al.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/downloads/linkcrypters/filecrypt.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/downloads/linkcrypters/hide.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/downloads/packages/__init__.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/downloads/sources/__init__.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/downloads/sources/al.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/downloads/sources/by.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/downloads/sources/dd.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/downloads/sources/dj.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/downloads/sources/dl.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/downloads/sources/dt.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/downloads/sources/dw.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/downloads/sources/he.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/downloads/sources/mb.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/downloads/sources/nk.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/downloads/sources/nx.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/downloads/sources/sf.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/downloads/sources/sj.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/downloads/sources/sl.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/downloads/sources/wd.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/downloads/sources/wx.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/providers/__init__.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/providers/cloudflare.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/providers/html_images.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/providers/html_templates.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/providers/imdb_metadata.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/providers/log.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/providers/myjd_api.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/providers/notifications.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/providers/obfuscated.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/providers/sessions/__init__.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/providers/sessions/al.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/providers/sessions/dd.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/providers/sessions/dl.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/providers/sessions/nx.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/providers/shared_state.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/providers/statistics.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/providers/web_server.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/search/__init__.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/search/sources/__init__.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/search/sources/al.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/search/sources/dd.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/search/sources/dj.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/search/sources/dt.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/search/sources/dw.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/search/sources/fx.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/search/sources/he.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/search/sources/mb.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/search/sources/nk.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/search/sources/nx.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/search/sources/sf.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/search/sources/sj.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/search/sources/sl.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/search/sources/wd.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/search/sources/wx.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/storage/__init__.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/storage/config.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/storage/setup.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr/storage/sqlite_database.py +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr.egg-info/SOURCES.txt +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr.egg-info/dependency_links.txt +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr.egg-info/entry_points.txt +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr.egg-info/not-zip-safe +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr.egg-info/requires.txt +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/quasarr.egg-info/top_level.txt +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/setup.cfg +0 -0
- {quasarr-1.21.1 → quasarr-1.21.2}/setup.py +0 -0
|
@@ -353,6 +353,17 @@ def setup_arr_routes(app):
|
|
|
353
353
|
<enclosure url="{release.get("link", "")}" length="{release.get("size", 0)}" type="application/x-nzb" />
|
|
354
354
|
</item>'''
|
|
355
355
|
|
|
356
|
+
if not items:
|
|
357
|
+
items = f'''
|
|
358
|
+
<item>
|
|
359
|
+
<title>No results found</title>
|
|
360
|
+
<guid isPermaLink="False">0</guid>
|
|
361
|
+
<link>https://github.com/rix1337/Quasarr</link>
|
|
362
|
+
<comments>No results matched your search criteria.</comments>
|
|
363
|
+
<pubDate>{datetime.now().strftime("%a, %d %b %Y %H:%M:%S +0000")}</pubDate>
|
|
364
|
+
<enclosure url="https://github.com/rix1337/Quasarr" length="0" type="application/x-nzb" />
|
|
365
|
+
</item>'''
|
|
366
|
+
|
|
356
367
|
return f'''<?xml version="1.0" encoding="UTF-8"?>
|
|
357
368
|
<rss>
|
|
358
369
|
<channel>
|
|
@@ -17,9 +17,10 @@ from quasarr.providers.log import info, debug
|
|
|
17
17
|
|
|
18
18
|
hostname = "by"
|
|
19
19
|
supported_mirrors = ["rapidgator", "ddownload", "nitroflare"]
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
RESOLUTION_REGEX = re.compile(r"\d{3,4}p", re.I)
|
|
22
22
|
CODEC_REGEX = re.compile(r"x264|x265|h264|h265|hevc|avc", re.I)
|
|
23
|
+
XXX_REGEX = re.compile(r"\.xxx\.", re.I)
|
|
23
24
|
IMDB_REGEX = re.compile(r"imdb\.com/title/(tt\d+)")
|
|
24
25
|
|
|
25
26
|
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
import re
|
|
6
6
|
import time
|
|
7
7
|
from base64 import urlsafe_b64encode
|
|
8
|
-
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
9
8
|
from datetime import datetime
|
|
10
9
|
from html import unescape
|
|
11
10
|
|
|
@@ -16,7 +15,27 @@ from quasarr.providers.log import info, debug
|
|
|
16
15
|
from quasarr.providers.sessions.dl import retrieve_and_validate_session, invalidate_session, fetch_via_requests_session
|
|
17
16
|
|
|
18
17
|
hostname = "dl"
|
|
19
|
-
|
|
18
|
+
|
|
19
|
+
RESOLUTION_REGEX = re.compile(r"\d{3,4}p", re.I)
|
|
20
|
+
CODEC_REGEX = re.compile(r"x264|x265|h264|h265|hevc|avc", re.I)
|
|
21
|
+
XXX_REGEX = re.compile(r"\.xxx\.", re.I)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def convert_to_rss_date(iso_date_str):
|
|
25
|
+
"""
|
|
26
|
+
Convert ISO format datetime to RSS date format.
|
|
27
|
+
DL date format: '2025-12-15T20:43:06+0100'
|
|
28
|
+
Returns: 'Sun, 15 Dec 2025 20:43:06 +0100'
|
|
29
|
+
Falls back to current time if conversion fails.
|
|
30
|
+
"""
|
|
31
|
+
if not iso_date_str:
|
|
32
|
+
return datetime.now().strftime("%a, %d %b %Y %H:%M:%S +0000")
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
dt_obj = datetime.fromisoformat(iso_date_str)
|
|
36
|
+
return dt_obj.strftime("%a, %d %b %Y %H:%M:%S %z")
|
|
37
|
+
except Exception:
|
|
38
|
+
return datetime.now().strftime("%a, %d %b %Y %H:%M:%S +0000")
|
|
20
39
|
|
|
21
40
|
|
|
22
41
|
def normalize_title_for_sonarr(title):
|
|
@@ -95,21 +114,9 @@ def dl_feed(shared_state, start_time, request_from, mirror=None):
|
|
|
95
114
|
thread_url = f"https://www.{host}{thread_url}"
|
|
96
115
|
|
|
97
116
|
# Extract date and convert to RFC 2822 format
|
|
98
|
-
date_str = None
|
|
99
117
|
date_elem = item.select_one('time.u-dt')
|
|
100
|
-
if date_elem
|
|
101
|
-
|
|
102
|
-
if iso_date:
|
|
103
|
-
try:
|
|
104
|
-
# Parse ISO format and convert to RFC 2822
|
|
105
|
-
dt = datetime.fromisoformat(iso_date.replace('Z', '+00:00'))
|
|
106
|
-
date_str = dt.strftime("%a, %d %b %Y %H:%M:%S %z")
|
|
107
|
-
except Exception:
|
|
108
|
-
date_str = None
|
|
109
|
-
|
|
110
|
-
# Fallback: use current time if no date found
|
|
111
|
-
if not date_str:
|
|
112
|
-
date_str = datetime.now().strftime("%a, %d %b %Y %H:%M:%S %z")
|
|
118
|
+
iso_date = date_elem.get('datetime', '') if date_elem else ''
|
|
119
|
+
published = convert_to_rss_date(iso_date)
|
|
113
120
|
|
|
114
121
|
mb = 0
|
|
115
122
|
imdb_id = None
|
|
@@ -128,7 +135,7 @@ def dl_feed(shared_state, start_time, request_from, mirror=None):
|
|
|
128
135
|
"link": link,
|
|
129
136
|
"mirror": mirror,
|
|
130
137
|
"size": mb * 1024 * 1024,
|
|
131
|
-
"date":
|
|
138
|
+
"date": published,
|
|
132
139
|
"source": thread_url
|
|
133
140
|
},
|
|
134
141
|
"type": "protected"
|
|
@@ -228,6 +235,15 @@ def _search_single_page(shared_state, host, search_string, search_id, page_num,
|
|
|
228
235
|
title = unescape(title)
|
|
229
236
|
title_normalized = normalize_title_for_sonarr(title)
|
|
230
237
|
|
|
238
|
+
# Filter: Skip if no resolution or codec info (unless LazyLibrarian)
|
|
239
|
+
if 'lazylibrarian' not in request_from.lower():
|
|
240
|
+
if not (RESOLUTION_REGEX.search(title_normalized) or CODEC_REGEX.search(title_normalized)):
|
|
241
|
+
continue
|
|
242
|
+
|
|
243
|
+
# Filter: Skip XXX content unless explicitly searched for
|
|
244
|
+
if XXX_REGEX.search(title_normalized) and 'xxx' not in search_string.lower():
|
|
245
|
+
continue
|
|
246
|
+
|
|
231
247
|
thread_url = title_elem.get('href')
|
|
232
248
|
if thread_url.startswith('/'):
|
|
233
249
|
thread_url = f"https://www.{host}{thread_url}"
|
|
@@ -235,16 +251,10 @@ def _search_single_page(shared_state, host, search_string, search_id, page_num,
|
|
|
235
251
|
if not shared_state.is_valid_release(title_normalized, request_from, search_string, season, episode):
|
|
236
252
|
continue
|
|
237
253
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
if
|
|
241
|
-
|
|
242
|
-
if date_elem:
|
|
243
|
-
date_str = date_elem.get('datetime', '')
|
|
244
|
-
|
|
245
|
-
# Fallback: use current time if no date found
|
|
246
|
-
if not date_str:
|
|
247
|
-
date_str = datetime.now().strftime("%a, %d %b %Y %H:%M:%S +0000")
|
|
254
|
+
# Extract date and convert to RFC 2822 format
|
|
255
|
+
date_elem = item.select_one('time.u-dt')
|
|
256
|
+
iso_date = date_elem.get('datetime', '') if date_elem else ''
|
|
257
|
+
published = convert_to_rss_date(iso_date)
|
|
248
258
|
|
|
249
259
|
mb = 0
|
|
250
260
|
password = ""
|
|
@@ -262,7 +272,7 @@ def _search_single_page(shared_state, host, search_string, search_id, page_num,
|
|
|
262
272
|
"link": link,
|
|
263
273
|
"mirror": mirror,
|
|
264
274
|
"size": mb * 1024 * 1024,
|
|
265
|
-
"date":
|
|
275
|
+
"date": published,
|
|
266
276
|
"source": thread_url
|
|
267
277
|
},
|
|
268
278
|
"type": "protected"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|