quasarr 1.18.0__tar.gz → 1.20.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.18.0 → quasarr-1.20.0}/PKG-INFO +1 -1
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/api/captcha/__init__.py +157 -16
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/downloads/__init__.py +9 -0
- quasarr-1.20.0/quasarr/downloads/sources/dj.py +7 -0
- quasarr-1.20.0/quasarr/downloads/sources/he.py +112 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/downloads/sources/nk.py +3 -7
- quasarr-1.20.0/quasarr/downloads/sources/sj.py +7 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/providers/html_images.py +3 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/providers/html_templates.py +1 -1
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/providers/obfuscated.py +18 -1
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/providers/version.py +1 -1
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/search/__init__.py +12 -0
- quasarr-1.20.0/quasarr/search/sources/dj.py +213 -0
- quasarr-1.20.0/quasarr/search/sources/he.py +196 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/search/sources/nk.py +6 -7
- quasarr-1.20.0/quasarr/search/sources/sj.py +213 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/storage/config.py +3 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr.egg-info/PKG-INFO +1 -1
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr.egg-info/SOURCES.txt +6 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/LICENSE +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/README.md +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/__init__.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/api/__init__.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/api/arr/__init__.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/api/config/__init__.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/api/sponsors_helper/__init__.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/api/statistics/__init__.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/downloads/linkcrypters/__init__.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/downloads/linkcrypters/al.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/downloads/linkcrypters/filecrypt.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/downloads/linkcrypters/hide.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/downloads/packages/__init__.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/downloads/sources/__init__.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/downloads/sources/al.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/downloads/sources/by.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/downloads/sources/dd.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/downloads/sources/dt.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/downloads/sources/dw.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/downloads/sources/mb.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/downloads/sources/nx.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/downloads/sources/sf.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/downloads/sources/sl.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/downloads/sources/wd.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/providers/__init__.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/providers/cloudflare.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/providers/imdb_metadata.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/providers/log.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/providers/myjd_api.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/providers/notifications.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/providers/sessions/__init__.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/providers/sessions/al.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/providers/sessions/dd.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/providers/sessions/nx.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/providers/shared_state.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/providers/statistics.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/providers/web_server.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/search/sources/__init__.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/search/sources/al.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/search/sources/by.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/search/sources/dd.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/search/sources/dt.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/search/sources/dw.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/search/sources/fx.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/search/sources/mb.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/search/sources/nx.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/search/sources/sf.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/search/sources/sl.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/search/sources/wd.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/storage/__init__.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/storage/setup.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr/storage/sqlite_database.py +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr.egg-info/dependency_links.txt +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr.egg-info/entry_points.txt +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr.egg-info/not-zip-safe +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr.egg-info/requires.txt +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/quasarr.egg-info/top_level.txt +0 -0
- {quasarr-1.18.0 → quasarr-1.20.0}/setup.cfg +0 -0
- {quasarr-1.18.0 → quasarr-1.20.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_user_js, junkies_user_js
|
|
20
20
|
from quasarr.providers.statistics import StatsHelper
|
|
21
21
|
|
|
22
22
|
|
|
@@ -58,7 +58,7 @@ def setup_captcha_routes(app):
|
|
|
58
58
|
desired_mirror = None
|
|
59
59
|
|
|
60
60
|
# This is set for circle CAPTCHAs
|
|
61
|
-
|
|
61
|
+
filecrypt_session = data.get("session", None)
|
|
62
62
|
|
|
63
63
|
# This is required for cutcaptcha
|
|
64
64
|
rapid = [ln for ln in links if "rapidgator" in ln[1].lower()]
|
|
@@ -73,15 +73,21 @@ def setup_captcha_routes(app):
|
|
|
73
73
|
"title": title,
|
|
74
74
|
"password": password,
|
|
75
75
|
"mirror": desired_mirror,
|
|
76
|
-
"session":
|
|
76
|
+
"session": filecrypt_session,
|
|
77
77
|
"links": prioritized_links,
|
|
78
78
|
"original_url": original_url
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
encoded_payload = urlsafe_b64encode(json.dumps(payload).encode()).decode()
|
|
82
82
|
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
sj = True
|
|
84
|
+
dj = False
|
|
85
|
+
|
|
86
|
+
if sj or dj:
|
|
87
|
+
debug("Redirecting to Junkies CAPTCHA")
|
|
88
|
+
redirect(f"/captcha/junkies?data={quote(encoded_payload)}")
|
|
89
|
+
elif filecrypt_session:
|
|
90
|
+
debug(f'Redirecting to circle CAPTCHA')
|
|
85
91
|
redirect(f"/captcha/circle?data={quote(encoded_payload)}")
|
|
86
92
|
else:
|
|
87
93
|
debug(f"Redirecting to cutcaptcha")
|
|
@@ -101,13 +107,140 @@ def setup_captcha_routes(app):
|
|
|
101
107
|
except Exception as e:
|
|
102
108
|
return {"error": f"Failed to decode payload: {str(e)}"}
|
|
103
109
|
|
|
104
|
-
@app.get(
|
|
105
|
-
def
|
|
106
|
-
|
|
110
|
+
@app.get("/captcha/junkies")
|
|
111
|
+
def serve_junkies_captcha():
|
|
112
|
+
payload = decode_payload()
|
|
113
|
+
|
|
114
|
+
if "error" in payload:
|
|
115
|
+
return render_centered_html(f'''<h1><img src="{images.logo}" type="image/png" alt="Quasarr logo" class="logo"/>Quasarr</h1>
|
|
116
|
+
<p>{payload["error"]}</p>
|
|
117
|
+
<p>
|
|
118
|
+
{render_button("Back", "secondary", {"onclick": "location.href='/'"})}
|
|
119
|
+
</p>''')
|
|
120
|
+
|
|
121
|
+
package_id = payload.get("package_id")
|
|
122
|
+
title = payload.get("title")
|
|
123
|
+
password = payload.get("password")
|
|
124
|
+
urls = payload.get("links")
|
|
125
|
+
url = urls[0]
|
|
126
|
+
|
|
127
|
+
return render_centered_html(f"""
|
|
128
|
+
<!DOCTYPE html>
|
|
129
|
+
<html>
|
|
130
|
+
<body>
|
|
131
|
+
<h1><img src="{images.logo}" type="image/png" alt="Quasarr logo" class="logo"/>Quasarr</h1>
|
|
132
|
+
<p><b>Package:</b> {title}</p>
|
|
133
|
+
{render_junkies_section(url, package_id, title, password)}
|
|
134
|
+
<p>
|
|
135
|
+
{render_button("Delete Package", "secondary", {"onclick": f"location.href='/captcha/delete/{package_id}'"})}
|
|
136
|
+
</p>
|
|
137
|
+
<p>
|
|
138
|
+
{render_button("Back", "secondary", {"onclick": "location.href='/'"})}
|
|
139
|
+
</p>
|
|
140
|
+
|
|
141
|
+
</body>
|
|
142
|
+
</html>""")
|
|
143
|
+
|
|
144
|
+
def render_junkies_section(url, package_id, title, password):
|
|
145
|
+
"""Render the UI section for SJ and DJ pages"""
|
|
146
|
+
|
|
147
|
+
# Generate userscript URL with transfer params
|
|
148
|
+
# Get base URL of current request
|
|
149
|
+
base_url = request.urlparts.scheme + '://' + request.urlparts.netloc
|
|
150
|
+
transfer_url = f"{base_url}/captcha/quick-transfer"
|
|
151
|
+
|
|
152
|
+
url_with_quick_transfer_params = (
|
|
153
|
+
f"{url}?"
|
|
154
|
+
f"transfer_url={quote(transfer_url)}&"
|
|
155
|
+
f"pkg_id={quote(package_id)}&"
|
|
156
|
+
f"pkg_title={quote(title)}&"
|
|
157
|
+
f"pkg_pass={quote(password)}"
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
return f'''
|
|
161
|
+
<div>
|
|
162
|
+
<!-- One-time setup section - visually separated -->
|
|
163
|
+
<div id="setup-instructions" style="background: #2a2a2a; border: 2px solid #444; border-radius: 8px; padding: 16px; margin-bottom: 24px;">
|
|
164
|
+
<h3 style="margin-top: 0; color: #58a6ff;">First Time Setup:</h3>
|
|
165
|
+
<p style="margin-bottom: 8px;">
|
|
166
|
+
<a href="https://www.tampermonkey.net/" target="_blank" rel="noopener noreferrer">1. Install Tampermonkey</a>
|
|
167
|
+
</p>
|
|
168
|
+
<p style="margin-top: 0; margin-bottom: 12px;">
|
|
169
|
+
<a href="/captcha/junkies.user.js" target="_blank">2. Install this userscript</a>
|
|
170
|
+
</p>
|
|
171
|
+
<p style="margin-top: 0;">
|
|
172
|
+
<button id="hide-setup-btn" type="button" style="background: #444; color: #fff; border: 1px solid #666; padding: 6px 12px; border-radius: 4px; cursor: pointer;">
|
|
173
|
+
✅ Don't show this again
|
|
174
|
+
</button>
|
|
175
|
+
</p>
|
|
176
|
+
</div>
|
|
177
|
+
|
|
178
|
+
<!-- Hidden "show instructions" link -->
|
|
179
|
+
<div id="show-instructions-link" style="display: none; margin-bottom: 16px;">
|
|
180
|
+
<a href="#" id="show-setup-btn" style="color: #58a6ff;">ℹ️ Show instructions again</a>
|
|
181
|
+
</div>
|
|
182
|
+
|
|
183
|
+
<strong><a href="{url_with_quick_transfer_params}" target="_blank">🔗 Obtain the download links here!</a></strong><br><br>
|
|
184
|
+
|
|
185
|
+
<form id="bypass-form" action="/captcha/bypass-submit" method="post" enctype="multipart/form-data">
|
|
186
|
+
<input type="hidden" name="package_id" value="{package_id}" />
|
|
187
|
+
<input type="hidden" name="title" value="{title}" />
|
|
188
|
+
<input type="hidden" name="password" value="{password}" />
|
|
189
|
+
|
|
190
|
+
<div>
|
|
191
|
+
<strong>Paste the download links (one per line):</strong>
|
|
192
|
+
<textarea id="links-input" name="links" rows="5" style="width: 100%; padding: 8px; font-family: monospace; resize: vertical;"></textarea>
|
|
193
|
+
</div>
|
|
194
|
+
|
|
195
|
+
<div>
|
|
196
|
+
{render_button("Submit", "primary", {"type": "submit"})}
|
|
197
|
+
</div>
|
|
198
|
+
</form>
|
|
199
|
+
</div>
|
|
200
|
+
<script>
|
|
201
|
+
// Handle setup instructions hide/show
|
|
202
|
+
const hideSetup = localStorage.getItem('hideJunkiesSetupInstructions');
|
|
203
|
+
const setupBox = document.getElementById('setup-instructions');
|
|
204
|
+
const showLink = document.getElementById('show-instructions-link');
|
|
205
|
+
|
|
206
|
+
if (hideSetup === 'true') {{
|
|
207
|
+
setupBox.style.display = 'none';
|
|
208
|
+
showLink.style.display = 'block';
|
|
209
|
+
}}
|
|
210
|
+
|
|
211
|
+
// Hide setup instructions
|
|
212
|
+
document.getElementById('hide-setup-btn').addEventListener('click', function() {{
|
|
213
|
+
localStorage.setItem('hideJunkiesSetupInstructions', 'true');
|
|
214
|
+
setupBox.style.display = 'none';
|
|
215
|
+
showLink.style.display = 'block';
|
|
216
|
+
}});
|
|
217
|
+
|
|
218
|
+
// Show setup instructions again
|
|
219
|
+
document.getElementById('show-setup-btn').addEventListener('click', function(e) {{
|
|
220
|
+
e.preventDefault();
|
|
221
|
+
localStorage.setItem('hideJunkiesSetupInstructions', 'false');
|
|
222
|
+
setupBox.style.display = 'block';
|
|
223
|
+
showLink.style.display = 'none';
|
|
224
|
+
}});
|
|
225
|
+
</script>
|
|
226
|
+
'''
|
|
227
|
+
|
|
228
|
+
@app.get('/captcha/junkies.user.js')
|
|
229
|
+
def serve_junkies_user_js():
|
|
230
|
+
sj = shared_state.values["config"]("Hostnames").get("sj")
|
|
231
|
+
dj = shared_state.values["config"]("Hostnames").get("dj")
|
|
232
|
+
|
|
233
|
+
content = junkies_user_js(sj, dj)
|
|
234
|
+
response.content_type = 'application/javascript'
|
|
235
|
+
return content
|
|
236
|
+
|
|
237
|
+
@app.get('/captcha/filecrypt.user.js')
|
|
238
|
+
def serve_filecrypt_user_js():
|
|
239
|
+
content = filecrypt_user_js()
|
|
107
240
|
response.content_type = 'application/javascript'
|
|
108
241
|
return content
|
|
109
242
|
|
|
110
|
-
def
|
|
243
|
+
def render_filecrypt_bypass_section(url, package_id, title, password):
|
|
111
244
|
"""Render the bypass UI section for both cutcaptcha and circle captcha pages"""
|
|
112
245
|
|
|
113
246
|
# Generate userscript URL with transfer params
|
|
@@ -135,7 +268,7 @@ def setup_captcha_routes(app):
|
|
|
135
268
|
<a href="https://www.tampermonkey.net/" target="_blank" rel="noopener noreferrer">1. Install Tampermonkey</a>
|
|
136
269
|
</p>
|
|
137
270
|
<p style="margin-top: 0; margin-bottom: 12px;">
|
|
138
|
-
<a href="/captcha/
|
|
271
|
+
<a href="/captcha/filecrypt.user.js" target="_blank">2. Install this userscript</a>
|
|
139
272
|
</p>
|
|
140
273
|
<p style="margin-top: 0;">
|
|
141
274
|
<button id="hide-setup-btn" type="button" style="background: #444; color: #fff; border: 1px solid #666; padding: 6px 12px; border-radius: 4px; cursor: pointer;">
|
|
@@ -146,7 +279,7 @@ def setup_captcha_routes(app):
|
|
|
146
279
|
|
|
147
280
|
<!-- Hidden "show instructions" link -->
|
|
148
281
|
<div id="show-instructions-link" style="display: none; margin-bottom: 16px;">
|
|
149
|
-
<a href="#" id="show-setup-btn" style="color: #58a6ff;
|
|
282
|
+
<a href="#" id="show-setup-btn" style="color: #58a6ff;">ℹ️ Show instructions again</a>
|
|
150
283
|
</div>
|
|
151
284
|
|
|
152
285
|
<strong><a href="{url_with_quick_transfer_params}" target="_blank">🔗 Obtain the download links here!</a></strong><br><br>
|
|
@@ -188,7 +321,7 @@ def setup_captcha_routes(app):
|
|
|
188
321
|
}}
|
|
189
322
|
|
|
190
323
|
// Handle setup instructions hide/show
|
|
191
|
-
const hideSetup = localStorage.getItem('
|
|
324
|
+
const hideSetup = localStorage.getItem('hideFileCryptSetupInstructions');
|
|
192
325
|
const setupBox = document.getElementById('setup-instructions');
|
|
193
326
|
const showLink = document.getElementById('show-instructions-link');
|
|
194
327
|
|
|
@@ -199,7 +332,7 @@ def setup_captcha_routes(app):
|
|
|
199
332
|
|
|
200
333
|
// Hide setup instructions
|
|
201
334
|
document.getElementById('hide-setup-btn').addEventListener('click', function() {{
|
|
202
|
-
localStorage.setItem('
|
|
335
|
+
localStorage.setItem('hideFileCryptSetupInstructions', 'true');
|
|
203
336
|
setupBox.style.display = 'none';
|
|
204
337
|
showLink.style.display = 'block';
|
|
205
338
|
}});
|
|
@@ -207,7 +340,7 @@ def setup_captcha_routes(app):
|
|
|
207
340
|
// Show setup instructions again
|
|
208
341
|
document.getElementById('show-setup-btn').addEventListener('click', function(e) {{
|
|
209
342
|
e.preventDefault();
|
|
210
|
-
localStorage.setItem('
|
|
343
|
+
localStorage.setItem('hideFileCryptSetupInstructions', 'false');
|
|
211
344
|
setupBox.style.display = 'block';
|
|
212
345
|
showLink.style.display = 'none';
|
|
213
346
|
}});
|
|
@@ -426,7 +559,7 @@ def setup_captcha_routes(app):
|
|
|
426
559
|
url = prioritized_links[0][0]
|
|
427
560
|
|
|
428
561
|
# Add bypass section
|
|
429
|
-
bypass_section =
|
|
562
|
+
bypass_section = render_filecrypt_bypass_section(url, package_id, title, password)
|
|
430
563
|
|
|
431
564
|
content = render_centered_html(r'''
|
|
432
565
|
<script type="text/javascript">
|
|
@@ -607,6 +740,14 @@ def setup_captcha_routes(app):
|
|
|
607
740
|
{render_button("Back", "secondary", {"onclick": "location.href='/captcha'"})}
|
|
608
741
|
</p>''')
|
|
609
742
|
|
|
743
|
+
package_exists = shared_state.get_db("protected").retrieve(package_id)
|
|
744
|
+
if not package_exists:
|
|
745
|
+
return render_centered_html(f'''<h1><img src="{images.logo}" type="image/png" alt="Quasarr logo" class="logo"/>Quasarr</h1>
|
|
746
|
+
<p><b>Error:</b> Package not found or already solved.</p>
|
|
747
|
+
<p>
|
|
748
|
+
{render_button("Back", "secondary", {"onclick": "location.href='/captcha'"})}
|
|
749
|
+
</p>''')
|
|
750
|
+
|
|
610
751
|
# Process links input
|
|
611
752
|
if links_input:
|
|
612
753
|
info(f"Processing direct links bypass for {title}")
|
|
@@ -787,7 +928,7 @@ def setup_captcha_routes(app):
|
|
|
787
928
|
return "Missing required parameters"
|
|
788
929
|
|
|
789
930
|
# Add bypass section
|
|
790
|
-
bypass_section =
|
|
931
|
+
bypass_section = render_filecrypt_bypass_section(original_url, package_id, title, password)
|
|
791
932
|
|
|
792
933
|
return render_centered_html(f"""
|
|
793
934
|
<!DOCTYPE html>
|
|
@@ -11,12 +11,15 @@ from quasarr.downloads.linkcrypters.hide import decrypt_links_if_hide
|
|
|
11
11
|
from quasarr.downloads.sources.al import get_al_download_links
|
|
12
12
|
from quasarr.downloads.sources.by import get_by_download_links
|
|
13
13
|
from quasarr.downloads.sources.dd import get_dd_download_links
|
|
14
|
+
from quasarr.downloads.sources.dj import get_dj_download_links
|
|
14
15
|
from quasarr.downloads.sources.dt import get_dt_download_links
|
|
15
16
|
from quasarr.downloads.sources.dw import get_dw_download_links
|
|
17
|
+
from quasarr.downloads.sources.he import get_he_download_links
|
|
16
18
|
from quasarr.downloads.sources.mb import get_mb_download_links
|
|
17
19
|
from quasarr.downloads.sources.nk import get_nk_download_links
|
|
18
20
|
from quasarr.downloads.sources.nx import get_nx_download_links
|
|
19
21
|
from quasarr.downloads.sources.sf import get_sf_download_links, resolve_sf_redirect
|
|
22
|
+
from quasarr.downloads.sources.sj import get_sj_download_links
|
|
20
23
|
from quasarr.downloads.sources.sl import get_sl_download_links
|
|
21
24
|
from quasarr.downloads.sources.wd import get_wd_download_links
|
|
22
25
|
from quasarr.providers.log import info
|
|
@@ -200,12 +203,15 @@ def download(shared_state, request_from, title, url, mirror, size_mb, password,
|
|
|
200
203
|
'AL': config.get("al"),
|
|
201
204
|
'BY': config.get("by"),
|
|
202
205
|
'DD': config.get("dd"),
|
|
206
|
+
'DJ': config.get("dj"),
|
|
203
207
|
'DT': config.get("dt"),
|
|
204
208
|
'DW': config.get("dw"),
|
|
209
|
+
'HE': config.get("he"),
|
|
205
210
|
'MB': config.get("mb"),
|
|
206
211
|
'NK': config.get("nk"),
|
|
207
212
|
'NX': config.get("nx"),
|
|
208
213
|
'SF': config.get("sf"),
|
|
214
|
+
'SJ': config.get("sj"),
|
|
209
215
|
'SL': config.get("sl"),
|
|
210
216
|
'WD': config.get("wd")
|
|
211
217
|
}
|
|
@@ -214,12 +220,15 @@ def download(shared_state, request_from, title, url, mirror, size_mb, password,
|
|
|
214
220
|
(flags['AL'], handle_al),
|
|
215
221
|
(flags['BY'], handle_by),
|
|
216
222
|
(flags['DD'], lambda *a: handle_unprotected(*a, func=get_dd_download_links, label='DD')),
|
|
223
|
+
(flags['DJ'], lambda *a: handle_protected(*a, func=get_dj_download_links, label='DJ')),
|
|
217
224
|
(flags['DT'], lambda *a: handle_unprotected(*a, func=get_dt_download_links, label='DT')),
|
|
218
225
|
(flags['DW'], lambda *a: handle_protected(*a, func=get_dw_download_links, label='DW')),
|
|
226
|
+
(flags['HE'], lambda *a: handle_unprotected(*a, func=get_he_download_links, label='HE')),
|
|
219
227
|
(flags['MB'], lambda *a: handle_protected(*a, func=get_mb_download_links, label='MB')),
|
|
220
228
|
(flags['NK'], lambda *a: handle_protected(*a, func=get_nk_download_links, label='NK')),
|
|
221
229
|
(flags['NX'], lambda *a: handle_unprotected(*a, func=get_nx_download_links, label='NX')),
|
|
222
230
|
(flags['SF'], handle_sf),
|
|
231
|
+
(flags['SJ'], lambda *a: handle_protected(*a, func=get_sj_download_links, label='SJ')),
|
|
223
232
|
(flags['SL'], handle_sl),
|
|
224
233
|
(flags['WD'], handle_wd),
|
|
225
234
|
]
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Quasarr
|
|
3
|
+
# Project by https://github.com/rix1337
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
from urllib.parse import urlparse, urljoin
|
|
7
|
+
|
|
8
|
+
import requests
|
|
9
|
+
from bs4 import BeautifulSoup
|
|
10
|
+
|
|
11
|
+
from quasarr.providers.log import info, debug
|
|
12
|
+
|
|
13
|
+
hostname = "he"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_he_download_links(shared_state, url, mirror, title):
|
|
17
|
+
headers = {
|
|
18
|
+
'User-Agent': shared_state.values["user_agent"],
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
session = requests.Session()
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
resp = session.get(url, headers=headers, timeout=30)
|
|
25
|
+
soup = BeautifulSoup(resp.text, 'html.parser')
|
|
26
|
+
except Exception as e:
|
|
27
|
+
info(f"{hostname}: could not fetch release for {title}: {e}")
|
|
28
|
+
return False
|
|
29
|
+
|
|
30
|
+
imdb_id = None
|
|
31
|
+
try:
|
|
32
|
+
imdb_link = soup.find('a', href=re.compile(r"imdb\.com/title/tt\d+", re.IGNORECASE))
|
|
33
|
+
if imdb_link:
|
|
34
|
+
href = imdb_link['href'].strip()
|
|
35
|
+
m = re.search(r"(tt\d{4,7})", href)
|
|
36
|
+
if m:
|
|
37
|
+
imdb_id = m.group(1)
|
|
38
|
+
else:
|
|
39
|
+
debug(f"{hostname}: imdb_id not found for title {title} in link href.")
|
|
40
|
+
else:
|
|
41
|
+
debug(f"{hostname}: imdb_id link href not found for title {title}.")
|
|
42
|
+
except Exception:
|
|
43
|
+
debug(f"{hostname}: failed to extract imdb_id for title {title}.")
|
|
44
|
+
|
|
45
|
+
anchors = []
|
|
46
|
+
for retries in range(10):
|
|
47
|
+
form = soup.find('form', id=re.compile(r'content-protector-access-form'))
|
|
48
|
+
if not form:
|
|
49
|
+
return False
|
|
50
|
+
|
|
51
|
+
action = form.get('action') or url
|
|
52
|
+
action_url = urljoin(resp.url, action)
|
|
53
|
+
|
|
54
|
+
payload = {}
|
|
55
|
+
for inp in form.find_all('input'):
|
|
56
|
+
name = inp.get('name')
|
|
57
|
+
if not name:
|
|
58
|
+
continue
|
|
59
|
+
value = inp.get('value', '')
|
|
60
|
+
payload[name] = value
|
|
61
|
+
|
|
62
|
+
append_patt = re.compile(r"append\(\s*[\'\"](?P<key>[^\'\"]+)[\'\"]\s*,\s*[\'\"](?P<val>[^\'\"]+)[\'\"]\s*\)",
|
|
63
|
+
re.IGNORECASE)
|
|
64
|
+
|
|
65
|
+
for script in soup.find_all('script'):
|
|
66
|
+
txt = script.string if script.string is not None else script.get_text()
|
|
67
|
+
if not txt:
|
|
68
|
+
continue
|
|
69
|
+
for m in append_patt.finditer(txt):
|
|
70
|
+
payload[m.group('key')] = m.group('val')
|
|
71
|
+
|
|
72
|
+
post_headers = headers.copy()
|
|
73
|
+
post_headers.update({'Referer': resp.url})
|
|
74
|
+
try:
|
|
75
|
+
resp = session.post(action_url, data=payload, headers=post_headers, timeout=30)
|
|
76
|
+
soup = BeautifulSoup(resp.text, 'html.parser')
|
|
77
|
+
except Exception as e:
|
|
78
|
+
info(f"{hostname}: could not submit protector form for {title}: {e}")
|
|
79
|
+
break
|
|
80
|
+
|
|
81
|
+
unlocked = soup.select('.content-protector-access-form')
|
|
82
|
+
if unlocked:
|
|
83
|
+
for u in unlocked:
|
|
84
|
+
anchors.extend(u.find_all('a', href=True))
|
|
85
|
+
|
|
86
|
+
if anchors:
|
|
87
|
+
break
|
|
88
|
+
|
|
89
|
+
links = []
|
|
90
|
+
for a in anchors:
|
|
91
|
+
try:
|
|
92
|
+
href = a['href'].strip()
|
|
93
|
+
|
|
94
|
+
netloc = urlparse(href).netloc
|
|
95
|
+
hoster = netloc.split(':')[0].lower()
|
|
96
|
+
parts = hoster.split('.')
|
|
97
|
+
if len(parts) >= 2:
|
|
98
|
+
hoster = parts[-2]
|
|
99
|
+
|
|
100
|
+
links.append([href, hoster])
|
|
101
|
+
except Exception:
|
|
102
|
+
debug(f"{hostname}: could not resolve download link hoster for {title}")
|
|
103
|
+
continue
|
|
104
|
+
|
|
105
|
+
if not links:
|
|
106
|
+
info(f"No external download links found on {hostname} page for {title}")
|
|
107
|
+
return False
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
"links": links,
|
|
111
|
+
"imdb_id": imdb_id,
|
|
112
|
+
}
|
|
@@ -2,13 +2,10 @@
|
|
|
2
2
|
# Quasarr
|
|
3
3
|
# Project by https://github.com/rix1337
|
|
4
4
|
|
|
5
|
-
import re
|
|
6
|
-
|
|
7
5
|
import requests
|
|
8
6
|
from bs4 import BeautifulSoup
|
|
9
7
|
|
|
10
|
-
from quasarr.providers.log import info
|
|
11
|
-
from urllib.parse import urlparse, urljoin
|
|
8
|
+
from quasarr.providers.log import info
|
|
12
9
|
|
|
13
10
|
hostname = "nk"
|
|
14
11
|
|
|
@@ -28,15 +25,14 @@ def get_nk_download_links(shared_state, url, mirror, title):
|
|
|
28
25
|
info(f"{hostname}: could not fetch release page for {title}: {e}")
|
|
29
26
|
return False
|
|
30
27
|
|
|
31
|
-
# download links are provided as anchors with class 'dl-button'
|
|
32
28
|
anchors = soup.select('a.btn-orange')
|
|
33
29
|
candidates = []
|
|
34
30
|
for a in anchors:
|
|
35
|
-
|
|
31
|
+
|
|
36
32
|
href = a.get('href', '').strip()
|
|
37
33
|
hoster = href.split('/')[3].lower()
|
|
38
34
|
if not href.lower().startswith(('http://', 'https://')):
|
|
39
|
-
href
|
|
35
|
+
href = 'https://' + host + href
|
|
40
36
|
|
|
41
37
|
try:
|
|
42
38
|
href = requests.head(href, headers=headers, allow_redirects=True, timeout=20).url
|
|
@@ -6,12 +6,15 @@ logo = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAX
|
|
|
6
6
|
al = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAA9UlEQVR4nBXBv0rDQADA4d8ld8EQ2yJiGxAchOqgQSFEEEGfQV18DgcHwYcQ36GDg07+wUlwcBApCnUrbYcKIrRIa0qTy534fSI+vbMCi7GSUe7zr6QmOEJjEUhhDcZReHLEQXiLNoKn4S66CHBMjjTKJ0+nHPZPOJrtEPguc+17GuE5fjCD9H57rHYuCT/H3HxUmaYp5aDPRnZBd2kfp9d6I15fYe/qmdryJiVvge3GI1tRnW7rHbF2fG0rXy9E5QFJnoFSNF1Jc1jhp5YgkrMHm2kYtF9R+TdYS6aqzNdjPBek0RolYDHaoSgsWHClQE/GGA1/SzpdtJMWu3cAAAAASUVORK5CYII='
|
|
7
7
|
by = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAMAAADz0U65AAAATlBMVEX///8crf/29fQDo//J7f/u7u7w+v/2/P/8/PyytLWenp6IhoWTwNfPz8+mpaVYxP94eHhryf+75fyB0f+oxNPl5eW4yNGrr68xsfmUlJQWKuGqAAAAQklEQVQI1yWLSRKAIBADMzOAsgiC+/8/aiwvSR+6AUB15mJyZ42ev8ldclI4MWvXuvwQCaGblPxQCmNP9fgyqGf+AkFFAeZ3L10cAAAAAElFTkSuQmCC'
|
|
8
8
|
dd = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAABCElEQVR4nAXBP0sCYRzA8e89d6eQ4SRkdNKQOEVSvQQbegdB4dAgLY1tLS1NvYFoDIIIGtqKXPq3JJGWEQkaDQliGJnaPXf6e/p8rGrt4/CxUl777fZQylYGg4iReHyMxez8kXN1c5c/Pj1D7AhKQqKujQgqCDSrK35evTca/InD+sYmyXSWdqeLFvCHhka9bpyvdgsdCpl0msRkin1/xMLcLKXbIs3mp6UG/R5vL2VKzzV29g4oFAokkh7XxQuGgcbxtTYy6Fr97xaZ6QmeHu55rVYIf9poHeAMR8ZCNLvbW8TGY5x0OrgK7KhLEIY4U6nUeS63tBwGWowR5dgziME4bsTyPO/yH3LufRKlNxKMAAAAAElFTkSuQmCC'
|
|
9
|
+
dj = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAMAAADz0U65AAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAC9UExURY2NjYWGhoeIiYiIiIiIiYWFhoODg4mKillZWYSEhFBMS3x7e0xIR3Bsa0E+PldWVi4wMT4/Px0eHiQkJA8PDwoMDAsMDAsMDAsLCw0NDWxqaHZtZnBrZ2dnZ25qZ21oZJ94XtWNWr6DXG9mYpp2X6p5V6JwVNJ9TsN4UXBgWZhtVaxuTZBbR6xiRMpoQKlgQ6JfRZ5cQHFGN6dOMqFOM5lMM6tPMmZBNCYlJS8mIywlJCglJC8mJCMhIf////64+awAAAAadFJOU1SosLCwokSyl7ugup+6n7ugr5RLlJmYmZA8Hg7dEgAAAAFiS0dEPklkAOMAAAAHdElNRQfpDBESHCL8f1a2AAAAUElEQVQI12NgYGRiYmZhZWNgl5KWkZWT52DgVFBUUlZR5WLgVlPX0NTS5mHg1dHV0zcw5GPgNzI2MTUzF2AQtLC0sraxFWIQFhEVExOXkAQA4WIHfGNBCckAAAAldEVYdGRhdGU6Y3JlYXRlADIwMjUtMTItMTdUMTg6Mjg6MjgrMDA6MDDR5B2HAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDI1LTEyLTE3VDE4OjI4OjI4KzAwOjAwoLmlOwAAACh0RVh0ZGF0ZTp0aW1lc3RhbXAAMjAyNS0xMi0xN1QxODoyODozNCswMDowMPym7g4AAAAASUVORK5CYII='
|
|
9
10
|
dt = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAA4ElEQVR4nD2PsWrCUBSGv3ubBoq+QevQUhAXV6dMRcyTZBV8CCfxCTq4ZOmSJwg+giB4t16p1NCpSFECyY2n5EL7LeeD8/PDr5qmEa01+XrNz35PaAxFUXCrNQ/DIVophbWW19WKt+WSp16PYLvlvtNBHY8ESZLg6ppPaxmMRgymUz4WC577fR5nM3SapryMx0RRxPf5jDjHXRi21bQEWZZhjCGeTIiDgOvpxM3hQLXb+QAiImVZSlVV0tS1XEXkPY7laz5vX0K74h/n/KnyXNxm41351B+tKoVcLt5Vt8svgsSBPKnRQSAAAAAASUVORK5CYII='
|
|
10
11
|
dw = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAA70lEQVR4nAXBTUrDQBiA4febmfjbpqZUsFkJxS6UIq4EvYS46CUExRPkBL2HFM/gIdxIFq4Ff2JNia3JzBefR+bzuZ1Op+E+y/q6Fd/GSe8qijZH1lpfN00uADdZNt5NDh7GJ8dng2HKxvYOBtB6jctms/5S3ePpxeWklw69tZE1IqKqrIxT81U1d4PReCJJ338HXBVURCCokhelMZW467YTt9pi1rUntPCHYJ0ljiyubMJh0yJFuZSk26ENjufPFV0CCeAUfLEo8V7pRBHWOMJvBc5Q+xpnIf8pl+fvi1Lztw9zlO6T7sWw9jy9vPIPUL1kPErau3YAAAAASUVORK5CYII='
|
|
11
12
|
fx = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAABB0lEQVR4nB2LP0sCcQBA3/2Uzugu8E4IoT9cSYhUENFWYSA1FFTQ4hK5SENNDW19hoYcImhvaGgLguYgcIk0haLOE7wrNGzo5A4v9K3vPWknmwt0LYrrunieTygkAAm300EIQTg5nWB3e5O39w9s54t4fISEYfBZq/H4VETIsoxp1ftyJpWkR7lSZXFhnsFIhLBtOxR9n1KliqZFeX4po+saZ4VLTMtC9M61TJrTk2OarR9WV5bIpJfZ2ljH8zxEw3EovVaZm01xd//AsKpwfXNLLKaTmDSQ9vJHwWE+x3ezRbv9i6oqTBkTmLU65xdXSNn9g0CWB2jYDuNjo/y5Lqoy1A+63S7/GeVj+5KBt3UAAAAASUVORK5CYII='
|
|
12
13
|
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='
|
|
14
|
+
he = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAHYYAAB2GAV2iE4EAAACsSURBVChTY2CAgv///zPC2DA+uhh28IiBxZ5FQTWdS8tUgktOLZlHTq2eR05tAoeschxYwTsGpnpRVq6bDMxscxhYue4xsPM8ZBIULWVg57nAwM6uyPCPg0N+DwPD4zgGhnMyDAz32BgY7jAwMJQxMDCeMmdgCAeb8oeBIeEfA4PjMgaG3FQGhnlODIzHHBgY18UzMARjur6+numfuDj3f0lJLogA1DvoCmEAAJVNNF84URktAAAAAElFTkSuQmCC'
|
|
13
15
|
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='
|
|
14
16
|
nx = 'data:image/png;base64,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'
|
|
15
17
|
sf = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAA8ElEQVR4nBXBv0rDQADA4d/lz1lqmlREECUIFTq4FBeHDA6uPkRfwwfxBRx19gmk4GZBBAcjCAUrWEkaTUzucjnx+0R6kzQboZDCb7AWdNmiMo3KLHUmlCcDR/Z2DujvJXRth6kNqqgoXufo6kk6lpzwcEr7fUrx7POTugh9xPZkilE5jh9MsJ2mreaUi0eKdIa7CUIogjjB8wcnyOiM0rmkH+8ih8dY1gTxOeHoA69eLRCOxBvsE21JOmVo8gy3N6T+fMNbPdwiwzG6XFJ/vWC1xY9GvN9dsZxdI+4vxo3rtxLH8q/TFvPbYhqL0Z76AydWbEnTqqOqAAAAAElFTkSuQmCC'
|
|
18
|
+
sj = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAMAAADz0U65AAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAC9UExURY2NjYWGhoeIiYiIiIiIiYWFhoODg4mKillZWYSEhFBMS3x7e0xIR3Bsa0E+PldWVi4wMT4/Px0eHiQkJA8PDwoMDAsMDAsMDAsLCw0NDWxqaHZtZnBrZ2dnZ25qZ21oZJ94XtWNWr6DXG9mYpp2X6p5V6JwVNJ9TsN4UXBgWZhtVaxuTZBbR6xiRMpoQKlgQ6JfRZ5cQHFGN6dOMqFOM5lMM6tPMmZBNCYlJS8mIywlJCglJC8mJCMhIf////64+awAAAAadFJOU1SosLCwokSyl7ugup+6n7ugr5RLlJmYmZA8Hg7dEgAAAAFiS0dEPklkAOMAAAAHdElNRQfpDBESHCL8f1a2AAAAUElEQVQI12NgYGRiYmZhZWNgl5KWkZWT52DgVFBUUlZR5WLgVlPX0NTS5mHg1dHV0zcw5GPgNzI2MTUzF2AQtLC0sraxFWIQFhEVExOXkAQA4WIHfGNBCckAAAAldEVYdGRhdGU6Y3JlYXRlADIwMjUtMTItMTdUMTg6Mjg6MjgrMDA6MDDR5B2HAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDI1LTEyLTE3VDE4OjI4OjI4KzAwOjAwoLmlOwAAACh0RVh0ZGF0ZTp0aW1lc3RhbXAAMjAyNS0xMi0xN1QxODoyODozNCswMDowMPym7g4AAAAASUVORK5CYII='
|
|
16
19
|
sl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAA/ElEQVR4nE3PrUpDYRzH8d/z5tnRozugImIYgjAwGY5egGUG64JRkxgWvIFV0zCIwVsQLLYhWgSDLizJiowVFUHZdJ7zvP7Ftu8NfPgybOwvImcFet0C6FhMtrYTSQg1Ru/id3W7sfTxmc3rQpeE4gk8BZJiigF1kWYLe9rSGZEvR4o/AvRAxBLB8SObzXVqXb/tBjFdJjOCtliJI/U6fDo/CQSwf4ozIM2OGrm2xyGEClQCReO76tZmTabZYcsHmnHOfSvJ+8axCiNtlJDtztdNkLmxbViyEIx7669YxPPlZG44uD99wXs9ltqNbvF8aSbvBgBH9WAWMZX+AJIYacQLryqFAAAAAElFTkSuQmCC'
|
|
17
20
|
wd = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAA90lEQVR4nC3OsS5DUQAG4P8/Pb2kiS4mliaEkMYgTBiQiMVk6C6RsHmAxuoFbHTzCmIR9QSWLko6kIiQCnqHq+fec84vEt8TfMS/5s3jniFf36uD9sTH6Fg9rQ8aDQY2r7trhJmFUY1kW9I4gF0I9wGuZUOM04x+B4o9EvMSZ0D1EVWYkklsnn51TFIOhJ2DwgaN6QiqgsbRh00rseu9J1WsUngGOBmhSvaZnZwdbA1MkWfrwQ2PvXMvwbk7n7taLPKppFpe+cvb8DN8gi09RGmkbEv9GHQLqQZi+bB19WZDdN+WlYskRe/0aNsBaO+fXy4ZxEWKC7/R+XkmFbstdAAAAABJRU5ErkJggg=='
|