quasarr 1.26.4__py3-none-any.whl → 1.26.6__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/__init__.py CHANGED
@@ -10,8 +10,9 @@ import socket
10
10
  import sys
11
11
  import tempfile
12
12
  import time
13
- from urllib.parse import urlparse
13
+ from urllib.parse import urlparse, urljoin, parse_qs
14
14
 
15
+ import dukpy
15
16
  import requests
16
17
 
17
18
  from quasarr.api import get_api
@@ -117,16 +118,21 @@ def run():
117
118
  print("\n===== Hostnames =====")
118
119
  try:
119
120
  if arguments.hostnames:
120
- hostnames_link = make_raw_pastebin_link(arguments.hostnames)
121
-
121
+ hostnames_link = arguments.hostnames
122
122
  if is_valid_url(hostnames_link):
123
+ if "pastebin.com" in hostnames_link:
124
+ hostnames_link = make_raw_pastebin_link(hostnames_link)
125
+
123
126
  print(f"Extracting hostnames from {hostnames_link}...")
124
127
  allowed_keys = supported_hostnames
125
128
  max_keys = len(allowed_keys)
126
129
  shorthand_list = ', '.join(
127
130
  [f'"{key}"' for key in allowed_keys[:-1]]) + ' and ' + f'"{allowed_keys[-1]}"'
128
131
  print(f'There are up to {max_keys} hostnames currently supported: {shorthand_list}')
129
- data = requests.get(hostnames_link).text
132
+ if "/ini.html" in hostnames_link:
133
+ data = build_ini_from_ini_html(hostnames_link)
134
+ else:
135
+ data = requests.get(hostnames_link).text
130
136
  results = extract_kv_pairs(data, allowed_keys)
131
137
 
132
138
  extracted_hostnames = 0
@@ -413,6 +419,35 @@ def make_raw_pastebin_link(url):
413
419
  return url # Not a Pastebin link, return unchanged
414
420
 
415
421
 
422
+ def build_ini_from_ini_html(url: str) -> str:
423
+ def get(u: str) -> str:
424
+ r = requests.get(u, timeout=10)
425
+ r.raise_for_status()
426
+ return r.text
427
+
428
+ parsed = urlparse(url)
429
+ params = parse_qs(parsed.query)
430
+
431
+ data_js = get(urljoin(f"{parsed.scheme}://{parsed.netloc}", "data.js"))
432
+
433
+ hostnames = dukpy.evaljs("""
434
+ var window = {};
435
+ %s
436
+ window.HOSTNAMES;
437
+ """ % data_js)
438
+
439
+ excluded = set()
440
+ if "exclude" in params:
441
+ excluded = set(params["exclude"][0].split(","))
442
+
443
+ lines = []
444
+ for h in hostnames:
445
+ if h["key"] not in excluded:
446
+ lines.append(f"{h['key']} = {h['name']}")
447
+
448
+ return "\n".join(lines) + "\n"
449
+
450
+
416
451
  def is_valid_url(url):
417
452
  if "https://pastebin.com/raw/eX4Mpl3" in url:
418
453
  print("Example URL detected. Please provide a valid URL found on pastebin or another public site!")
@@ -353,7 +353,8 @@ 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:
356
+ is_feed_request = not getattr(request.query, 'imdbid', '')
357
+ if is_feed_request and not items:
357
358
  items = f'''
358
359
  <item>
359
360
  <title>No results found</title>
@@ -8,7 +8,7 @@ import requests
8
8
 
9
9
 
10
10
  def get_version():
11
- return "1.26.4"
11
+ return "1.26.6"
12
12
 
13
13
 
14
14
  def get_latest_version():
@@ -90,6 +90,12 @@ def he_search(shared_state, start_time, request_from, search_string="", mirror=N
90
90
  else:
91
91
  imdb_id = None
92
92
 
93
+ if season:
94
+ source_search += f" S{int(season):02d}"
95
+
96
+ if episode:
97
+ source_search += f"E{int(episode):02d}"
98
+
93
99
  url = f'https://{host}/tag/{tag}/'
94
100
 
95
101
  headers = {"User-Agent": shared_state.values["user_agent"]}
@@ -81,6 +81,12 @@ def nk_search(shared_state, start_time, request_from, search_string="", mirror=N
81
81
  else:
82
82
  imdb_id = None
83
83
 
84
+ if season:
85
+ source_search += f" S{int(season):02d}"
86
+
87
+ if episode:
88
+ source_search += f"E{int(episode):02d}"
89
+
84
90
  url = f'https://{host}/search'
85
91
  headers = {"User-Agent": shared_state.values["user_agent"]}
86
92
  data = {"search": source_search}
@@ -52,7 +52,7 @@ def wx_feed(shared_state, start_time, request_from, mirror=None):
52
52
  items = soup.find_all('item')
53
53
 
54
54
  if not items:
55
- debug(f"{hostname.upper()}: No entries found in RSS feed")
55
+ info(f"{hostname.upper()}: No entries found in RSS feed")
56
56
  return releases
57
57
 
58
58
  debug(f"{hostname.upper()}: Found {len(items)} entries in RSS feed")
@@ -141,15 +141,15 @@ def wx_search(shared_state, start_time, request_from, search_string, mirror=None
141
141
 
142
142
  imdb_id = shared_state.is_imdb_id(search_string)
143
143
  if imdb_id:
144
- info(f"{hostname.upper()}: Received IMDb ID: {imdb_id}")
144
+ debug(f"{hostname.upper()}: Received IMDb ID: {imdb_id}")
145
145
  title = get_localized_title(shared_state, imdb_id, 'de')
146
146
  if not title:
147
- info(f"{hostname.upper()}: no title for IMDb {imdb_id}")
147
+ debug(f"{hostname.upper()}: no title for IMDb {imdb_id}")
148
148
  return releases
149
- info(f"{hostname.upper()}: Translated IMDb {imdb_id} to German title: '{title}'")
149
+ debug(f"{hostname.upper()}: Translated IMDb {imdb_id} to German title: '{title}'")
150
150
  search_string = html.unescape(title)
151
151
  else:
152
- info(f"{hostname.upper()}: Using search string directly: '{search_string}'")
152
+ debug(f"{hostname.upper()}: Using search string directly: '{search_string}'")
153
153
 
154
154
  api_url = f'https://api.{host}/start/search'
155
155
 
@@ -179,13 +179,13 @@ def wx_search(shared_state, start_time, request_from, search_string, mirror=None
179
179
  elif "radarr" in request_from.lower():
180
180
  params['types'] = 'movie'
181
181
 
182
- info(f"{hostname.upper()}: Searching: '{search_string}'")
182
+ debug(f"{hostname.upper()}: Searching: '{search_string}'")
183
183
 
184
184
  try:
185
185
  response = requests.get(api_url, headers=headers, params=params, timeout=10)
186
186
 
187
187
  if response.status_code != 200:
188
- info(f"{hostname.upper()}: Search API returned status {response.status_code}")
188
+ debug(f"{hostname.upper()}: Search API returned status {response.status_code}")
189
189
  return releases
190
190
 
191
191
  data = response.json()
@@ -199,7 +199,7 @@ def wx_search(shared_state, start_time, request_from, search_string, mirror=None
199
199
  else:
200
200
  items = data if isinstance(data, list) else []
201
201
 
202
- info(f"{hostname.upper()}: Found {len(items)} items in search results")
202
+ debug(f"{hostname.upper()}: Found {len(items)} items in search results")
203
203
 
204
204
  for item in items:
205
205
  try:
@@ -208,7 +208,7 @@ def wx_search(shared_state, start_time, request_from, search_string, mirror=None
208
208
  debug(f"{hostname.upper()}: Item has no UID, skipping")
209
209
  continue
210
210
 
211
- info(f"{hostname.upper()}: Fetching details for UID: {uid}")
211
+ debug(f"{hostname.upper()}: Fetching details for UID: {uid}")
212
212
 
213
213
  detail_url = f'https://api.{host}/start/d/{uid}'
214
214
  detail_response = requests.get(detail_url, headers=headers, timeout=10)
@@ -263,7 +263,7 @@ def wx_search(shared_state, start_time, request_from, search_string, mirror=None
263
263
  })
264
264
 
265
265
  if 'releases' in detail_item and isinstance(detail_item['releases'], list):
266
- info(f"{hostname.upper()}: Found {len(detail_item['releases'])} releases for {uid}")
266
+ debug(f"{hostname.upper()}: Found {len(detail_item['releases'])} releases for {uid}")
267
267
 
268
268
  for release in detail_item['releases']:
269
269
  try:
@@ -323,7 +323,7 @@ def wx_search(shared_state, start_time, request_from, search_string, mirror=None
323
323
  debug(f"{hostname.upper()}: {traceback.format_exc()}")
324
324
  continue
325
325
 
326
- info(f"{hostname.upper()}: Returning {len(releases)} total releases")
326
+ debug(f"{hostname.upper()}: Returning {len(releases)} total releases")
327
327
 
328
328
  except Exception as e:
329
329
  info(f"Error in {hostname.upper()} search: {e}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quasarr
3
- Version: 1.26.4
3
+ Version: 1.26.6
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
@@ -1,6 +1,6 @@
1
- quasarr/__init__.py,sha256=4-EVvIdDjMqidqp3xpXfcDl-fSe0J_B415ueZDAKBss,18137
1
+ quasarr/__init__.py,sha256=BslVqfYcaIHJ-oE96ZvRN-7fLCs4cg8LqYwS19u06Kg,19133
2
2
  quasarr/api/__init__.py,sha256=9Y_DTNYsHeimrXL3mAli8OUg0zqo7QGLF2ft40d3R-c,6822
3
- quasarr/api/arr/__init__.py,sha256=-e7Sge8mzQCtxlixY2pEJ2p2wQ06TckaczFPUZWCz3c,17361
3
+ quasarr/api/arr/__init__.py,sha256=6CFASudVLlqKVNhTnS72Np2T3uAMsJXE-8u0986WW9c,17460
4
4
  quasarr/api/captcha/__init__.py,sha256=IhJVn9iWtb01P2yfoqtOF7wSsiXizES7HNn29BX1uHk,60268
5
5
  quasarr/api/config/__init__.py,sha256=0K7zqC9dt39Ul1RIJt0zNVdh1b9ARnfC6QFPa2D9FCw,819
6
6
  quasarr/api/sponsors_helper/__init__.py,sha256=kAZabPlplPYRG6Uw7ZHTk5uypualwvhs-NoTOjQhhhA,6369
@@ -39,7 +39,7 @@ quasarr/providers/notifications.py,sha256=bohT-6yudmFnmZMc3BwCGX0n1HdzSVgQG_LDZm
39
39
  quasarr/providers/obfuscated.py,sha256=xPI3WrteOiZN5BgNDp0CURcYfkRrdnRCz_cT7BpzIJU,1363310
40
40
  quasarr/providers/shared_state.py,sha256=-TIiH2lkCfovq7bzUZicpUjXEjS87ZHCcevsFgySOqw,29944
41
41
  quasarr/providers/statistics.py,sha256=cEQixYnDMDqtm5wWe40E_2ucyo4mD0n3SrfelhQi1L8,6452
42
- quasarr/providers/version.py,sha256=GAEHoTd_JPGHtyBwvxPAOOhjEUro28TLorMoV9n2yXs,4004
42
+ quasarr/providers/version.py,sha256=zYvFuXh_gULofghR4rNtgM1zf9PIjQ0lywLhM41ee74,4004
43
43
  quasarr/providers/web_server.py,sha256=AYd0KRxdDWMBr87BP8wlSMuL4zZo0I_rY-vHBai6Pfg,1688
44
44
  quasarr/providers/sessions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
45
  quasarr/providers/sessions/al.py,sha256=F1d76eAJcbTvb6YvAIlQ4gfrYC_256QAKiWEQcuWe8k,10612
@@ -56,22 +56,22 @@ quasarr/search/sources/dl.py,sha256=Ci1OvOppZ_mJ6esA9qvWd_NQfN-FEK8lWhkev7W-JP8,
56
56
  quasarr/search/sources/dt.py,sha256=m1kQ7mC43QlWZyVIkw-OXJGjWiT9IbQuFtHWiR8CjhA,9580
57
57
  quasarr/search/sources/dw.py,sha256=-daUTBTA5izeatrE7TITVlnzNCQ5HfovYMMZ8UTM-2o,7636
58
58
  quasarr/search/sources/fx.py,sha256=JAyD727yDAFIP14bzfi2SkX9paysXGkQdIybShYtdko,8596
59
- quasarr/search/sources/he.py,sha256=ieBVlpd4nRonZyocV1kDlxIjgfWspspbspLS04PDQkQ,6503
59
+ quasarr/search/sources/he.py,sha256=niow7YCqgEHD3PiushIED5EkY6E8ItBxKXzWdSCUq4g,6632
60
60
  quasarr/search/sources/mb.py,sha256=owwH5T0Yh7dwYRqMVQ0ecAdDlQ5CwLwWkTcig2ePggI,7749
61
- quasarr/search/sources/nk.py,sha256=x84zckK8eG64X3oaPHYhNbK0aoSuVW8xp_n_mlE__NI,6427
61
+ quasarr/search/sources/nk.py,sha256=lRBGqigCpm1fCnb3WlaLHkuu9kYhERI9WIUwvRNJKsI,6556
62
62
  quasarr/search/sources/nx.py,sha256=JdRLA2pWS05m5_ARU-RxAoaBW-8YWEoUN2RebyD2ejo,6981
63
63
  quasarr/search/sources/sf.py,sha256=3z_fvcafOh7U4D_vgq9yC8ktKeazI9fiAi96hCeXb5Q,14869
64
64
  quasarr/search/sources/sj.py,sha256=JRzoCDohClmGH7aXOz82KVUt6pZsZoBDBXvwvQrAijM,7074
65
65
  quasarr/search/sources/sl.py,sha256=5e5S7JvdbNOc2EthyOkfC4aTpG8O7fn4WS2O3_EXjnM,9463
66
66
  quasarr/search/sources/wd.py,sha256=O02j3irSlVw2qES82g_qHuavAk-njjSRH1dHSCnOUas,7540
67
- quasarr/search/sources/wx.py,sha256=HIGElGKoBkxBdgoYiaC70T4Y22xRUmgMzzbJpFq1cxw,12897
67
+ quasarr/search/sources/wx.py,sha256=_h1M6GhkJzixwHscrt0lMOnPSEDP1Xl24OypEe8Jy7c,12906
68
68
  quasarr/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
69
69
  quasarr/storage/config.py,sha256=hOI7vvIo1YaML3dtAkTmp0HSedWF6brVhRk3d8pJtXI,6300
70
70
  quasarr/storage/setup.py,sha256=V_dWfyCYxRE_ahmBtD-DmHOKP2L6brBcVYydPRcHjns,21448
71
71
  quasarr/storage/sqlite_database.py,sha256=yMqFQfKf0k7YS-6Z3_7pj4z1GwWSXJ8uvF4IydXsuTE,3554
72
- quasarr-1.26.4.dist-info/licenses/LICENSE,sha256=QQFCAfDgt7lSA8oSWDHIZ9aTjFbZaBJdjnGOHkuhK7k,1060
73
- quasarr-1.26.4.dist-info/METADATA,sha256=WctqxWiUX7TalmsjliMVQoB1cQmT3kmCF4pYqJ7KsCk,12805
74
- quasarr-1.26.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
75
- quasarr-1.26.4.dist-info/entry_points.txt,sha256=gXi8mUKsIqKVvn-bOc8E5f04sK_KoMCC-ty6b2Hf-jc,40
76
- quasarr-1.26.4.dist-info/top_level.txt,sha256=dipJdaRda5ruTZkoGfZU60bY4l9dtPlmOWwxK_oGSF0,8
77
- quasarr-1.26.4.dist-info/RECORD,,
72
+ quasarr-1.26.6.dist-info/licenses/LICENSE,sha256=QQFCAfDgt7lSA8oSWDHIZ9aTjFbZaBJdjnGOHkuhK7k,1060
73
+ quasarr-1.26.6.dist-info/METADATA,sha256=M7gOmlAC-bEd8ZoJIhQ8AeRhPSkeHspdavJMp4pYI7o,12805
74
+ quasarr-1.26.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
75
+ quasarr-1.26.6.dist-info/entry_points.txt,sha256=gXi8mUKsIqKVvn-bOc8E5f04sK_KoMCC-ty6b2Hf-jc,40
76
+ quasarr-1.26.6.dist-info/top_level.txt,sha256=dipJdaRda5ruTZkoGfZU60bY4l9dtPlmOWwxK_oGSF0,8
77
+ quasarr-1.26.6.dist-info/RECORD,,