quasarr 1.17.1__tar.gz → 1.17.3__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.

Files changed (70) hide show
  1. {quasarr-1.17.1 → quasarr-1.17.3}/PKG-INFO +1 -1
  2. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/api/captcha/__init__.py +172 -23
  3. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/providers/version.py +1 -1
  4. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr.egg-info/PKG-INFO +1 -1
  5. {quasarr-1.17.1 → quasarr-1.17.3}/LICENSE +0 -0
  6. {quasarr-1.17.1 → quasarr-1.17.3}/README.md +0 -0
  7. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/__init__.py +0 -0
  8. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/api/__init__.py +0 -0
  9. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/api/arr/__init__.py +0 -0
  10. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/api/config/__init__.py +0 -0
  11. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/api/sponsors_helper/__init__.py +0 -0
  12. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/api/statistics/__init__.py +0 -0
  13. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/downloads/__init__.py +0 -0
  14. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/downloads/linkcrypters/__init__.py +0 -0
  15. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/downloads/linkcrypters/al.py +0 -0
  16. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/downloads/linkcrypters/filecrypt.py +0 -0
  17. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/downloads/linkcrypters/hide.py +0 -0
  18. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/downloads/packages/__init__.py +0 -0
  19. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/downloads/sources/__init__.py +0 -0
  20. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/downloads/sources/al.py +0 -0
  21. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/downloads/sources/by.py +0 -0
  22. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/downloads/sources/dd.py +0 -0
  23. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/downloads/sources/dt.py +0 -0
  24. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/downloads/sources/dw.py +0 -0
  25. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/downloads/sources/mb.py +0 -0
  26. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/downloads/sources/nx.py +0 -0
  27. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/downloads/sources/sf.py +0 -0
  28. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/downloads/sources/sl.py +0 -0
  29. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/downloads/sources/wd.py +0 -0
  30. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/providers/__init__.py +0 -0
  31. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/providers/cloudflare.py +0 -0
  32. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/providers/html_images.py +0 -0
  33. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/providers/html_templates.py +0 -0
  34. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/providers/imdb_metadata.py +0 -0
  35. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/providers/log.py +0 -0
  36. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/providers/myjd_api.py +0 -0
  37. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/providers/notifications.py +0 -0
  38. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/providers/obfuscated.py +0 -0
  39. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/providers/sessions/__init__.py +0 -0
  40. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/providers/sessions/al.py +0 -0
  41. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/providers/sessions/dd.py +0 -0
  42. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/providers/sessions/nx.py +0 -0
  43. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/providers/shared_state.py +0 -0
  44. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/providers/statistics.py +0 -0
  45. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/providers/web_server.py +0 -0
  46. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/search/__init__.py +0 -0
  47. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/search/sources/__init__.py +0 -0
  48. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/search/sources/al.py +0 -0
  49. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/search/sources/by.py +0 -0
  50. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/search/sources/dd.py +0 -0
  51. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/search/sources/dt.py +0 -0
  52. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/search/sources/dw.py +0 -0
  53. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/search/sources/fx.py +0 -0
  54. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/search/sources/mb.py +0 -0
  55. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/search/sources/nx.py +0 -0
  56. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/search/sources/sf.py +0 -0
  57. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/search/sources/sl.py +0 -0
  58. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/search/sources/wd.py +0 -0
  59. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/storage/__init__.py +0 -0
  60. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/storage/config.py +0 -0
  61. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/storage/setup.py +0 -0
  62. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr/storage/sqlite_database.py +0 -0
  63. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr.egg-info/SOURCES.txt +0 -0
  64. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr.egg-info/dependency_links.txt +0 -0
  65. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr.egg-info/entry_points.txt +0 -0
  66. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr.egg-info/not-zip-safe +0 -0
  67. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr.egg-info/requires.txt +0 -0
  68. {quasarr-1.17.1 → quasarr-1.17.3}/quasarr.egg-info/top_level.txt +0 -0
  69. {quasarr-1.17.1 → quasarr-1.17.3}/setup.cfg +0 -0
  70. {quasarr-1.17.1 → quasarr-1.17.3}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quasarr
3
- Version: 1.17.1
3
+ Version: 1.17.3
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
@@ -103,32 +103,180 @@ def setup_captcha_routes(app):
103
103
 
104
104
  def render_bypass_section(url, package_id, title, password):
105
105
  """Render the bypass UI section for both cutcaptcha and circle captcha pages"""
106
+
107
+ # Generate userscript URL with transfer params
108
+ # Get base URL of current request
109
+ base_url = request.urlparts.scheme + '://' + request.urlparts.netloc
110
+ transfer_url = f"{base_url}/captcha/quick-transfer"
111
+
112
+ url_with_quick_transfer_params = (
113
+ f"{url}?"
114
+ f"transfer_url={quote(transfer_url)}&"
115
+ f"pkg_id={quote(package_id)}&"
116
+ f"pkg_title={quote(title)}&"
117
+ f"pkg_pass={quote(password)}"
118
+ )
119
+
106
120
  return f'''
107
121
  <div style="margin-top: 40px; padding-top: 20px; border-top: 2px solid #ccc;">
108
- <h3>Bypass CAPTCHA</h3>
109
- <a href="{url}" target="_blank">Protected Link</a>
110
- <form id="bypass-form" action="/captcha/bypass-submit" method="post" enctype="multipart/form-data">
111
- <input type="hidden" name="package_id" value="{package_id}" />
112
- <input type="hidden" name="title" value="{title}" />
113
- <input type="hidden" name="password" value="{password}" />
114
-
115
- <div style="margin-bottom: 15px;">
116
- <label for="links-input"><b>Paste direct download links (one per line):</b></label><br>
117
- <textarea id="links-input" name="links" rows="5" style="width: 100%; padding: 8px; font-family: monospace; resize: vertical;"></textarea>
118
- </div>
122
+ <details id="bypassDetails">
123
+ <summary id="bypassSummary">Show CAPTCHA Bypass</summary><br>
124
+ <strong><a href="{url_with_quick_transfer_params}" target="_blank">🔗 Obtain the download links here!</a></strong><br><br>
125
+ <form id="bypass-form" action="/captcha/bypass-submit" method="post" enctype="multipart/form-data">
126
+ <input type="hidden" name="package_id" value="{package_id}" />
127
+ <input type="hidden" name="title" value="{title}" />
128
+ <input type="hidden" name="password" value="{password}" />
129
+
130
+ <div>
131
+ <strong>Paste the download links (one per line):</strong>
132
+ <textarea id="links-input" name="links" rows="5" style="width: 100%; padding: 8px; font-family: monospace; resize: vertical;"></textarea>
133
+ </div>
119
134
 
120
- <div style="margin-bottom: 15px;">
121
- <label for="dlc-file"><b>Or upload DLC file:</b></label><br>
122
- <input type="file" id="dlc-file" name="dlc_file" accept=".dlc" />
123
- </div>
135
+ <div>
136
+ <strong>Or upload DLC file:</strong><br>
137
+ <input type="file" id="dlc-file" name="dlc_file" accept=".dlc" />
138
+ </div>
124
139
 
125
- <div>
126
- {render_button("Submit Bypass", "primary", {"type": "submit"})}
127
- </div>
128
- </form>
140
+ <div>
141
+ {render_button("Submit", "primary", {"type": "submit"})}
142
+ </div>
143
+ </form>
144
+ </details>
129
145
  </div>
146
+ <script>
147
+ const bypassDetails = document.getElementById('bypassDetails');
148
+ const bypassSummary = document.getElementById('bypassSummary');
149
+
150
+ if (bypassDetails && bypassSummary) {{
151
+ bypassDetails.addEventListener('toggle', () => {{
152
+ if (bypassDetails.open) {{
153
+ bypassSummary.textContent = 'Hide CAPTCHA Bypass';
154
+ }} else {{
155
+ bypassSummary.textContent = 'Show CAPTCHA Bypass';
156
+ }}
157
+ }});
158
+ }}
159
+ </script>
130
160
  '''
131
161
 
162
+ @app.get('/captcha/quick-transfer')
163
+ def handle_quick_transfer():
164
+ """Handle quick transfer from userscript"""
165
+ import zlib
166
+
167
+ try:
168
+ package_id = request.query.get('pkg_id')
169
+ compressed_links = request.query.get('links', '')
170
+
171
+ if not package_id or not compressed_links:
172
+ return render_centered_html(f'''<h1><img src="{images.logo}" type="image/png" alt="Quasarr logo" class="logo"/>Quasarr</h1>
173
+ <p><b>Error:</b> Missing parameters</p>
174
+ <p>
175
+ {render_button("Back", "secondary", {"onclick": "location.href='/captcha'"})}
176
+ </p>''')
177
+
178
+ # Decode the compressed links using urlsafe_b64decode
179
+ # Add padding if needed
180
+ padding = 4 - (len(compressed_links) % 4)
181
+ if padding != 4:
182
+ compressed_links += '=' * padding
183
+
184
+ try:
185
+ decoded = urlsafe_b64decode(compressed_links)
186
+ except Exception as e:
187
+ info(f"Base64 decode error: {e}")
188
+ return render_centered_html(f'''<h1><img src="{images.logo}" type="image/png" alt="Quasarr logo" class="logo"/>Quasarr</h1>
189
+ <p><b>Error:</b> Failed to decode data: {str(e)}</p>
190
+ <p>
191
+ {render_button("Back", "secondary", {"onclick": "location.href='/captcha'"})}
192
+ </p>''')
193
+
194
+ # Decompress using zlib - use raw deflate format (no header)
195
+ try:
196
+ decompressed = zlib.decompress(decoded, -15) # -15 = raw deflate, no zlib header
197
+ except Exception as e:
198
+ info(f"Decompression error: {e}, trying with header...")
199
+ try:
200
+ # Fallback: try with zlib header
201
+ decompressed = zlib.decompress(decoded)
202
+ except Exception as e2:
203
+ info(f"Decompression also failed with header: {e2}")
204
+ return render_centered_html(f'''<h1><img src="{images.logo}" type="image/png" alt="Quasarr logo" class="logo"/>Quasarr</h1>
205
+ <p><b>Error:</b> Failed to decompress data: {str(e)}</p>
206
+ <p>
207
+ {render_button("Back", "secondary", {"onclick": "location.href='/captcha'"})}
208
+ </p>''')
209
+
210
+ links_text = decompressed.decode('utf-8')
211
+
212
+ # Parse links and restore protocols
213
+ raw_links = [link.strip() for link in links_text.split('\n') if link.strip()]
214
+ links = []
215
+ for link in raw_links:
216
+ if not link.startswith(('http://', 'https://')):
217
+ link = 'https://' + link
218
+ links.append(link)
219
+
220
+ info(f"Quick transfer received {len(links)} links for package {package_id}")
221
+
222
+ # Get package info
223
+ raw_data = shared_state.get_db("protected").retrieve(package_id)
224
+ if not raw_data:
225
+ return render_centered_html(f'''<h1><img src="{images.logo}" type="image/png" alt="Quasarr logo" class="logo"/>Quasarr</h1>
226
+ <p><b>Error:</b> Package not found</p>
227
+ <p>
228
+ {render_button("Back", "secondary", {"onclick": "location.href='/captcha'"})}
229
+ </p>''')
230
+
231
+ data = json.loads(raw_data)
232
+ title = data.get("title", "Unknown")
233
+ password = data.get("password", "")
234
+
235
+ # Download the package
236
+ downloaded = shared_state.download_package(links, title, password, package_id)
237
+
238
+ if downloaded:
239
+ StatsHelper(shared_state).increment_package_with_links(links)
240
+ StatsHelper(shared_state).increment_captcha_decryptions_manual()
241
+ shared_state.get_db("protected").delete(package_id)
242
+
243
+ info(f"Quick transfer successful: {len(links)} links processed")
244
+
245
+ # Check if more CAPTCHAs remain
246
+ remaining_protected = shared_state.get_db("protected").retrieve_all_titles()
247
+ has_more_captchas = bool(remaining_protected)
248
+
249
+ if has_more_captchas:
250
+ solve_button = render_button("Solve another CAPTCHA", "primary",
251
+ {"onclick": "location.href='/captcha'"})
252
+ else:
253
+ solve_button = "<b>No more CAPTCHAs</b>"
254
+
255
+ return render_centered_html(f'''<h1><img src="{images.logo}" type="image/png" alt="Quasarr logo" class="logo"/>Quasarr</h1>
256
+ <p><b>✅ Quick Transfer Successful!</b></p>
257
+ <p>Package "{title}" with {len(links)} link(s) submitted to JDownloader.</p>
258
+ <p>
259
+ {solve_button}
260
+ </p>
261
+ <p>
262
+ {render_button("Back", "secondary", {"onclick": "location.href='/'"})}
263
+ </p>''')
264
+ else:
265
+ StatsHelper(shared_state).increment_failed_decryptions_manual()
266
+ return render_centered_html(f'''<h1><img src="{images.logo}" type="image/png" alt="Quasarr logo" class="logo"/>Quasarr</h1>
267
+ <p><b>Error:</b> Failed to submit package to JDownloader</p>
268
+ <p>
269
+ {render_button("Try Again", "secondary", {"onclick": "location.href='/captcha'"})}
270
+ </p>''')
271
+
272
+ except Exception as e:
273
+ info(f"Quick transfer error: {e}")
274
+ return render_centered_html(f'''<h1><img src="{images.logo}" type="image/png" alt="Quasarr logo" class="logo"/>Quasarr</h1>
275
+ <p><b>Error:</b> {str(e)}</p>
276
+ <p>
277
+ {render_button("Back", "secondary", {"onclick": "location.href='/captcha'"})}
278
+ </p>''')
279
+
132
280
  @app.get('/captcha/delete/<package_id>')
133
281
  def delete_captcha_package(package_id):
134
282
  success = delete_package(shared_state, package_id)
@@ -285,7 +433,6 @@ def setup_captcha_routes(app):
285
433
  <div>
286
434
  <h1><img src="{images.logo}" type="image/png" alt="Quasarr logo" class="logo"/>Quasarr</h1>
287
435
  <p id="package-title" style="max-width: 370px; word-wrap: break-word; overflow-wrap: break-word;"><b>Package:</b> {title}</p>
288
- <h3>Solve CAPTCHA</h3>
289
436
  <div id="captcha-key"></div>
290
437
  {link_select}<br><br>
291
438
  <input type="hidden" id="link-hidden" value="{prioritized_links[0][0]}" />
@@ -408,8 +555,11 @@ def setup_captcha_routes(app):
408
555
  # Process links input
409
556
  if links_input:
410
557
  info(f"Processing direct links bypass for {title}")
411
- links = [link.strip() for link in links_input.split('\n') if link.strip()]
412
- info(f"Received {len(links)} direct download links")
558
+ raw_links = [link.strip() for link in links_input.split('\n') if link.strip()]
559
+ links = [l for l in raw_links if l.lower().startswith(("http://", "https://"))]
560
+
561
+ info(f"Received {len(links)} valid direct download links "
562
+ f"(from {len(raw_links)} provided)")
413
563
 
414
564
  # Process DLC file
415
565
  elif dlc_upload:
@@ -590,7 +740,6 @@ def setup_captcha_routes(app):
590
740
  <body>
591
741
  <h1><img src="{images.logo}" type="image/png" alt="Quasarr logo" class="logo"/>Quasarr</h1>
592
742
  <p><b>Package:</b> {title}</p>
593
- <h3>Solve CAPTCHA</h3>
594
743
  <form action="/captcha/decrypt-filecrypt-circle?url={url}&session_id={session_id}&package_id={package_id}" method="post">
595
744
  <input type="image" src="/captcha/circle.php?url={url}&session_id={session_id}" name="button" alt="Circle CAPTCHA">
596
745
  </form>
@@ -8,7 +8,7 @@ import requests
8
8
 
9
9
 
10
10
  def get_version():
11
- return "1.17.1"
11
+ return "1.17.3"
12
12
 
13
13
 
14
14
  def get_latest_version():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quasarr
3
- Version: 1.17.1
3
+ Version: 1.17.3
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
File without changes
File without changes
File without changes
File without changes
File without changes