quasarr 2.3.2__tar.gz → 2.4.0__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-2.3.2 → quasarr-2.4.0}/PKG-INFO +1 -1
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/api/captcha/__init__.py +57 -48
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/api/sponsors_helper/__init__.py +25 -37
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/providers/version.py +1 -1
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr.egg-info/PKG-INFO +1 -1
- {quasarr-2.3.2 → quasarr-2.4.0}/LICENSE +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/README.md +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/__init__.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/api/__init__.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/api/arr/__init__.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/api/config/__init__.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/api/packages/__init__.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/api/statistics/__init__.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/downloads/__init__.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/downloads/linkcrypters/__init__.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/downloads/linkcrypters/al.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/downloads/linkcrypters/filecrypt.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/downloads/linkcrypters/hide.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/downloads/packages/__init__.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/downloads/sources/__init__.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/downloads/sources/al.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/downloads/sources/by.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/downloads/sources/dd.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/downloads/sources/dj.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/downloads/sources/dl.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/downloads/sources/dt.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/downloads/sources/dw.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/downloads/sources/he.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/downloads/sources/mb.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/downloads/sources/nk.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/downloads/sources/nx.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/downloads/sources/sf.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/downloads/sources/sj.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/downloads/sources/sl.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/downloads/sources/wd.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/downloads/sources/wx.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/providers/__init__.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/providers/auth.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/providers/cloudflare.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/providers/hostname_issues.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/providers/html_images.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/providers/html_templates.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/providers/imdb_metadata.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/providers/jd_cache.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/providers/log.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/providers/myjd_api.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/providers/notifications.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/providers/obfuscated.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/providers/sessions/__init__.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/providers/sessions/al.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/providers/sessions/dd.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/providers/sessions/dl.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/providers/sessions/nx.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/providers/shared_state.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/providers/statistics.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/providers/utils.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/providers/web_server.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/search/__init__.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/search/sources/__init__.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/search/sources/al.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/search/sources/by.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/search/sources/dd.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/search/sources/dj.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/search/sources/dl.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/search/sources/dt.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/search/sources/dw.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/search/sources/fx.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/search/sources/he.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/search/sources/mb.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/search/sources/nk.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/search/sources/nx.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/search/sources/sf.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/search/sources/sj.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/search/sources/sl.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/search/sources/wd.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/search/sources/wx.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/storage/__init__.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/storage/config.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/storage/setup.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr/storage/sqlite_database.py +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr.egg-info/SOURCES.txt +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr.egg-info/dependency_links.txt +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr.egg-info/entry_points.txt +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr.egg-info/not-zip-safe +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr.egg-info/requires.txt +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/quasarr.egg-info/top_level.txt +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/setup.cfg +0 -0
- {quasarr-2.3.2 → quasarr-2.4.0}/setup.py +0 -0
|
@@ -86,6 +86,8 @@ def setup_captcha_routes(app):
|
|
|
86
86
|
except KeyError:
|
|
87
87
|
desired_mirror = None
|
|
88
88
|
|
|
89
|
+
original_url = data.get("original_url")
|
|
90
|
+
|
|
89
91
|
# This is required for cutcaptcha
|
|
90
92
|
rapid = [ln for ln in links if "rapidgator" in ln[1].lower()]
|
|
91
93
|
others = [ln for ln in links if "rapidgator" not in ln[1].lower()]
|
|
@@ -97,6 +99,7 @@ def setup_captcha_routes(app):
|
|
|
97
99
|
"password": password,
|
|
98
100
|
"mirror": desired_mirror,
|
|
99
101
|
"links": prioritized_links,
|
|
102
|
+
"original_url": original_url,
|
|
100
103
|
}
|
|
101
104
|
|
|
102
105
|
encoded_payload = urlsafe_b64encode(json.dumps(payload).encode()).decode()
|
|
@@ -194,29 +197,18 @@ def setup_captcha_routes(app):
|
|
|
194
197
|
|
|
195
198
|
return f'''
|
|
196
199
|
<div>
|
|
197
|
-
<!-- Info section explaining the process -->
|
|
198
|
-
<div class="info-box">
|
|
199
|
-
<h3>ℹ️ How This Works:</h3>
|
|
200
|
-
<p style="margin-bottom: 8px;">
|
|
201
|
-
1. Click the link below to open {provider_name}
|
|
202
|
-
</p>
|
|
203
|
-
<p style="margin-top: 0; margin-bottom: 8px;">
|
|
204
|
-
2. Solve any CAPTCHAs on their site to reveal the download links
|
|
205
|
-
</p>
|
|
206
|
-
<p style="margin-top: 0; margin-bottom: 0;">
|
|
207
|
-
3. <b>With the userscript installed</b>, links are automatically sent back to Quasarr!
|
|
208
|
-
</p>
|
|
209
|
-
</div>
|
|
210
|
-
|
|
211
200
|
<!-- One-time setup section - visually separated -->
|
|
212
201
|
<div id="setup-instructions" class="setup-box">
|
|
213
202
|
<h3>📦 First Time Setup:</h3>
|
|
214
203
|
<p style="margin-bottom: 8px;">
|
|
215
|
-
<a href="https://www.tampermonkey.net/" target="_blank" rel="noopener noreferrer">1.
|
|
204
|
+
<a href="https://www.tampermonkey.net/" target="_blank" rel="noopener noreferrer">1. On mobile Safari/Firefox or any Desktop Browser install Tampermonkey</a>
|
|
216
205
|
</p>
|
|
217
|
-
<p style="margin-top: 0; margin-bottom:
|
|
206
|
+
<p style="margin-top: 0; margin-bottom: 8px;">
|
|
218
207
|
<a href="{userscript_url}" target="_blank">2. Install the {provider_name} userscript</a>
|
|
219
208
|
</p>
|
|
209
|
+
<p style="margin-top: 0; margin-bottom: 12px;">
|
|
210
|
+
3. Open link, solve CAPTCHAs, and links are automatically sent back to Quasarr!
|
|
211
|
+
</p>
|
|
220
212
|
<p style="margin-top: 0;">
|
|
221
213
|
<button id="hide-setup-btn" type="button" class="btn-subtle">
|
|
222
214
|
✅ Don't show this again
|
|
@@ -318,6 +310,7 @@ def setup_captcha_routes(app):
|
|
|
318
310
|
title = payload.get("title")
|
|
319
311
|
password = payload.get("password")
|
|
320
312
|
urls = payload.get("links")
|
|
313
|
+
original_url = payload.get("original_url")
|
|
321
314
|
url = urls[0][0] if isinstance(urls[0], (list, tuple)) else urls[0]
|
|
322
315
|
|
|
323
316
|
check_package_exists(package_id)
|
|
@@ -325,6 +318,10 @@ def setup_captcha_routes(app):
|
|
|
325
318
|
package_selector = render_package_selector(package_id, title)
|
|
326
319
|
failed_warning = render_failed_attempts_warning(package_id)
|
|
327
320
|
|
|
321
|
+
source_button = ""
|
|
322
|
+
if original_url:
|
|
323
|
+
source_button = f'<p>{render_button("Source", "secondary", {"onclick": f"window.open(\'{js_single_quoted_string_safe(original_url)}\', \'_blank\')" })}</p>'
|
|
324
|
+
|
|
328
325
|
return render_centered_html(f"""
|
|
329
326
|
<!DOCTYPE html>
|
|
330
327
|
<html>
|
|
@@ -333,6 +330,7 @@ def setup_captcha_routes(app):
|
|
|
333
330
|
{package_selector}
|
|
334
331
|
{failed_warning}
|
|
335
332
|
{render_userscript_section(url, package_id, title, password, "hide")}
|
|
333
|
+
{source_button}
|
|
336
334
|
<p>
|
|
337
335
|
{render_button("Delete Package", "secondary", {"onclick": f"location.href='/captcha/delete/{package_id}'"})}
|
|
338
336
|
</p>
|
|
@@ -358,6 +356,7 @@ def setup_captcha_routes(app):
|
|
|
358
356
|
title = payload.get("title")
|
|
359
357
|
password = payload.get("password")
|
|
360
358
|
urls = payload.get("links")
|
|
359
|
+
original_url = payload.get("original_url")
|
|
361
360
|
url = urls[0][0] if isinstance(urls[0], (list, tuple)) else urls[0]
|
|
362
361
|
|
|
363
362
|
check_package_exists(package_id)
|
|
@@ -365,6 +364,10 @@ def setup_captcha_routes(app):
|
|
|
365
364
|
package_selector = render_package_selector(package_id, title)
|
|
366
365
|
failed_warning = render_failed_attempts_warning(package_id)
|
|
367
366
|
|
|
367
|
+
source_button = ""
|
|
368
|
+
if original_url:
|
|
369
|
+
source_button = f'<p>{render_button("Source", "secondary", {"onclick": f"window.open(\'{js_single_quoted_string_safe(original_url)}\', \'_blank\')" })}</p>'
|
|
370
|
+
|
|
368
371
|
return render_centered_html(f"""
|
|
369
372
|
<!DOCTYPE html>
|
|
370
373
|
<html>
|
|
@@ -373,6 +376,7 @@ def setup_captcha_routes(app):
|
|
|
373
376
|
{package_selector}
|
|
374
377
|
{failed_warning}
|
|
375
378
|
{render_userscript_section(url, package_id, title, password, "junkies")}
|
|
379
|
+
{source_button}
|
|
376
380
|
<p>
|
|
377
381
|
{render_button("Delete Package", "secondary", {"onclick": f"location.href='/captcha/delete/{package_id}'"})}
|
|
378
382
|
</p>
|
|
@@ -398,6 +402,7 @@ def setup_captcha_routes(app):
|
|
|
398
402
|
title = payload.get("title")
|
|
399
403
|
password = payload.get("password")
|
|
400
404
|
urls = payload.get("links")
|
|
405
|
+
original_url = payload.get("original_url")
|
|
401
406
|
|
|
402
407
|
check_package_exists(package_id)
|
|
403
408
|
|
|
@@ -406,6 +411,10 @@ def setup_captcha_routes(app):
|
|
|
406
411
|
package_selector = render_package_selector(package_id, title)
|
|
407
412
|
failed_warning = render_failed_attempts_warning(package_id)
|
|
408
413
|
|
|
414
|
+
source_button = ""
|
|
415
|
+
if original_url:
|
|
416
|
+
source_button = f'<p>{render_button("Source", "secondary", {"onclick": f"window.open(\'{js_single_quoted_string_safe(original_url)}\', \'_blank\')" })}</p>'
|
|
417
|
+
|
|
409
418
|
return render_centered_html(f"""
|
|
410
419
|
<!DOCTYPE html>
|
|
411
420
|
<html>
|
|
@@ -414,6 +423,7 @@ def setup_captcha_routes(app):
|
|
|
414
423
|
{package_selector}
|
|
415
424
|
{failed_warning}
|
|
416
425
|
{render_userscript_section(url, package_id, title, password, "keeplinks")}
|
|
426
|
+
{source_button}
|
|
417
427
|
<p>
|
|
418
428
|
{render_button("Delete Package", "secondary", {"onclick": f"location.href='/captcha/delete/{package_id}'"})}
|
|
419
429
|
</p>
|
|
@@ -439,6 +449,7 @@ def setup_captcha_routes(app):
|
|
|
439
449
|
title = payload.get("title")
|
|
440
450
|
password = payload.get("password")
|
|
441
451
|
urls = payload.get("links")
|
|
452
|
+
original_url = payload.get("original_url")
|
|
442
453
|
|
|
443
454
|
check_package_exists(package_id)
|
|
444
455
|
|
|
@@ -447,6 +458,10 @@ def setup_captcha_routes(app):
|
|
|
447
458
|
package_selector = render_package_selector(package_id, title)
|
|
448
459
|
failed_warning = render_failed_attempts_warning(package_id)
|
|
449
460
|
|
|
461
|
+
source_button = ""
|
|
462
|
+
if original_url:
|
|
463
|
+
source_button = f'<p>{render_button("Source", "secondary", {"onclick": f"window.open(\'{js_single_quoted_string_safe(original_url)}\', \'_blank\')" })}</p>'
|
|
464
|
+
|
|
450
465
|
return render_centered_html(f"""
|
|
451
466
|
<!DOCTYPE html>
|
|
452
467
|
<html>
|
|
@@ -455,6 +470,7 @@ def setup_captcha_routes(app):
|
|
|
455
470
|
{package_selector}
|
|
456
471
|
{failed_warning}
|
|
457
472
|
{render_userscript_section(url, package_id, title, password, "tolink")}
|
|
473
|
+
{source_button}
|
|
458
474
|
<p>
|
|
459
475
|
{render_button("Delete Package", "secondary", {"onclick": f"location.href='/captcha/delete/{package_id}'"})}
|
|
460
476
|
</p>
|
|
@@ -519,29 +535,18 @@ def setup_captcha_routes(app):
|
|
|
519
535
|
<details id="bypassDetails">
|
|
520
536
|
<summary id="bypassSummary">Show CAPTCHA Bypass</summary><br>
|
|
521
537
|
|
|
522
|
-
<!-- Info section explaining the process -->
|
|
523
|
-
<div class="info-box">
|
|
524
|
-
<h3>ℹ️ How This Works:</h3>
|
|
525
|
-
<p style="margin-bottom: 8px;">
|
|
526
|
-
1. Click the button below to open FileCrypt directly
|
|
527
|
-
</p>
|
|
528
|
-
<p style="margin-top: 0; margin-bottom: 8px;">
|
|
529
|
-
2. Solve any CAPTCHAs on their site to reveal the download links
|
|
530
|
-
</p>
|
|
531
|
-
<p style="margin-top: 0; margin-bottom: 0;">
|
|
532
|
-
3. <b>With the userscript installed</b>, links are automatically sent back to Quasarr!
|
|
533
|
-
</p>
|
|
534
|
-
</div>
|
|
535
|
-
|
|
536
538
|
<!-- One-time setup section - visually separated -->
|
|
537
539
|
<div id="setup-instructions" class="setup-box">
|
|
538
540
|
<h3>📦 First Time Setup:</h3>
|
|
539
541
|
<p style="margin-bottom: 8px;">
|
|
540
|
-
<a href="https://www.tampermonkey.net/" target="_blank" rel="noopener noreferrer">1.
|
|
542
|
+
<a href="https://www.tampermonkey.net/" target="_blank" rel="noopener noreferrer">1. On mobile Safari/Firefox or any Desktop Browser install Tampermonkey</a>
|
|
541
543
|
</p>
|
|
542
|
-
<p style="margin-top: 0; margin-bottom:
|
|
544
|
+
<p style="margin-top: 0; margin-bottom: 8px;">
|
|
543
545
|
<a href="/captcha/filecrypt.user.js" target="_blank">2. Install the FileCrypt userscript</a>
|
|
544
546
|
</p>
|
|
547
|
+
<p style="margin-top: 0; margin-bottom: 12px;">
|
|
548
|
+
3. Open link, solve CAPTCHAs, and links are automatically sent back to Quasarr!
|
|
549
|
+
</p>
|
|
545
550
|
<p style="margin-top: 0;">
|
|
546
551
|
<button id="hide-setup-btn" type="button" class="btn-subtle">
|
|
547
552
|
✅ Don't show this again
|
|
@@ -682,6 +687,7 @@ def setup_captcha_routes(app):
|
|
|
682
687
|
links = data.get("links", [])
|
|
683
688
|
password = data.get("password", "")
|
|
684
689
|
mirror = data.get("mirror")
|
|
690
|
+
original_url = data.get("original_url")
|
|
685
691
|
|
|
686
692
|
# Prioritize rapidgator links for cutcaptcha
|
|
687
693
|
rapid = [ln for ln in links if "rapidgator" in ln[1].lower()]
|
|
@@ -694,6 +700,7 @@ def setup_captcha_routes(app):
|
|
|
694
700
|
"password": password,
|
|
695
701
|
"mirror": mirror,
|
|
696
702
|
"links": prioritized,
|
|
703
|
+
"original_url": original_url,
|
|
697
704
|
}
|
|
698
705
|
encoded = urlsafe_b64encode(json.dumps(payload).encode()).decode()
|
|
699
706
|
captcha_type = get_captcha_type_for_links(prioritized)
|
|
@@ -818,6 +825,7 @@ def setup_captcha_routes(app):
|
|
|
818
825
|
title = payload.get("title")
|
|
819
826
|
password = payload.get("password")
|
|
820
827
|
urls = payload.get("links")
|
|
828
|
+
original_url = payload.get("original_url")
|
|
821
829
|
|
|
822
830
|
check_package_exists(package_id)
|
|
823
831
|
|
|
@@ -838,6 +846,10 @@ def setup_captcha_routes(app):
|
|
|
838
846
|
package_selector = render_package_selector(package_id, title)
|
|
839
847
|
failed_warning = render_failed_attempts_warning(package_id)
|
|
840
848
|
|
|
849
|
+
source_button = ""
|
|
850
|
+
if original_url:
|
|
851
|
+
source_button = f'<p>{render_button("Source", "secondary", {"onclick": f"window.open(\'{js_single_quoted_string_safe(original_url)}\', \'_blank\')" })}</p>'
|
|
852
|
+
|
|
841
853
|
return render_centered_html(f"""
|
|
842
854
|
<!DOCTYPE html>
|
|
843
855
|
<html>
|
|
@@ -847,29 +859,18 @@ def setup_captcha_routes(app):
|
|
|
847
859
|
{failed_warning}
|
|
848
860
|
|
|
849
861
|
<div>
|
|
850
|
-
<!-- Info section explaining the process -->
|
|
851
|
-
<div class="info-box">
|
|
852
|
-
<h3>ℹ️ How This Works:</h3>
|
|
853
|
-
<p style="margin-bottom: 8px;">
|
|
854
|
-
1. Click the button below to open FileCrypt directly
|
|
855
|
-
</p>
|
|
856
|
-
<p style="margin-top: 0; margin-bottom: 8px;">
|
|
857
|
-
2. Solve any CAPTCHAs on their site to reveal the download links
|
|
858
|
-
</p>
|
|
859
|
-
<p style="margin-top: 0; margin-bottom: 0;">
|
|
860
|
-
3. <b>With the userscript installed</b>, links are automatically sent back to Quasarr!
|
|
861
|
-
</p>
|
|
862
|
-
</div>
|
|
863
|
-
|
|
864
862
|
<!-- One-time setup section - visually separated -->
|
|
865
863
|
<div id="setup-instructions" class="setup-box">
|
|
866
864
|
<h3>📦 First Time Setup:</h3>
|
|
867
865
|
<p style="margin-bottom: 8px;">
|
|
868
|
-
<a href="https://www.tampermonkey.net/" target="_blank" rel="noopener noreferrer">1.
|
|
866
|
+
<a href="https://www.tampermonkey.net/" target="_blank" rel="noopener noreferrer">1. On mobile Safari/Firefox or any Desktop Browser install Tampermonkey</a>
|
|
869
867
|
</p>
|
|
870
|
-
<p style="margin-top: 0; margin-bottom:
|
|
868
|
+
<p style="margin-top: 0; margin-bottom: 8px;">
|
|
871
869
|
<a href="/captcha/filecrypt.user.js" target="_blank">2. Install the FileCrypt userscript</a>
|
|
872
870
|
</p>
|
|
871
|
+
<p style="margin-top: 0; margin-bottom: 12px;">
|
|
872
|
+
3. Open link, solve CAPTCHAs, and links are automatically sent back to Quasarr!
|
|
873
|
+
</p>
|
|
873
874
|
<p style="margin-top: 0;">
|
|
874
875
|
<button id="hide-setup-btn" type="button" class="btn-subtle">
|
|
875
876
|
✅ Don't show this again
|
|
@@ -921,6 +922,7 @@ def setup_captcha_routes(app):
|
|
|
921
922
|
</div>
|
|
922
923
|
</div>
|
|
923
924
|
|
|
925
|
+
{source_button}
|
|
924
926
|
<p>
|
|
925
927
|
{render_button("Delete Package", "secondary", {"onclick": f"location.href='/captcha/delete/{package_id}'"})}
|
|
926
928
|
</p>
|
|
@@ -1142,6 +1144,7 @@ def setup_captcha_routes(app):
|
|
|
1142
1144
|
password = payload.get("password")
|
|
1143
1145
|
desired_mirror = payload.get("mirror")
|
|
1144
1146
|
prioritized_links = payload.get("links")
|
|
1147
|
+
original_url = payload.get("original_url")
|
|
1145
1148
|
|
|
1146
1149
|
check_package_exists(package_id)
|
|
1147
1150
|
|
|
@@ -1199,6 +1202,7 @@ def setup_captcha_routes(app):
|
|
|
1199
1202
|
"password": password,
|
|
1200
1203
|
"mirror": desired_mirror,
|
|
1201
1204
|
"links": prioritized_links,
|
|
1205
|
+
"original_url": original_url,
|
|
1202
1206
|
}
|
|
1203
1207
|
fallback_encoded = urlsafe_b64encode(json.dumps(fallback_payload).encode()).decode()
|
|
1204
1208
|
filecrypt_fallback_url = f"/captcha/filecrypt?data={quote(fallback_encoded)}"
|
|
@@ -1209,6 +1213,10 @@ def setup_captcha_routes(app):
|
|
|
1209
1213
|
# Escape title for safe use in JavaScript string
|
|
1210
1214
|
escaped_title_js = title.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r')
|
|
1211
1215
|
|
|
1216
|
+
source_button_html = ""
|
|
1217
|
+
if original_url:
|
|
1218
|
+
source_button_html = f'<p>{render_button("Source", "secondary", {"onclick": f"window.open(\'{js_single_quoted_string_safe(original_url)}\', \'_blank\')" })}</p>'
|
|
1219
|
+
|
|
1212
1220
|
content = render_centered_html(r'''
|
|
1213
1221
|
<style>
|
|
1214
1222
|
/* Fix captcha container to shrink-wrap iframe on desktop */
|
|
@@ -1321,6 +1329,7 @@ def setup_captcha_routes(app):
|
|
|
1321
1329
|
</div>
|
|
1322
1330
|
<br>
|
|
1323
1331
|
<div id="delete-package-section">
|
|
1332
|
+
''' + source_button_html + f'''
|
|
1324
1333
|
<p>
|
|
1325
1334
|
{render_button("Delete Package", "secondary", {"onclick": f"location.href='/captcha/delete/{package_id}'"})}
|
|
1326
1335
|
</p>
|
|
@@ -33,16 +33,16 @@ def setup_sponsors_helper_routes(app):
|
|
|
33
33
|
if not protected:
|
|
34
34
|
return abort(404, "No encrypted packages found")
|
|
35
35
|
|
|
36
|
-
# Find the first package
|
|
36
|
+
# Find the first package that hasn't been disabled
|
|
37
37
|
selected_package = None
|
|
38
38
|
for package in protected:
|
|
39
39
|
data = json.loads(package[1])
|
|
40
|
-
if "
|
|
40
|
+
if "disabled" not in data:
|
|
41
41
|
selected_package = (package[0], data)
|
|
42
42
|
break
|
|
43
43
|
|
|
44
44
|
if not selected_package:
|
|
45
|
-
return abort(404, "No valid packages
|
|
45
|
+
return abort(404, "No valid packages found")
|
|
46
46
|
|
|
47
47
|
package_id, data = selected_package
|
|
48
48
|
title = data["title"]
|
|
@@ -67,9 +67,9 @@ def setup_sponsors_helper_routes(app):
|
|
|
67
67
|
except Exception as e:
|
|
68
68
|
return abort(500, str(e))
|
|
69
69
|
|
|
70
|
-
@app.post("/sponsors_helper/api/
|
|
70
|
+
@app.post("/sponsors_helper/api/download/")
|
|
71
71
|
@require_api_key
|
|
72
|
-
def
|
|
72
|
+
def download_api():
|
|
73
73
|
try:
|
|
74
74
|
data = request.json
|
|
75
75
|
title = data.get('name')
|
|
@@ -97,51 +97,39 @@ def setup_sponsors_helper_routes(app):
|
|
|
97
97
|
StatsHelper(shared_state).increment_failed_decryptions_automatic()
|
|
98
98
|
return abort(500, "Failed")
|
|
99
99
|
|
|
100
|
-
@app.post("/sponsors_helper/api/
|
|
100
|
+
@app.post("/sponsors_helper/api/disable/")
|
|
101
101
|
@require_api_key
|
|
102
|
-
def
|
|
102
|
+
def disable_api():
|
|
103
103
|
try:
|
|
104
104
|
data = request.json
|
|
105
|
-
name = data.get('name')
|
|
106
105
|
package_id = data.get('package_id')
|
|
107
|
-
password = data.get('password')
|
|
108
|
-
replace_url = data.get('replace_url')
|
|
109
|
-
mirror = data.get('mirror')
|
|
110
|
-
session = data.get('session')
|
|
111
|
-
|
|
112
|
-
if not all([name, package_id, replace_url, mirror, session]):
|
|
113
|
-
info("Missing required replacement data")
|
|
114
|
-
return {"error": "Missing required replacement data"}, 400
|
|
115
|
-
|
|
116
|
-
if password is None:
|
|
117
|
-
password = ""
|
|
118
|
-
|
|
119
|
-
blob = json.dumps(
|
|
120
|
-
{
|
|
121
|
-
"title": name,
|
|
122
|
-
"links": [replace_url, mirror],
|
|
123
|
-
"size_mb": 0,
|
|
124
|
-
"password": password,
|
|
125
|
-
"mirror": mirror,
|
|
126
|
-
"session": session
|
|
127
|
-
})
|
|
128
106
|
|
|
129
|
-
|
|
107
|
+
if not package_id:
|
|
108
|
+
return {"error": "Missing package_id"}, 400
|
|
109
|
+
|
|
110
|
+
StatsHelper(shared_state).increment_failed_decryptions_automatic()
|
|
130
111
|
|
|
131
|
-
|
|
112
|
+
blob = shared_state.get_db("protected").retrieve(package_id)
|
|
113
|
+
package_data = json.loads(blob)
|
|
114
|
+
title = package_data.get('title')
|
|
115
|
+
|
|
116
|
+
package_data["disabled"] = True
|
|
117
|
+
|
|
118
|
+
shared_state.get_db("protected").update_store(package_id, json.dumps(package_data))
|
|
119
|
+
|
|
120
|
+
info(f"Disabled package {title}")
|
|
132
121
|
|
|
133
122
|
StatsHelper(shared_state).increment_captcha_decryptions_automatic()
|
|
134
123
|
|
|
135
|
-
return f"
|
|
124
|
+
return f"Package {title} disabled"
|
|
136
125
|
|
|
137
126
|
except Exception as e:
|
|
138
|
-
|
|
139
|
-
info(f"Error handling replacement: {e}")
|
|
127
|
+
info(f"Error handling disable: {e}")
|
|
140
128
|
return {"error": str(e)}, 500
|
|
141
129
|
|
|
142
|
-
@app.delete("/sponsors_helper/api/
|
|
130
|
+
@app.delete("/sponsors_helper/api/fail/")
|
|
143
131
|
@require_api_key
|
|
144
|
-
def
|
|
132
|
+
def fail_api():
|
|
145
133
|
try:
|
|
146
134
|
StatsHelper(shared_state).increment_failed_decryptions_automatic()
|
|
147
135
|
|
|
@@ -165,7 +153,7 @@ def setup_sponsors_helper_routes(app):
|
|
|
165
153
|
|
|
166
154
|
@app.put("/sponsors_helper/api/set_sponsor_status/")
|
|
167
155
|
@require_api_key
|
|
168
|
-
def
|
|
156
|
+
def set_sponsor_status_api():
|
|
169
157
|
try:
|
|
170
158
|
data = request.body.read().decode("utf-8")
|
|
171
159
|
payload = json.loads(data)
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|