quasarr 1.17.2__tar.gz → 1.18.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-1.17.2 → quasarr-1.18.0}/PKG-INFO +1 -1
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/api/captcha/__init__.py +193 -7
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/downloads/__init__.py +3 -0
- quasarr-1.18.0/quasarr/downloads/sources/nk.py +55 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/providers/html_images.py +1 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/providers/obfuscated.py +18 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/providers/version.py +1 -1
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/search/__init__.py +4 -0
- quasarr-1.18.0/quasarr/search/sources/nk.py +189 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/storage/config.py +1 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr.egg-info/PKG-INFO +1 -1
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr.egg-info/SOURCES.txt +2 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/LICENSE +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/README.md +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/__init__.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/api/__init__.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/api/arr/__init__.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/api/config/__init__.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/api/sponsors_helper/__init__.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/api/statistics/__init__.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/downloads/linkcrypters/__init__.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/downloads/linkcrypters/al.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/downloads/linkcrypters/filecrypt.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/downloads/linkcrypters/hide.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/downloads/packages/__init__.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/downloads/sources/__init__.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/downloads/sources/al.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/downloads/sources/by.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/downloads/sources/dd.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/downloads/sources/dt.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/downloads/sources/dw.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/downloads/sources/mb.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/downloads/sources/nx.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/downloads/sources/sf.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/downloads/sources/sl.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/downloads/sources/wd.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/providers/__init__.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/providers/cloudflare.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/providers/html_templates.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/providers/imdb_metadata.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/providers/log.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/providers/myjd_api.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/providers/notifications.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/providers/sessions/__init__.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/providers/sessions/al.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/providers/sessions/dd.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/providers/sessions/nx.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/providers/shared_state.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/providers/statistics.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/providers/web_server.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/search/sources/__init__.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/search/sources/al.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/search/sources/by.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/search/sources/dd.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/search/sources/dt.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/search/sources/dw.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/search/sources/fx.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/search/sources/mb.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/search/sources/nx.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/search/sources/sf.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/search/sources/sl.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/search/sources/wd.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/storage/__init__.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/storage/setup.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr/storage/sqlite_database.py +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr.egg-info/dependency_links.txt +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr.egg-info/entry_points.txt +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr.egg-info/not-zip-safe +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr.egg-info/requires.txt +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/quasarr.egg-info/top_level.txt +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/setup.cfg +0 -0
- {quasarr-1.17.2 → quasarr-1.18.0}/setup.py +0 -0
|
@@ -16,7 +16,7 @@ from quasarr.downloads.packages import delete_package
|
|
|
16
16
|
from quasarr.providers import shared_state
|
|
17
17
|
from quasarr.providers.html_templates import render_button, render_centered_html
|
|
18
18
|
from quasarr.providers.log import info, debug
|
|
19
|
-
from quasarr.providers.obfuscated import captcha_js, captcha_values
|
|
19
|
+
from quasarr.providers.obfuscated import captcha_js, captcha_values, filecrypt_quasarr_helper_user_js
|
|
20
20
|
from quasarr.providers.statistics import StatsHelper
|
|
21
21
|
|
|
22
22
|
|
|
@@ -101,28 +101,71 @@ def setup_captcha_routes(app):
|
|
|
101
101
|
except Exception as e:
|
|
102
102
|
return {"error": f"Failed to decode payload: {str(e)}"}
|
|
103
103
|
|
|
104
|
+
@app.get('/captcha/quasarr.user.js')
|
|
105
|
+
def serve_quasarr_user_js():
|
|
106
|
+
content = filecrypt_quasarr_helper_user_js()
|
|
107
|
+
response.content_type = 'application/javascript'
|
|
108
|
+
return content
|
|
109
|
+
|
|
104
110
|
def render_bypass_section(url, package_id, title, password):
|
|
105
111
|
"""Render the bypass UI section for both cutcaptcha and circle captcha pages"""
|
|
112
|
+
|
|
113
|
+
# Generate userscript URL with transfer params
|
|
114
|
+
# Get base URL of current request
|
|
115
|
+
base_url = request.urlparts.scheme + '://' + request.urlparts.netloc
|
|
116
|
+
transfer_url = f"{base_url}/captcha/quick-transfer"
|
|
117
|
+
|
|
118
|
+
url_with_quick_transfer_params = (
|
|
119
|
+
f"{url}?"
|
|
120
|
+
f"transfer_url={quote(transfer_url)}&"
|
|
121
|
+
f"pkg_id={quote(package_id)}&"
|
|
122
|
+
f"pkg_title={quote(title)}&"
|
|
123
|
+
f"pkg_pass={quote(password)}"
|
|
124
|
+
)
|
|
125
|
+
|
|
106
126
|
return f'''
|
|
107
127
|
<div style="margin-top: 40px; padding-top: 20px; border-top: 2px solid #ccc;">
|
|
108
128
|
<details id="bypassDetails">
|
|
109
129
|
<summary id="bypassSummary">Show CAPTCHA Bypass</summary><br>
|
|
110
|
-
|
|
130
|
+
|
|
131
|
+
<!-- One-time setup section - visually separated -->
|
|
132
|
+
<div id="setup-instructions" style="background: #2a2a2a; border: 2px solid #444; border-radius: 8px; padding: 16px; margin-bottom: 24px;">
|
|
133
|
+
<h3 style="margin-top: 0; color: #58a6ff;">First Time Setup:</h3>
|
|
134
|
+
<p style="margin-bottom: 8px;">
|
|
135
|
+
<a href="https://www.tampermonkey.net/" target="_blank" rel="noopener noreferrer">1. Install Tampermonkey</a>
|
|
136
|
+
</p>
|
|
137
|
+
<p style="margin-top: 0; margin-bottom: 12px;">
|
|
138
|
+
<a href="/captcha/quasarr.user.js" target="_blank">2. Install this userscript</a>
|
|
139
|
+
</p>
|
|
140
|
+
<p style="margin-top: 0;">
|
|
141
|
+
<button id="hide-setup-btn" type="button" style="background: #444; color: #fff; border: 1px solid #666; padding: 6px 12px; border-radius: 4px; cursor: pointer;">
|
|
142
|
+
✅ Don't show this again
|
|
143
|
+
</button>
|
|
144
|
+
</p>
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<!-- Hidden "show instructions" link -->
|
|
148
|
+
<div id="show-instructions-link" style="display: none; margin-bottom: 16px;">
|
|
149
|
+
<a href="#" id="show-setup-btn" style="color: #58a6ff; text-decoration: underline;">ℹ️ Show instructions again</a>
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
<strong><a href="{url_with_quick_transfer_params}" target="_blank">🔗 Obtain the download links here!</a></strong><br><br>
|
|
153
|
+
|
|
111
154
|
<form id="bypass-form" action="/captcha/bypass-submit" method="post" enctype="multipart/form-data">
|
|
112
155
|
<input type="hidden" name="package_id" value="{package_id}" />
|
|
113
156
|
<input type="hidden" name="title" value="{title}" />
|
|
114
157
|
<input type="hidden" name="password" value="{password}" />
|
|
115
|
-
|
|
158
|
+
|
|
116
159
|
<div>
|
|
117
160
|
<strong>Paste the download links (one per line):</strong>
|
|
118
161
|
<textarea id="links-input" name="links" rows="5" style="width: 100%; padding: 8px; font-family: monospace; resize: vertical;"></textarea>
|
|
119
162
|
</div>
|
|
120
|
-
|
|
163
|
+
|
|
121
164
|
<div>
|
|
122
165
|
<strong>Or upload DLC file:</strong><br>
|
|
123
166
|
<input type="file" id="dlc-file" name="dlc_file" accept=".dlc" />
|
|
124
167
|
</div>
|
|
125
|
-
|
|
168
|
+
|
|
126
169
|
<div>
|
|
127
170
|
{render_button("Submit", "primary", {"type": "submit"})}
|
|
128
171
|
</div>
|
|
@@ -130,10 +173,10 @@ def setup_captcha_routes(app):
|
|
|
130
173
|
</details>
|
|
131
174
|
</div>
|
|
132
175
|
<script>
|
|
133
|
-
// Handle
|
|
176
|
+
// Handle CAPTCHA Bypass toggle
|
|
134
177
|
const bypassDetails = document.getElementById('bypassDetails');
|
|
135
178
|
const bypassSummary = document.getElementById('bypassSummary');
|
|
136
|
-
|
|
179
|
+
|
|
137
180
|
if (bypassDetails && bypassSummary) {{
|
|
138
181
|
bypassDetails.addEventListener('toggle', () => {{
|
|
139
182
|
if (bypassDetails.open) {{
|
|
@@ -143,9 +186,152 @@ def setup_captcha_routes(app):
|
|
|
143
186
|
}}
|
|
144
187
|
}});
|
|
145
188
|
}}
|
|
189
|
+
|
|
190
|
+
// Handle setup instructions hide/show
|
|
191
|
+
const hideSetup = localStorage.getItem('hideSetupInstructions');
|
|
192
|
+
const setupBox = document.getElementById('setup-instructions');
|
|
193
|
+
const showLink = document.getElementById('show-instructions-link');
|
|
194
|
+
|
|
195
|
+
if (hideSetup === 'true') {{
|
|
196
|
+
setupBox.style.display = 'none';
|
|
197
|
+
showLink.style.display = 'block';
|
|
198
|
+
}}
|
|
199
|
+
|
|
200
|
+
// Hide setup instructions
|
|
201
|
+
document.getElementById('hide-setup-btn').addEventListener('click', function() {{
|
|
202
|
+
localStorage.setItem('hideSetupInstructions', 'true');
|
|
203
|
+
setupBox.style.display = 'none';
|
|
204
|
+
showLink.style.display = 'block';
|
|
205
|
+
}});
|
|
206
|
+
|
|
207
|
+
// Show setup instructions again
|
|
208
|
+
document.getElementById('show-setup-btn').addEventListener('click', function(e) {{
|
|
209
|
+
e.preventDefault();
|
|
210
|
+
localStorage.setItem('hideSetupInstructions', 'false');
|
|
211
|
+
setupBox.style.display = 'block';
|
|
212
|
+
showLink.style.display = 'none';
|
|
213
|
+
}});
|
|
146
214
|
</script>
|
|
147
215
|
'''
|
|
148
216
|
|
|
217
|
+
@app.get('/captcha/quick-transfer')
|
|
218
|
+
def handle_quick_transfer():
|
|
219
|
+
"""Handle quick transfer from userscript"""
|
|
220
|
+
import zlib
|
|
221
|
+
|
|
222
|
+
try:
|
|
223
|
+
package_id = request.query.get('pkg_id')
|
|
224
|
+
compressed_links = request.query.get('links', '')
|
|
225
|
+
|
|
226
|
+
if not package_id or not compressed_links:
|
|
227
|
+
return render_centered_html(f'''<h1><img src="{images.logo}" type="image/png" alt="Quasarr logo" class="logo"/>Quasarr</h1>
|
|
228
|
+
<p><b>Error:</b> Missing parameters</p>
|
|
229
|
+
<p>
|
|
230
|
+
{render_button("Back", "secondary", {"onclick": "location.href='/captcha'"})}
|
|
231
|
+
</p>''')
|
|
232
|
+
|
|
233
|
+
# Decode the compressed links using urlsafe_b64decode
|
|
234
|
+
# Add padding if needed
|
|
235
|
+
padding = 4 - (len(compressed_links) % 4)
|
|
236
|
+
if padding != 4:
|
|
237
|
+
compressed_links += '=' * padding
|
|
238
|
+
|
|
239
|
+
try:
|
|
240
|
+
decoded = urlsafe_b64decode(compressed_links)
|
|
241
|
+
except Exception as e:
|
|
242
|
+
info(f"Base64 decode error: {e}")
|
|
243
|
+
return render_centered_html(f'''<h1><img src="{images.logo}" type="image/png" alt="Quasarr logo" class="logo"/>Quasarr</h1>
|
|
244
|
+
<p><b>Error:</b> Failed to decode data: {str(e)}</p>
|
|
245
|
+
<p>
|
|
246
|
+
{render_button("Back", "secondary", {"onclick": "location.href='/captcha'"})}
|
|
247
|
+
</p>''')
|
|
248
|
+
|
|
249
|
+
# Decompress using zlib - use raw deflate format (no header)
|
|
250
|
+
try:
|
|
251
|
+
decompressed = zlib.decompress(decoded, -15) # -15 = raw deflate, no zlib header
|
|
252
|
+
except Exception as e:
|
|
253
|
+
info(f"Decompression error: {e}, trying with header...")
|
|
254
|
+
try:
|
|
255
|
+
# Fallback: try with zlib header
|
|
256
|
+
decompressed = zlib.decompress(decoded)
|
|
257
|
+
except Exception as e2:
|
|
258
|
+
info(f"Decompression also failed with header: {e2}")
|
|
259
|
+
return render_centered_html(f'''<h1><img src="{images.logo}" type="image/png" alt="Quasarr logo" class="logo"/>Quasarr</h1>
|
|
260
|
+
<p><b>Error:</b> Failed to decompress data: {str(e)}</p>
|
|
261
|
+
<p>
|
|
262
|
+
{render_button("Back", "secondary", {"onclick": "location.href='/captcha'"})}
|
|
263
|
+
</p>''')
|
|
264
|
+
|
|
265
|
+
links_text = decompressed.decode('utf-8')
|
|
266
|
+
|
|
267
|
+
# Parse links and restore protocols
|
|
268
|
+
raw_links = [link.strip() for link in links_text.split('\n') if link.strip()]
|
|
269
|
+
links = []
|
|
270
|
+
for link in raw_links:
|
|
271
|
+
if not link.startswith(('http://', 'https://')):
|
|
272
|
+
link = 'https://' + link
|
|
273
|
+
links.append(link)
|
|
274
|
+
|
|
275
|
+
info(f"Quick transfer received {len(links)} links for package {package_id}")
|
|
276
|
+
|
|
277
|
+
# Get package info
|
|
278
|
+
raw_data = shared_state.get_db("protected").retrieve(package_id)
|
|
279
|
+
if not raw_data:
|
|
280
|
+
return render_centered_html(f'''<h1><img src="{images.logo}" type="image/png" alt="Quasarr logo" class="logo"/>Quasarr</h1>
|
|
281
|
+
<p><b>Error:</b> Package not found</p>
|
|
282
|
+
<p>
|
|
283
|
+
{render_button("Back", "secondary", {"onclick": "location.href='/captcha'"})}
|
|
284
|
+
</p>''')
|
|
285
|
+
|
|
286
|
+
data = json.loads(raw_data)
|
|
287
|
+
title = data.get("title", "Unknown")
|
|
288
|
+
password = data.get("password", "")
|
|
289
|
+
|
|
290
|
+
# Download the package
|
|
291
|
+
downloaded = shared_state.download_package(links, title, password, package_id)
|
|
292
|
+
|
|
293
|
+
if downloaded:
|
|
294
|
+
StatsHelper(shared_state).increment_package_with_links(links)
|
|
295
|
+
StatsHelper(shared_state).increment_captcha_decryptions_manual()
|
|
296
|
+
shared_state.get_db("protected").delete(package_id)
|
|
297
|
+
|
|
298
|
+
info(f"Quick transfer successful: {len(links)} links processed")
|
|
299
|
+
|
|
300
|
+
# Check if more CAPTCHAs remain
|
|
301
|
+
remaining_protected = shared_state.get_db("protected").retrieve_all_titles()
|
|
302
|
+
has_more_captchas = bool(remaining_protected)
|
|
303
|
+
|
|
304
|
+
if has_more_captchas:
|
|
305
|
+
solve_button = render_button("Solve another CAPTCHA", "primary",
|
|
306
|
+
{"onclick": "location.href='/captcha'"})
|
|
307
|
+
else:
|
|
308
|
+
solve_button = "<b>No more CAPTCHAs</b>"
|
|
309
|
+
|
|
310
|
+
return render_centered_html(f'''<h1><img src="{images.logo}" type="image/png" alt="Quasarr logo" class="logo"/>Quasarr</h1>
|
|
311
|
+
<p><b>✅ Quick Transfer Successful!</b></p>
|
|
312
|
+
<p>Package "{title}" with {len(links)} link(s) submitted to JDownloader.</p>
|
|
313
|
+
<p>
|
|
314
|
+
{solve_button}
|
|
315
|
+
</p>
|
|
316
|
+
<p>
|
|
317
|
+
{render_button("Back", "secondary", {"onclick": "location.href='/'"})}
|
|
318
|
+
</p>''')
|
|
319
|
+
else:
|
|
320
|
+
StatsHelper(shared_state).increment_failed_decryptions_manual()
|
|
321
|
+
return render_centered_html(f'''<h1><img src="{images.logo}" type="image/png" alt="Quasarr logo" class="logo"/>Quasarr</h1>
|
|
322
|
+
<p><b>Error:</b> Failed to submit package to JDownloader</p>
|
|
323
|
+
<p>
|
|
324
|
+
{render_button("Try Again", "secondary", {"onclick": "location.href='/captcha'"})}
|
|
325
|
+
</p>''')
|
|
326
|
+
|
|
327
|
+
except Exception as e:
|
|
328
|
+
info(f"Quick transfer error: {e}")
|
|
329
|
+
return render_centered_html(f'''<h1><img src="{images.logo}" type="image/png" alt="Quasarr logo" class="logo"/>Quasarr</h1>
|
|
330
|
+
<p><b>Error:</b> {str(e)}</p>
|
|
331
|
+
<p>
|
|
332
|
+
{render_button("Back", "secondary", {"onclick": "location.href='/captcha'"})}
|
|
333
|
+
</p>''')
|
|
334
|
+
|
|
149
335
|
@app.get('/captcha/delete/<package_id>')
|
|
150
336
|
def delete_captcha_package(package_id):
|
|
151
337
|
success = delete_package(shared_state, package_id)
|
|
@@ -14,6 +14,7 @@ from quasarr.downloads.sources.dd import get_dd_download_links
|
|
|
14
14
|
from quasarr.downloads.sources.dt import get_dt_download_links
|
|
15
15
|
from quasarr.downloads.sources.dw import get_dw_download_links
|
|
16
16
|
from quasarr.downloads.sources.mb import get_mb_download_links
|
|
17
|
+
from quasarr.downloads.sources.nk import get_nk_download_links
|
|
17
18
|
from quasarr.downloads.sources.nx import get_nx_download_links
|
|
18
19
|
from quasarr.downloads.sources.sf import get_sf_download_links, resolve_sf_redirect
|
|
19
20
|
from quasarr.downloads.sources.sl import get_sl_download_links
|
|
@@ -202,6 +203,7 @@ def download(shared_state, request_from, title, url, mirror, size_mb, password,
|
|
|
202
203
|
'DT': config.get("dt"),
|
|
203
204
|
'DW': config.get("dw"),
|
|
204
205
|
'MB': config.get("mb"),
|
|
206
|
+
'NK': config.get("nk"),
|
|
205
207
|
'NX': config.get("nx"),
|
|
206
208
|
'SF': config.get("sf"),
|
|
207
209
|
'SL': config.get("sl"),
|
|
@@ -215,6 +217,7 @@ def download(shared_state, request_from, title, url, mirror, size_mb, password,
|
|
|
215
217
|
(flags['DT'], lambda *a: handle_unprotected(*a, func=get_dt_download_links, label='DT')),
|
|
216
218
|
(flags['DW'], lambda *a: handle_protected(*a, func=get_dw_download_links, label='DW')),
|
|
217
219
|
(flags['MB'], lambda *a: handle_protected(*a, func=get_mb_download_links, label='MB')),
|
|
220
|
+
(flags['NK'], lambda *a: handle_protected(*a, func=get_nk_download_links, label='NK')),
|
|
218
221
|
(flags['NX'], lambda *a: handle_unprotected(*a, func=get_nx_download_links, label='NX')),
|
|
219
222
|
(flags['SF'], handle_sf),
|
|
220
223
|
(flags['SL'], handle_sl),
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Quasarr
|
|
3
|
+
# Project by https://github.com/rix1337
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
import requests
|
|
8
|
+
from bs4 import BeautifulSoup
|
|
9
|
+
|
|
10
|
+
from quasarr.providers.log import info, debug
|
|
11
|
+
from urllib.parse import urlparse, urljoin
|
|
12
|
+
|
|
13
|
+
hostname = "nk"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_nk_download_links(shared_state, url, mirror, title):
|
|
17
|
+
host = shared_state.values["config"]("Hostnames").get(hostname)
|
|
18
|
+
headers = {
|
|
19
|
+
'User-Agent': shared_state.values["user_agent"],
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
session = requests.Session()
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
resp = session.get(url, headers=headers, timeout=20)
|
|
26
|
+
soup = BeautifulSoup(resp.text, 'html.parser')
|
|
27
|
+
except Exception as e:
|
|
28
|
+
info(f"{hostname}: could not fetch release page for {title}: {e}")
|
|
29
|
+
return False
|
|
30
|
+
|
|
31
|
+
# download links are provided as anchors with class 'dl-button'
|
|
32
|
+
anchors = soup.select('a.btn-orange')
|
|
33
|
+
candidates = []
|
|
34
|
+
for a in anchors:
|
|
35
|
+
|
|
36
|
+
href = a.get('href', '').strip()
|
|
37
|
+
hoster = href.split('/')[3].lower()
|
|
38
|
+
if not href.lower().startswith(('http://', 'https://')):
|
|
39
|
+
href = 'https://' + host + href
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
href = requests.head(href, headers=headers, allow_redirects=True, timeout=20).url
|
|
43
|
+
except Exception as e:
|
|
44
|
+
info(f"{hostname}: could not resolve download link for {title}: {e}")
|
|
45
|
+
continue
|
|
46
|
+
|
|
47
|
+
if hoster == 'ddl.to':
|
|
48
|
+
hoster = 'ddownload'
|
|
49
|
+
|
|
50
|
+
candidates.append([href, hoster])
|
|
51
|
+
|
|
52
|
+
if not candidates:
|
|
53
|
+
info(f"No external download links found on {hostname} page for {title}")
|
|
54
|
+
|
|
55
|
+
return candidates
|
|
@@ -9,6 +9,7 @@ dd = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAABCElE
|
|
|
9
9
|
dt = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAA4ElEQVR4nD2PsWrCUBSGv3ubBoq+QevQUhAXV6dMRcyTZBV8CCfxCTq4ZOmSJwg+giB4t16p1NCpSFECyY2n5EL7LeeD8/PDr5qmEa01+XrNz35PaAxFUXCrNQ/DIVophbWW19WKt+WSp16PYLvlvtNBHY8ESZLg6ppPaxmMRgymUz4WC577fR5nM3SapryMx0RRxPf5jDjHXRi21bQEWZZhjCGeTIiDgOvpxM3hQLXb+QAiImVZSlVV0tS1XEXkPY7laz5vX0K74h/n/KnyXNxm41351B+tKoVcLt5Vt8svgsSBPKnRQSAAAAAASUVORK5CYII='
|
|
10
10
|
dw = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAA70lEQVR4nAXBTUrDQBiA4febmfjbpqZUsFkJxS6UIq4EvYS46CUExRPkBL2HFM/gIdxIFq4Ff2JNia3JzBefR+bzuZ1Op+E+y/q6Fd/GSe8qijZH1lpfN00uADdZNt5NDh7GJ8dng2HKxvYOBtB6jctms/5S3ePpxeWklw69tZE1IqKqrIxT81U1d4PReCJJ338HXBVURCCokhelMZW467YTt9pi1rUntPCHYJ0ljiyubMJh0yJFuZSk26ENjufPFV0CCeAUfLEo8V7pRBHWOMJvBc5Q+xpnIf8pl+fvi1Lztw9zlO6T7sWw9jy9vPIPUL1kPErau3YAAAAASUVORK5CYII='
|
|
11
11
|
fx = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAABB0lEQVR4nB2LP0sCcQBA3/2Uzugu8E4IoT9cSYhUENFWYSA1FFTQ4hK5SENNDW19hoYcImhvaGgLguYgcIk0haLOE7wrNGzo5A4v9K3vPWknmwt0LYrrunieTygkAAm300EIQTg5nWB3e5O39w9s54t4fISEYfBZq/H4VETIsoxp1ftyJpWkR7lSZXFhnsFIhLBtOxR9n1KliqZFeX4po+saZ4VLTMtC9M61TJrTk2OarR9WV5bIpJfZ2ljH8zxEw3EovVaZm01xd//AsKpwfXNLLKaTmDSQ9vJHwWE+x3ezRbv9i6oqTBkTmLU65xdXSNn9g0CWB2jYDuNjo/y5Lqoy1A+63S7/GeVj+5KBt3UAAAAASUVORK5CYII='
|
|
12
|
+
nk = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAHYYAAB2GAV2iE4EAAAAZdEVYdFNvZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAADrmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4NCjx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4NCgk8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPg0KCQk8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxNCAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo4RUJCOThFRkQ5RTcxMUU1QTcyN0EzQzFGN0YzNjcwNCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo4RUJCOThGMEQ5RTcxMUU1QTcyN0EzQzFGN0YzNjcwNCI+DQoJCQk8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4RUJCOThFREQ5RTcxMUU1QTcyN0EzQzFGN0YzNjcwNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4RUJCOThFRUQ5RTcxMUU1QTcyN0EzQzFGN0YzNjcwNCIvPg0KCQk8L3JkZjpEZXNjcmlwdGlvbj4NCgkJPHJkZjpEZXNjcmlwdGlvbiB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+PHRpZmY6T3JpZW50YXRpb24+MTwvdGlmZjpPcmllbnRhdGlvbj48L3JkZjpEZXNjcmlwdGlvbj48L3JkZjpSREY+DQo8L3g6eG1wbWV0YT4NCjw/eHBhY2tldCBlbmQ9J3cnPz7hg4LgAAAA3UlEQVQoU2NgIAAYGRgYGP7//8/4cHak44//jJfY//3T+S0vdpz/zXvZZ8+/yTIzMDAwhP490ir479ecx89/H2X69nH123vvn/1592HVy6+/rjNeyrPR+/jz927mf3+5v7Pz+vH8/DSXm51Z7NW3v8ec5p11Zfr44fOSv5+/MDB+/fqP4dOnoJ9fvjN++/TtE/P376IMDAwMzL5qYt8Y/v5+ws383+ndb8ajLP9+2T36xZ7O/f9HTIyhFCMjzLVLIw28Hv8ROarA8sL64Ve+wyocX+R//mOQQfIQdgAAAghnscY2ZXIAAAAASUVORK5CYII='
|
|
12
13
|
mb = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAABE0lEQVR4nAEIAff+AQAAAACHttAxAQ0Kjd7o7ToDAQH/GREOxcDT4HK+cErSAYy70DHs/AG6tNjoFNzn6gD5+fwAQjElAIE/JuqWxdZEBBwVD5RSIhsUnsTV/JBRNwT9/v4AjcDU/DsgOxbW6RqUArra5zf39vb/KRwTBKPN3gBMKhwA3unyBJHE2P/i7/U6Auvz+ACkzt4AaTkmAN/u9AARCQYAQysdALXW5ADl8fYAAi4bEMbD5vQBMxoR/CwYEACVxtkAfUMr/PoECAEZDwrFAiAPCmwpEAjq/gcKBAUDAQCQwtcAMSIZBDkbDukIBAJtAmU5KNIP//1F1ePrvScWD/hSLR/4uNXkvAHz9kZ+RS/T0LpzUht5tWAAAAAASUVORK5CYII='
|
|
13
14
|
nx = 'data:image/png;base64,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'
|
|
14
15
|
sf = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAA8ElEQVR4nBXBv0rDQADA4d/lz1lqmlREECUIFTq4FBeHDA6uPkRfwwfxBRx19gmk4GZBBAcjCAUrWEkaTUzucjnx+0R6kzQboZDCb7AWdNmiMo3KLHUmlCcDR/Z2DujvJXRth6kNqqgoXufo6kk6lpzwcEr7fUrx7POTugh9xPZkilE5jh9MsJ2mreaUi0eKdIa7CUIogjjB8wcnyOiM0rmkH+8ih8dY1gTxOeHoA69eLRCOxBvsE21JOmVo8gy3N6T+fMNbPdwiwzG6XFJ/vWC1xY9GvN9dsZxdI+4vxo3rtxLH8q/TFvPbYhqL0Z76AydWbEnTqqOqAAAAAElFTkSuQmCC'
|