quasarr 1.22.0__py3-none-any.whl → 1.24.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.

@@ -5,6 +5,7 @@
5
5
  import base64
6
6
  import json
7
7
  import pickle
8
+ import time
8
9
  import urllib.parse
9
10
 
10
11
  import requests
@@ -15,6 +16,8 @@ from quasarr.providers.log import info, debug
15
16
 
16
17
  hostname = "al"
17
18
 
19
+ SESSION_MAX_AGE_SECONDS = 24 * 60 * 60 # 24 hours
20
+
18
21
 
19
22
  def create_and_persist_session(shared_state):
20
23
  cfg = shared_state.values["config"]("Hostnames")
@@ -55,7 +58,7 @@ def create_and_persist_session(shared_state):
55
58
  return None
56
59
 
57
60
  solution = fs_json["solution"]
58
- # store FlareSolverrs UA into our requests.Session
61
+ # store FlareSolverr's UA into our requests.Session
59
62
  fl_ua = solution.get("userAgent")
60
63
  if fl_ua:
61
64
  sess.headers.update({'User-Agent': fl_ua})
@@ -98,16 +101,36 @@ def create_and_persist_session(shared_state):
98
101
  info(f'Missing credentials for: "{hostname}" - skipping login')
99
102
  return None
100
103
 
101
- blob = pickle.dumps(sess)
102
- token = base64.b64encode(blob).decode("utf-8")
103
- shared_state.values["database"]("sessions").update_store(hostname, token)
104
+ _persist_session_to_db(shared_state, sess)
104
105
  return sess
105
106
 
106
107
 
107
108
  def retrieve_and_validate_session(shared_state):
108
109
  db = shared_state.values["database"]("sessions")
109
- token = db.retrieve(hostname)
110
- if not token:
110
+ stored = db.retrieve(hostname)
111
+ if not stored:
112
+ return create_and_persist_session(shared_state)
113
+
114
+ try:
115
+ # Try to parse as JSON (new format with timestamp)
116
+ session_data = json.loads(stored)
117
+ token = session_data.get("token")
118
+ created_at = session_data.get("created_at", 0)
119
+
120
+ # Check if session is older than 24 hours
121
+ age = time.time() - created_at
122
+ if age > SESSION_MAX_AGE_SECONDS:
123
+ debug(f"{hostname}: session expired (age: {age / 3600:.1f} hours)")
124
+ invalidate_session(shared_state)
125
+ return create_and_persist_session(shared_state)
126
+ else:
127
+ debug(f"{hostname}: session valid (age: {age / 3600:.1f} hours)")
128
+
129
+ except (json.JSONDecodeError, TypeError):
130
+ # Legacy format: plain base64 token without timestamp
131
+ # Treat as expired and recreate
132
+ debug(f"{hostname}: legacy session format detected, recreating")
133
+ invalidate_session(shared_state)
111
134
  return create_and_persist_session(shared_state)
112
135
 
113
136
  try:
@@ -131,10 +154,15 @@ def invalidate_session(shared_state):
131
154
  def _persist_session_to_db(shared_state, sess):
132
155
  """
133
156
  Serialize & store the given requests.Session into the database under `hostname`.
157
+ Includes creation timestamp for expiration checking.
134
158
  """
135
159
  blob = pickle.dumps(sess)
136
160
  token = base64.b64encode(blob).decode("utf-8")
137
- shared_state.values["database"]("sessions").update_store(hostname, token)
161
+ session_data = json.dumps({
162
+ "token": token,
163
+ "created_at": time.time()
164
+ })
165
+ shared_state.values["database"]("sessions").update_store(hostname, session_data)
138
166
 
139
167
 
140
168
  def _load_session_cookies_for_flaresolverr(sess):
@@ -177,13 +205,13 @@ def fetch_via_flaresolverr(shared_state,
177
205
  Load (or recreate) the requests.Session from DB.
178
206
  Package its cookies into FlareSolverr payload.
179
207
  Ask FlareSolverr to do a request.get or request.post on target_url.
180
- Replace the Sessions cookies with FlareSolverrs new cookies.
208
+ Replace the Session's cookies with FlareSolverr's new cookies.
181
209
  Re-persist the updated session to the DB.
182
- Return a dict with status_code”, headers”, json (parsed - if available), text and cookies”.
210
+ Return a dict with "status_code", "headers", "json" (parsed - if available), "text" and "cookies".
183
211
 
184
212
  – method: "GET" or "POST"
185
213
  – post_data: dict of form‐fields if method=="POST"
186
- – timeout: seconds (FlareSolverrs internal maxTimeout = timeout*1000 ms)
214
+ – timeout: seconds (FlareSolverr's internal maxTimeout = timeout*1000 ms)
187
215
  """
188
216
  flaresolverr_url = shared_state.values["config"]('FlareSolverr').get('url')
189
217
 
@@ -8,7 +8,7 @@ import requests
8
8
 
9
9
 
10
10
  def get_version():
11
- return "1.22.0"
11
+ return "1.24.0"
12
12
 
13
13
 
14
14
  def get_latest_version():
@@ -291,8 +291,8 @@ def _search_single_page(shared_state, host, search_string, search_id, page_num,
291
291
  def dl_search(shared_state, start_time, request_from, search_string,
292
292
  mirror=None, season=None, episode=None):
293
293
  """
294
- Search with sequential pagination (max 5 pages) to find best quality releases.
295
- Stops searching if a page returns 0 results.
294
+ Search with sequential pagination to find best quality releases.
295
+ Stops searching if a page returns 0 results or 10 seconds have elapsed.
296
296
  """
297
297
  releases = []
298
298
  host = shared_state.values["config"]("Hostnames").get(hostname)
@@ -306,10 +306,10 @@ def dl_search(shared_state, start_time, request_from, search_string,
306
306
  search_string = title
307
307
 
308
308
  search_string = unescape(search_string)
309
- max_pages = 5
309
+ max_search_duration = 10
310
310
 
311
311
  debug(
312
- f"{hostname}: Starting sequential paginated search for '{search_string}' (Season: {season}, Episode: {episode}) - up to {max_pages} pages")
312
+ f"{hostname}: Starting sequential paginated search for '{search_string}' (Season: {season}, Episode: {episode}) - max {max_search_duration}s")
313
313
 
314
314
  try:
315
315
  sess = retrieve_and_validate_session(shared_state)
@@ -318,9 +318,13 @@ def dl_search(shared_state, start_time, request_from, search_string,
318
318
  return releases
319
319
 
320
320
  search_id = None
321
+ page_num = 0
322
+ search_start_time = time.time()
323
+
324
+ # Sequential search through pages until timeout or no results
325
+ while (time.time() - search_start_time) < max_search_duration:
326
+ page_num += 1
321
327
 
322
- # Sequential search through pages
323
- for page_num in range(1, max_pages + 1):
324
328
  page_releases, extracted_search_id = _search_single_page(
325
329
  shared_state, host, search_string, search_id, page_num,
326
330
  imdb_id, mirror, request_from, season, episode
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quasarr
3
- Version: 1.22.0
3
+ Version: 1.24.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
@@ -44,7 +44,7 @@ Alternatively, follow the link from the console output (or discord notification)
44
44
  Quasarr will confidently handle the rest.
45
45
 
46
46
  # Instructions
47
- 1. Set up and run [FlareSolverr](https://github.com/FlareSolverr/FlareSolverr) 3.4.4 or later.
47
+ 1. Set up and run [FlareSolverr 3](https://github.com/FlareSolverr/FlareSolverr).
48
48
  2. Set up and run [JDownloader 2](https://jdownloader.org/download/index).
49
49
  3. Follow the next steps.
50
50
 
@@ -1,33 +1,33 @@
1
1
  quasarr/__init__.py,sha256=4-EVvIdDjMqidqp3xpXfcDl-fSe0J_B415ueZDAKBss,18137
2
2
  quasarr/api/__init__.py,sha256=9Y_DTNYsHeimrXL3mAli8OUg0zqo7QGLF2ft40d3R-c,6822
3
3
  quasarr/api/arr/__init__.py,sha256=-e7Sge8mzQCtxlixY2pEJ2p2wQ06TckaczFPUZWCz3c,17361
4
- quasarr/api/captcha/__init__.py,sha256=wZzdEZCuUDv-8Dcxu5GD5bV0M6WV_x2Z7-2GoyLhp6o,52341
4
+ quasarr/api/captcha/__init__.py,sha256=E9QUmsI61ubiQRcbSknXT-Yhf_mH6fWaMwRPVYWcb9s,55119
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=AGZcafQG7ZKLadYaWmR0HR3lljt-l00llWw3G39Y9vA,13345
8
+ quasarr/downloads/__init__.py,sha256=ZcX-PzMU8Dio8FOIk0PEYxuMgR31ohUS6dZteOunZ08,11555
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
12
12
  quasarr/downloads/linkcrypters/hide.py,sha256=kMxjsYZJpC1V3jwYv9b0h4HKBIectLlgglwOmexvFXs,4107
13
13
  quasarr/downloads/packages/__init__.py,sha256=Cub3ztyFYBm30HprvZl7qvfYnjaOH9FsRWDLEyCPHkE,18305
14
14
  quasarr/downloads/sources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- quasarr/downloads/sources/al.py,sha256=Ulc4fTuX8_gOHeTJzZYEAgUCiFPoyczIdbZh6qA3jzM,26180
16
- quasarr/downloads/sources/by.py,sha256=VzytGYyy81vjsvNJabohoK8PkjYTKCwXM1TjeD3Ker0,3695
17
- quasarr/downloads/sources/dd.py,sha256=EQ823wrVusVCVJhh9Rdf67-Yae9XYio8Uj_HW_y5qO0,2841
18
- quasarr/downloads/sources/dj.py,sha256=b_RR_dqd4Zc9lbZbZbwZijDkXCb42OaU7eOAI4lX9EE,214
19
- quasarr/downloads/sources/dl.py,sha256=GfrNypsTRhjuXv7cYcHFzXQLE28sf4-Rb9k7znP0MfQ,7575
20
- quasarr/downloads/sources/dt.py,sha256=fzAyJy8nmqTAFRObvaRbvsXdBkCo5JuojCJYQMYuPOs,2108
21
- quasarr/downloads/sources/dw.py,sha256=15UH-kBZt06GS5CDi-TTJGV_H59mQO0Nl-y3nYA5kOk,2504
22
- quasarr/downloads/sources/he.py,sha256=EZ42WIHE8rwvpvwesaWeG__1dUBq75OQzJ1n7Lgrx1g,3450
23
- quasarr/downloads/sources/mb.py,sha256=IS5_RdACD3yterFEAj_N7RIH4TVK-VEauZqfya23hmA,1411
24
- quasarr/downloads/sources/nk.py,sha256=qA1qIOthu-Jt93ykPzE-gvSFEfA5YSIMNDymIWD98Tc,1538
25
- quasarr/downloads/sources/nx.py,sha256=nI0c-oM1g_EyW06_o2wFgn_jm_Zh1XMy3kbRCN0hw1E,3211
26
- quasarr/downloads/sources/sf.py,sha256=PDBuWgJmEYmD1b-5blS3YWgrqIhJjfwz91IuiMy6rX8,6224
27
- quasarr/downloads/sources/sj.py,sha256=d2HC52SFYXUXAr7AIaipthVvL-WpvJaD-8AuN-5Z-I8,214
28
- quasarr/downloads/sources/sl.py,sha256=w6Mo1dphrZRlXfhBfAhFV8KcPfHINuTiFSNu3BYd46k,2851
29
- quasarr/downloads/sources/wd.py,sha256=NOilEZIF9rumU2LMtfRfXyet3Mzn2shCs8NFCEC3CHY,3747
30
- quasarr/downloads/sources/wx.py,sha256=lufMZYNniKWj2x2mfYsEkGw_Qqi3TWg66EgU3uP9TiI,4769
15
+ quasarr/downloads/sources/al.py,sha256=tb7HpMWFnW3VZCAjsk4tFZsh56xygDVmPgpv5cW1q1M,26942
16
+ quasarr/downloads/sources/by.py,sha256=kmUTn3izayRCV7W-t0E4kYE8qTbt3L3reCLozfvRGcU,3807
17
+ quasarr/downloads/sources/dd.py,sha256=8X2tOle3qTq0b60Aa3o0uqp2vNELDHYYj99ERI7U_X0,2971
18
+ quasarr/downloads/sources/dj.py,sha256=wY00hVRNhucZBG1hfExKqayhP1ISD8FFQm7wHYxutOk,404
19
+ quasarr/downloads/sources/dl.py,sha256=-8q3vjgdmLykptLtcehB7NLCAn5YANGWRDrLJu2Xg00,7174
20
+ quasarr/downloads/sources/dt.py,sha256=80yIHAivsqoPKAaFdZ4wPFBVGCbHNUO130pv7EO2LTM,2605
21
+ quasarr/downloads/sources/dw.py,sha256=_28-E58Hs9NVwHyLt2M1oYUxVZ-wpE5dQv8gMNhiAPM,2622
22
+ quasarr/downloads/sources/he.py,sha256=AA6OrIkD3KS_w1ClvXyW1_9hujM6A8P_5VcMHRM6ngg,3680
23
+ quasarr/downloads/sources/mb.py,sha256=bW0ahVOi1OAk8ah1-a2v8d8l9CQgaHP5d3Y_NbA5g2c,1538
24
+ quasarr/downloads/sources/nk.py,sha256=Y7MDbReToxayADrG18_SDPMD8XUbgRP1IV6gd3ITUlA,1716
25
+ quasarr/downloads/sources/nx.py,sha256=ESWGDz07m2kntvTGoNlL9Gleld-HUl9ckphaJA9PUbk,3758
26
+ quasarr/downloads/sources/sf.py,sha256=ecPHNsNiRNXTfQX9MBLzJKqrEc1IpkrKkBXpihTPhkE,6352
27
+ quasarr/downloads/sources/sj.py,sha256=Bkv0c14AXct50n_viaTNK3bYG-Bpvx8x2D0UN_6gm78,404
28
+ quasarr/downloads/sources/sl.py,sha256=jWprFt1Hew1T67fB1O_pc9YWgc3NVh30KXSwSyS50Pc,3186
29
+ quasarr/downloads/sources/wd.py,sha256=0FzfLaUUdrnoybWlTxszmT5a38j9KrlLGhkLNeEuIQ8,3905
30
+ quasarr/downloads/sources/wx.py,sha256=EygMfkgBMZYj3tSk4gvj5DcojkRswGhY_y8FMPNnVeU,4834
31
31
  quasarr/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
32
  quasarr/providers/cloudflare.py,sha256=mJxTYM7JjwIjdO6U_GyVj-dyug6XdD0-ObkYTaPtFVg,7028
33
33
  quasarr/providers/html_images.py,sha256=CvJgBs_M5ziTI-ccSQheI7FC1pZWY52R9Elq5WuBwfY,46481
@@ -36,13 +36,13 @@ quasarr/providers/imdb_metadata.py,sha256=10L4kZkt6Fg0HGdNcc6KCtIQHRYEqdarLyaMVN
36
36
  quasarr/providers/log.py,sha256=_g5RwtfuksARXnvryhsngzoJyFcNzj6suqd3ndqZM0Y,313
37
37
  quasarr/providers/myjd_api.py,sha256=Z3PEiO3c3UfDSr4Up5rgwTAnjloWHb-H1RkJ6BLKZv8,34140
38
38
  quasarr/providers/notifications.py,sha256=bohT-6yudmFnmZMc3BwCGX0n1HdzSVgQG_LDZm_38dI,4630
39
- quasarr/providers/obfuscated.py,sha256=RgIY4QEcipiGlHaGodaqjFJSjv5sbVXoFu8QGGlWER0,253438
39
+ quasarr/providers/obfuscated.py,sha256=i4qoNNpwAVIjiLIhnPPBQJvmZr1ZRCPVYm1uChhY9gg,310748
40
40
  quasarr/providers/shared_state.py,sha256=1NUKtm9YXWPvN64By2O2OYH5ke5TmBkJSbSxiNczgtU,29849
41
41
  quasarr/providers/statistics.py,sha256=cEQixYnDMDqtm5wWe40E_2ucyo4mD0n3SrfelhQi1L8,6452
42
- quasarr/providers/version.py,sha256=mjHQH88QURuF6A8EIUX1rCB6pgEQkJ8pGYsk9z24wSI,4004
42
+ quasarr/providers/version.py,sha256=eWfcJssPvgMn9yme0FOgOwBsMWV-m_wgBqquHsd77gc,4004
43
43
  quasarr/providers/web_server.py,sha256=XPj98T-axxgotovuB-rVw1IPCkJiNdXBlEeFvM_zSlM,1432
44
44
  quasarr/providers/sessions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
- quasarr/providers/sessions/al.py,sha256=mlP6SWfCY2HyOSV40uyotQ5T4eSBNYG9A5GWOEAdz-c,9589
45
+ quasarr/providers/sessions/al.py,sha256=F1d76eAJcbTvb6YvAIlQ4gfrYC_256QAKiWEQcuWe8k,10612
46
46
  quasarr/providers/sessions/dd.py,sha256=JdXjqmjuyY32w0cIlwphRm8Sy43EK8nEEFwyXUkEGb4,2596
47
47
  quasarr/providers/sessions/dl.py,sha256=8toAHn5C9FbjHuhjfQEeKR1Fz5tRENrIgFxdjUuXCIU,5381
48
48
  quasarr/providers/sessions/nx.py,sha256=qfW12AB_0nNsAoKOaSF4z0T9DCxMQleWCYf3fqJtF2A,2688
@@ -52,7 +52,7 @@ quasarr/search/sources/al.py,sha256=yr6wx-VcSOFYK_o3N1bepC4t6Gvt9eDvcG9fQBFg0bg,
52
52
  quasarr/search/sources/by.py,sha256=vnE3L43V8suPhPHcn6LVxKO1e3mJaDRqIIMg2BGxr_g,7915
53
53
  quasarr/search/sources/dd.py,sha256=pVpdHLZlw2CYklBf_YLkeDWbCNsDLR2iecccR2c2RyI,4889
54
54
  quasarr/search/sources/dj.py,sha256=2HIdg5ddXP4DtjHlyXmuQ8QVhOPt3Hh2kL4uxhFJK-8,7074
55
- quasarr/search/sources/dl.py,sha256=n7WYKWLLftbNL3uBcGM0n2VaTKspNLfFOTJK3YfkVXw,12375
55
+ quasarr/search/sources/dl.py,sha256=LLA2Pq0PT7ZzhWCueL22d8bm48AJhL6BEmSnmkLHUTk,12540
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
@@ -69,9 +69,9 @@ 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=Gf7e125KlHsyu-hhq3uFfH7N6i7-8DDONGcYJX0haLs,18261
71
71
  quasarr/storage/sqlite_database.py,sha256=yMqFQfKf0k7YS-6Z3_7pj4z1GwWSXJ8uvF4IydXsuTE,3554
72
- quasarr-1.22.0.dist-info/licenses/LICENSE,sha256=QQFCAfDgt7lSA8oSWDHIZ9aTjFbZaBJdjnGOHkuhK7k,1060
73
- quasarr-1.22.0.dist-info/METADATA,sha256=KT88JosXSAVCc9gSs6wxJ0Ge1qG0Ouy_ULm-pAE_R_o,12743
74
- quasarr-1.22.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
75
- quasarr-1.22.0.dist-info/entry_points.txt,sha256=gXi8mUKsIqKVvn-bOc8E5f04sK_KoMCC-ty6b2Hf-jc,40
76
- quasarr-1.22.0.dist-info/top_level.txt,sha256=dipJdaRda5ruTZkoGfZU60bY4l9dtPlmOWwxK_oGSF0,8
77
- quasarr-1.22.0.dist-info/RECORD,,
72
+ quasarr-1.24.0.dist-info/licenses/LICENSE,sha256=QQFCAfDgt7lSA8oSWDHIZ9aTjFbZaBJdjnGOHkuhK7k,1060
73
+ quasarr-1.24.0.dist-info/METADATA,sha256=y6ukkkj66F8rQDNFwHxQOK2y6rBBwZFziFH8LaTyDu8,12730
74
+ quasarr-1.24.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
75
+ quasarr-1.24.0.dist-info/entry_points.txt,sha256=gXi8mUKsIqKVvn-bOc8E5f04sK_KoMCC-ty6b2Hf-jc,40
76
+ quasarr-1.24.0.dist-info/top_level.txt,sha256=dipJdaRda5ruTZkoGfZU60bY4l9dtPlmOWwxK_oGSF0,8
77
+ quasarr-1.24.0.dist-info/RECORD,,