quasarr 2.1.2__py3-none-any.whl → 2.1.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of quasarr might be problematic. Click here for more details.

quasarr/api/__init__.py CHANGED
@@ -25,7 +25,10 @@ def get_api(shared_state_dict, shared_state_lock):
25
25
 
26
26
  # Auth: routes must come first, then hook
27
27
  add_auth_routes(app)
28
- add_auth_hook(app, whitelist_prefixes=['/api', '/api/', '/sponsors_helper/', '/download/'])
28
+ add_auth_hook(app,
29
+ whitelist_prefixes=['/api', '/api/', '/sponsors_helper/', '/download/'],
30
+ whitelist_suffixes=['.user.js']
31
+ )
29
32
 
30
33
  setup_arr_routes(app)
31
34
  setup_captcha_routes(app)
@@ -9,14 +9,24 @@ from quasarr.providers.html_templates import render_button, render_centered_html
9
9
 
10
10
 
11
11
  def _get_category_emoji(cat):
12
- return {'movies': '🎬', 'tv': '📺', 'docs': '📄', 'not_quasarr': '📦'}.get(cat, '📦')
12
+ return {'movies': '🎬', 'tv': '📺', 'docs': '📄', 'not_quasarr': ''}.get(cat, '')
13
13
 
14
14
 
15
15
  def _format_size(mb=None, bytes_val=None):
16
16
  if bytes_val is not None:
17
+ # Handle bytes directly for better precision with small files
18
+ if bytes_val == 0:
19
+ return "? MB"
20
+ if bytes_val < 1024 * 1024: # Less than 1 MB
21
+ kb = bytes_val / 1024
22
+ if kb < 1:
23
+ return f"{bytes_val} B"
24
+ return f"{kb:.0f} KB"
17
25
  mb = bytes_val / (1024 * 1024)
18
26
  if mb is None or mb == 0:
19
27
  return "? MB"
28
+ if mb < 1:
29
+ return f"{mb * 1024:.0f} KB"
20
30
  if mb < 1024:
21
31
  return f"{mb:.0f} MB"
22
32
  return f"{mb / 1024:.1f} GB"
@@ -30,7 +40,7 @@ def _render_queue_item(item):
30
40
  filename = item.get('filename', 'Unknown')
31
41
  percentage = item.get('percentage', 0)
32
42
  timeleft = item.get('timeleft', '??:??:??')
33
- mb = item.get('mb', 0)
43
+ bytes_val = item.get('bytes', 0)
34
44
  cat = item.get('cat', 'not_quasarr')
35
45
  is_archive = item.get('is_archive', False)
36
46
  nzo_id = item.get('nzo_id', '')
@@ -51,9 +61,9 @@ def _render_queue_item(item):
51
61
  for prefix in ['[Downloading] ', '[Extracting] ', '[Paused] ', '[Linkgrabber] ', '[CAPTCHA not solved!] ']:
52
62
  display_name = display_name.replace(prefix, '')
53
63
 
54
- archive_badge = '<span class="badge archive">📁 ARCHIVE</span>' if is_archive else ''
64
+ archive_badge = '<span class="badge archive">📁</span>' if is_archive else ''
55
65
  cat_emoji = _get_category_emoji(cat)
56
- size_str = _format_size(mb=mb)
66
+ size_str = _format_size(bytes_val=bytes_val)
57
67
 
58
68
  # Progress bar - show "waiting..." for 0%
59
69
  if percentage == 0:
@@ -84,7 +94,6 @@ def _render_queue_item(item):
84
94
  <div class="package-header">
85
95
  <span class="status-emoji">{status_emoji}</span>
86
96
  <span class="package-name">{display_name}</span>
87
- {archive_badge}
88
97
  </div>
89
98
  <div class="package-progress">
90
99
  {progress_html}
@@ -93,7 +102,8 @@ def _render_queue_item(item):
93
102
  <div class="package-details">
94
103
  <span>⏱️ {timeleft}</span>
95
104
  <span>💾 {size_str}</span>
96
- <span>{cat_emoji} {cat}</span>
105
+ <span>{cat_emoji}</span>
106
+ {archive_badge}
97
107
  </div>
98
108
  {actions}
99
109
  </div>
@@ -119,11 +129,11 @@ def _render_history_item(item):
119
129
  archive_badge = ''
120
130
  if is_archive:
121
131
  if extraction_status == 'SUCCESSFUL':
122
- archive_badge = '<span class="badge extracted">✅ EXTRACTED</span>'
132
+ archive_badge = '<span class="badge extracted">✅</span>'
123
133
  elif extraction_status == 'RUNNING':
124
- archive_badge = '<span class="badge pending">⏳ EXTRACTING</span>'
134
+ archive_badge = '<span class="badge pending">⏳</span>'
125
135
  else:
126
- archive_badge = '<span class="badge archive">📁 ARCHIVE</span>'
136
+ archive_badge = '<span class="badge archive">📁</span>'
127
137
 
128
138
  status_emoji = '❌' if is_error else '✅'
129
139
  error_html = f'<div class="package-error">⚠️ {fail_message}</div>' if fail_message else ''
@@ -143,11 +153,11 @@ def _render_history_item(item):
143
153
  <div class="package-header">
144
154
  <span class="status-emoji">{status_emoji}</span>
145
155
  <span class="package-name">{name}</span>
146
- {archive_badge}
147
156
  </div>
148
157
  <div class="package-details">
149
158
  <span>💾 {size_str}</span>
150
- <span>{cat_emoji} {category}</span>
159
+ <span>{cat_emoji}</span>
160
+ {archive_badge}
151
161
  </div>
152
162
  {error_html}
153
163
  {actions}
@@ -167,7 +177,12 @@ def _render_packages_content():
167
177
  quasarr_history = [p for p in history if p.get('category') != 'not_quasarr']
168
178
  other_history = [p for p in history if p.get('category') == 'not_quasarr']
169
179
 
170
- # Build queue section
180
+ # Check if there's anything at all
181
+ has_quasarr_content = quasarr_queue or quasarr_history
182
+ has_other_content = other_queue or other_history
183
+ has_any_content = has_quasarr_content or has_other_content
184
+
185
+ # Build queue section (only if has items)
171
186
  queue_html = ''
172
187
  if quasarr_queue:
173
188
  queue_items = ''.join(_render_queue_item(item) for item in quasarr_queue)
@@ -177,10 +192,8 @@ def _render_packages_content():
177
192
  <div class="packages-list">{queue_items}</div>
178
193
  </div>
179
194
  '''
180
- else:
181
- queue_html = '<div class="section"><p class="empty-message">No active downloads</p></div>'
182
195
 
183
- # Build history section
196
+ # Build history section (only if has items)
184
197
  history_html = ''
185
198
  if quasarr_history:
186
199
  history_items = ''.join(_render_history_item(item) for item in quasarr_history[:10])
@@ -204,20 +217,28 @@ def _render_packages_content():
204
217
  other_items += ''.join(_render_history_item(item) for item in other_history[:5])
205
218
 
206
219
  plural = 's' if other_count != 1 else ''
220
+ # Only add separator class if there's Quasarr content above
221
+ section_class = 'other-packages-section' if has_quasarr_content else 'other-packages-section no-separator'
207
222
  other_html = f'''
208
- <div class="other-packages-section">
223
+ <div class="{section_class}">
209
224
  <details id="otherPackagesDetails">
210
- <summary id="otherPackagesSummary">Show {other_count} non-Quasarr package{plural}</summary>
225
+ <summary id="otherPackagesSummary">Show {other_count} other package{plural}</summary>
211
226
  <div class="other-packages-content">{other_items}</div>
212
227
  </details>
213
228
  </div>
214
229
  '''
215
230
 
231
+ # Only show "no downloads" if there's literally nothing
232
+ empty_html = ''
233
+ if not has_any_content:
234
+ empty_html = '<p class="empty-message">No packages</p>'
235
+
216
236
  return f'''
217
237
  <div class="packages-container">
218
238
  {queue_html}
219
239
  {history_html}
220
240
  {other_html}
241
+ {empty_html}
221
242
  </div>
222
243
  '''
223
244
 
@@ -283,6 +304,8 @@ def setup_packages_routes(app):
283
304
 
284
305
  {status_message}
285
306
 
307
+ <div id="slow-warning" class="slow-warning" style="display:none;">⚠️ Slow connection detected</div>
308
+
286
309
  <div id="packages-content">
287
310
  {packages_content}
288
311
  </div>
@@ -349,7 +372,26 @@ def setup_packages_routes(app):
349
372
 
350
373
  .empty-message {{ color: var(--text-muted, #888); font-style: italic; text-align: center; padding: 20px; }}
351
374
 
375
+ .slow-warning {{
376
+ text-align: center;
377
+ font-size: 0.85em;
378
+ color: #856404;
379
+ background: #fff3cd;
380
+ border: 1px solid #ffc107;
381
+ padding: 8px 12px;
382
+ border-radius: 6px;
383
+ margin-bottom: 15px;
384
+ }}
385
+ @media (prefers-color-scheme: dark) {{
386
+ .slow-warning {{
387
+ color: #ffc107;
388
+ background: #3d3510;
389
+ border-color: #665c00;
390
+ }}
391
+ }}
392
+
352
393
  .other-packages-section {{ margin-top: 30px; padding-top: 20px; border-top: 1px solid var(--border-color, #ddd); }}
394
+ .other-packages-section.no-separator {{ margin-top: 0; padding-top: 0; border-top: none; }}
353
395
  .other-packages-section summary {{ cursor: pointer; padding: 8px 0; color: var(--text-muted, #666); }}
354
396
  .other-packages-section summary:hover {{ color: var(--link-color, #0066cc); }}
355
397
  .other-packages-content {{ margin-top: 15px; }}
@@ -405,24 +447,51 @@ def setup_packages_routes(app):
405
447
  <script>
406
448
  // Background refresh - fetches content via AJAX, waits 5s between refresh cycles
407
449
  let refreshPaused = false;
450
+ let slowConnection = false;
408
451
 
409
452
  async function refreshContent() {{
410
453
  if (refreshPaused) return;
454
+
455
+ const startTime = Date.now();
456
+ const warningEl = document.getElementById('slow-warning');
457
+
458
+ // Save scroll position before refresh
459
+ const scrollY = window.scrollY;
460
+
461
+ // Show warning after 5s if still loading
462
+ const slowTimer = setTimeout(() => {{
463
+ slowConnection = true;
464
+ if (warningEl) warningEl.style.display = 'block';
465
+ }}, 5000);
466
+
411
467
  try {{
412
468
  const response = await fetch('/api/packages/content');
469
+ const elapsed = Date.now() - startTime;
470
+
471
+ clearTimeout(slowTimer);
472
+
473
+ // Update slow connection state
474
+ if (elapsed < 5000) {{
475
+ slowConnection = false;
476
+ if (warningEl) warningEl.style.display = 'none';
477
+ }} else {{
478
+ slowConnection = true;
479
+ if (warningEl) warningEl.style.display = 'block';
480
+ }}
481
+
413
482
  if (response.ok) {{
414
483
  const html = await response.text();
415
484
  const container = document.getElementById('packages-content');
416
485
  if (container && html) {{
417
486
  container.innerHTML = html;
418
- // Re-apply collapse state after content update
419
487
  restoreCollapseState();
488
+ // Restore scroll position after content update
489
+ window.scrollTo(0, scrollY);
420
490
  }}
421
491
  }}
422
492
  }} catch (e) {{
423
- // Silent fail - will retry on next cycle
493
+ clearTimeout(slowTimer);
424
494
  }}
425
- // Schedule next refresh 5 seconds after this one completes
426
495
  setTimeout(refreshContent, 5000);
427
496
  }}
428
497
 
@@ -434,7 +503,7 @@ def setup_packages_routes(app):
434
503
  const plural = count !== '1' ? 's' : '';
435
504
  if (localStorage.getItem('otherPackagesOpen') === 'true') {{
436
505
  otherDetails.open = true;
437
- otherSummary.textContent = 'Hide ' + count + ' non-Quasarr package' + plural;
506
+ otherSummary.textContent = 'Hide ' + count + ' other package' + plural;
438
507
  }}
439
508
  // Re-attach event listener
440
509
  otherDetails.onclick = null;
@@ -442,23 +511,36 @@ def setup_packages_routes(app):
442
511
  localStorage.setItem('otherPackagesOpen', this.open);
443
512
  const summaryEl = document.getElementById('otherPackagesSummary');
444
513
  if (summaryEl) {{
445
- summaryEl.textContent = (this.open ? 'Hide ' : 'Show ') + count + ' non-Quasarr package' + plural;
514
+ summaryEl.textContent = (this.open ? 'Hide ' : 'Show ') + count + ' other package' + plural;
446
515
  }}
447
516
  }});
448
517
  }}
449
518
  }}
450
519
 
451
- // Start refresh cycle after initial 5s delay
452
- setTimeout(refreshContent, 5000);
453
-
454
520
  // Initial collapse state setup
455
521
  restoreCollapseState();
456
522
 
457
- // Clear status message from URL after display
523
+ // Clear status message from URL after display and auto-hide after 5s
458
524
  if (window.location.search.includes('deleted=')) {{
459
525
  const url = new URL(window.location);
460
526
  url.searchParams.delete('deleted');
461
527
  window.history.replaceState({{}}, '', url);
528
+
529
+ // Hide the status message after 5 seconds
530
+ const statusMsg = document.querySelector('.status-message');
531
+ if (statusMsg) {{
532
+ setTimeout(() => {{
533
+ statusMsg.style.transition = 'opacity 0.3s';
534
+ statusMsg.style.opacity = '0';
535
+ setTimeout(() => statusMsg.remove(), 300);
536
+ }}, 5000);
537
+ }}
538
+
539
+ // Reset refresh - start fresh 5s countdown after delete
540
+ setTimeout(refreshContent, 5000);
541
+ }} else {{
542
+ // Normal start - 5s delay
543
+ setTimeout(refreshContent, 5000);
462
544
  }}
463
545
 
464
546
  // Delete modal
@@ -510,22 +510,27 @@ def get_packages(shared_state, _cache=None):
510
510
  package_type = "protected"
511
511
  package_uuid = None
512
512
 
513
- if package_id:
513
+ # Use package_id if available, otherwise use uuid as fallback for non-Quasarr packages
514
+ effective_id = package_id or package_uuid
515
+
516
+ if effective_id:
514
517
  try:
515
- mb_left = int(mb_left) if mb_left else 0
516
- mb = int(mb) if mb else 0
517
518
  percentage = int(100 * (mb - mb_left) / mb) if mb > 0 else 0
518
519
  except (ZeroDivisionError, ValueError, TypeError):
519
520
  percentage = 0
520
521
 
522
+ # Keep mb/mbleft as integers for API compatibility, add bytes for UI display
523
+ bytes_total = int(mb * 1024 * 1024) if mb else 0
524
+
521
525
  downloads["queue"].append({
522
526
  "index": queue_index,
523
- "nzo_id": package_id,
527
+ "nzo_id": effective_id,
524
528
  "priority": "Normal",
525
529
  "filename": name,
526
530
  "cat": category,
527
- "mbleft": mb_left,
528
- "mb": mb,
531
+ "mbleft": int(mb_left) if mb_left else 0,
532
+ "mb": int(mb) if mb else 0,
533
+ "bytes": bytes_total,
529
534
  "status": "Downloading",
530
535
  "percentage": percentage,
531
536
  "timeleft": time_left,
@@ -535,18 +540,21 @@ def get_packages(shared_state, _cache=None):
535
540
  })
536
541
  queue_index += 1
537
542
  else:
538
- debug(f"get_packages: Skipping queue package without package_id: {name}")
543
+ debug(f"get_packages: Skipping queue package without package_id or uuid: {name}")
539
544
 
540
545
  elif package["location"] == "history":
541
546
  details = package["details"]
542
547
  name = details.get("name", "unknown")
543
548
  try:
544
- size = int(details.get("bytesLoaded", 0))
549
+ # Use bytesLoaded first, fall back to bytesTotal for failed/incomplete downloads
550
+ size = int(details.get("bytesLoaded", 0)) or int(details.get("bytesTotal", 0))
545
551
  except (KeyError, TypeError, ValueError):
546
552
  size = 0
547
553
  storage = details.get("saveTo", "/")
548
554
 
549
555
  package_id = package.get("comment")
556
+ # Use package_id if available, otherwise use uuid as fallback for non-Quasarr packages
557
+ effective_id = package_id or package.get("uuid")
550
558
  category = get_category_from_package_id(package_id)
551
559
 
552
560
  error = package.get("error")
@@ -562,7 +570,7 @@ def get_packages(shared_state, _cache=None):
562
570
  "category": category,
563
571
  "storage": storage,
564
572
  "status": status,
565
- "nzo_id": package_id,
573
+ "nzo_id": effective_id,
566
574
  "name": name,
567
575
  "bytes": int(size),
568
576
  "percentage": 100,
@@ -671,7 +679,8 @@ def delete_package(shared_state, package_id):
671
679
  found = False
672
680
  for package_location in packages:
673
681
  for package in packages[package_location]:
674
- if package.get("nzo_id") == package_id:
682
+ # Compare as strings to handle int UUIDs from JDownloader
683
+ if str(package.get("nzo_id", "")) == str(package_id):
675
684
  found = True
676
685
  package_type = package.get("type")
677
686
  package_uuid = package.get("uuid")
quasarr/providers/auth.py CHANGED
@@ -273,7 +273,7 @@ def add_auth_routes(app):
273
273
  return _handle_logout()
274
274
 
275
275
 
276
- def add_auth_hook(app, whitelist_prefixes=None):
276
+ def add_auth_hook(app, whitelist_prefixes=None, whitelist_suffixes=None):
277
277
  """Add authentication hook to a Bottle app.
278
278
 
279
279
  Args:
@@ -299,6 +299,11 @@ def add_auth_hook(app, whitelist_prefixes=None):
299
299
  if path.startswith(prefix):
300
300
  return
301
301
 
302
+ # Check whitelist suffixes:
303
+ for suffix in whitelist_suffixes:
304
+ if path.endswith(suffix):
305
+ return
306
+
302
307
  # Check authentication
303
308
  if is_form_auth():
304
309
  if not check_form_auth():
@@ -8,7 +8,7 @@ import requests
8
8
 
9
9
 
10
10
  def get_version():
11
- return "2.1.2"
11
+ return "2.1.4"
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: 2.1.2
3
+ Version: 2.1.4
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
@@ -1,9 +1,9 @@
1
1
  quasarr/__init__.py,sha256=cEtxN2AuwKvrxpIvAR7UL997VtYQ4iN3Eo3ZnP-WjZQ,14682
2
- quasarr/api/__init__.py,sha256=EEQSC7OKDyZYjMpzuz1T7bOFR9J54NhP_04XcULIvGM,16296
2
+ quasarr/api/__init__.py,sha256=yrDJM0qxmsOruOyqUwhSmmaT6E3DLK-yPy7Lutk1WYM,16384
3
3
  quasarr/api/arr/__init__.py,sha256=eEop8A5t936uT5azn4qz0bq1DMX84_Ja16wyleGFhyM,18495
4
4
  quasarr/api/captcha/__init__.py,sha256=2pca9jnJMWZECHeAvKP9Lwsa3_GkVsvQEn7rof8Ep1s,73504
5
5
  quasarr/api/config/__init__.py,sha256=HDoqRv6El-e5iejVpwEz6ttySjDeiTQGom5D__nachU,13682
6
- quasarr/api/packages/__init__.py,sha256=srQw71KSMr2gjvrISyXute606QJhPdVNwaGzRM9OrVA,22989
6
+ quasarr/api/packages/__init__.py,sha256=0X7U47xfU9zvNT-yxFGhQG3upqX7q-7PEC6dETRD-I8,26407
7
7
  quasarr/api/sponsors_helper/__init__.py,sha256=vZIFGkc5HTRozjvi47tqxz6XpwDe8sDXVyeydc9k0Y0,6708
8
8
  quasarr/api/statistics/__init__.py,sha256=NrBAjjHkIUE95HhPUGIfNqh2IqBqJ_zm00S90Y-Qnus,7038
9
9
  quasarr/downloads/__init__.py,sha256=BUZpqWN3VnYSM8ZX4lC3MXVfShwx95I6FKz8Xl95T1s,16004
@@ -11,7 +11,7 @@ quasarr/downloads/linkcrypters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5
11
11
  quasarr/downloads/linkcrypters/al.py,sha256=mfUG5VclC_-FcGoZL9zHYD7dz7X_YpaNmoKkgiyl9-0,8812
12
12
  quasarr/downloads/linkcrypters/filecrypt.py,sha256=nUZCTmvKylaNk1KAXcYUV1FgQCVAKNE3roXCNaqHLYA,17057
13
13
  quasarr/downloads/linkcrypters/hide.py,sha256=H4hJWhENkszV1u_ULC3aOW2fu9infC-Nv-7wx2DYqrA,6266
14
- quasarr/downloads/packages/__init__.py,sha256=zDMhLJz-16r4WSv2zzSlcBJEFrIUky2dRDkQaQLVSXY,32055
14
+ quasarr/downloads/packages/__init__.py,sha256=nBG4-O5-J3DRVp8tzMUN5HsUA946KwVyxhK0I69kAUw,32740
15
15
  quasarr/downloads/sources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  quasarr/downloads/sources/al.py,sha256=g587VESZRZHZ03uxHKpufEr5qAtzbyGLmoijksU35jk,27297
17
17
  quasarr/downloads/sources/by.py,sha256=kmUTn3izayRCV7W-t0E4kYE8qTbt3L3reCLozfvRGcU,3807
@@ -30,7 +30,7 @@ quasarr/downloads/sources/sl.py,sha256=jWprFt1Hew1T67fB1O_pc9YWgc3NVh30KXSwSyS50
30
30
  quasarr/downloads/sources/wd.py,sha256=kr1I1uJa7ZkEPH2LA6alXTJEn0LBPgLCwIh3wLXwCv8,4447
31
31
  quasarr/downloads/sources/wx.py,sha256=NzNNeqVL6sKkFKyreW-oerrreb5QP2tUGHTWHM5pMCU,7013
32
32
  quasarr/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
- quasarr/providers/auth.py,sha256=eWYXyw_q0v2rMihiAlltqFF8V0Epu_s63ye1Th4i5Tg,10372
33
+ quasarr/providers/auth.py,sha256=h0GuqLSvzzH0lduMXxVVs6OMYFBM8YBnamtZsRF7Ny8,10537
34
34
  quasarr/providers/cloudflare.py,sha256=9iet8runc2VHVcA0_2z1qkrL6D5JKqz1ndktqCgsJFs,7873
35
35
  quasarr/providers/html_images.py,sha256=2n82gTJg7E7q2ytPFN4FWouYTIlmPYu_iHFtG7uktIA,28482
36
36
  quasarr/providers/html_templates.py,sha256=22g3WhAmwDQgMqaXirVaFF1LtlSxHS-Fjm2gpRcbMNg,12463
@@ -43,7 +43,7 @@ quasarr/providers/obfuscated.py,sha256=d0dxu3oPqDqN8I7qmGPPIBqjLzTQbZTQsLAZ5auw1
43
43
  quasarr/providers/shared_state.py,sha256=5a_ZbGqTvt4-OqBt2a1WtR9I5J_Ky7IlkEY8EGtKVu8,30646
44
44
  quasarr/providers/statistics.py,sha256=cEQixYnDMDqtm5wWe40E_2ucyo4mD0n3SrfelhQi1L8,6452
45
45
  quasarr/providers/utils.py,sha256=mcUPbcXMsLmrYv0CTZO5a9aOt2-JLyL3SZxu6N8OyjU,12075
46
- quasarr/providers/version.py,sha256=_j_KhmgUu-CE4O_-aL3DAyrzwvkeTUXg6-wLhD-1Z6Y,4003
46
+ quasarr/providers/version.py,sha256=viG1avqtR1pw7V6UDPJRnVo5bxMllFUzhKf7fVFXt_Q,4003
47
47
  quasarr/providers/web_server.py,sha256=AYd0KRxdDWMBr87BP8wlSMuL4zZo0I_rY-vHBai6Pfg,1688
48
48
  quasarr/providers/sessions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
49
  quasarr/providers/sessions/al.py,sha256=WXue9LaT4y0BzsbKtHbN6bb_72c4AZZWR9NP-vg9-cg,12462
@@ -73,9 +73,9 @@ quasarr/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
73
73
  quasarr/storage/config.py,sha256=SSTgIce2FVYoVTK_6OCU3msknhxuLA3EC4Kcrrf_dxQ,6378
74
74
  quasarr/storage/setup.py,sha256=eXtgUqMacbaUDy-dszPtT15O9lJKSO1eI3v0jGjMiUA,42361
75
75
  quasarr/storage/sqlite_database.py,sha256=yMqFQfKf0k7YS-6Z3_7pj4z1GwWSXJ8uvF4IydXsuTE,3554
76
- quasarr-2.1.2.dist-info/licenses/LICENSE,sha256=QQFCAfDgt7lSA8oSWDHIZ9aTjFbZaBJdjnGOHkuhK7k,1060
77
- quasarr-2.1.2.dist-info/METADATA,sha256=u3iuK1WwbY0hV84T2qJF1P3awC_vlq7ZcLGdsY8A5XA,14914
78
- quasarr-2.1.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
79
- quasarr-2.1.2.dist-info/entry_points.txt,sha256=gXi8mUKsIqKVvn-bOc8E5f04sK_KoMCC-ty6b2Hf-jc,40
80
- quasarr-2.1.2.dist-info/top_level.txt,sha256=dipJdaRda5ruTZkoGfZU60bY4l9dtPlmOWwxK_oGSF0,8
81
- quasarr-2.1.2.dist-info/RECORD,,
76
+ quasarr-2.1.4.dist-info/licenses/LICENSE,sha256=QQFCAfDgt7lSA8oSWDHIZ9aTjFbZaBJdjnGOHkuhK7k,1060
77
+ quasarr-2.1.4.dist-info/METADATA,sha256=TMPUtWRbDzFwakaRor7JLnx2TwKZFUqB9-SZVoJbTH4,14914
78
+ quasarr-2.1.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
79
+ quasarr-2.1.4.dist-info/entry_points.txt,sha256=gXi8mUKsIqKVvn-bOc8E5f04sK_KoMCC-ty6b2Hf-jc,40
80
+ quasarr-2.1.4.dist-info/top_level.txt,sha256=dipJdaRda5ruTZkoGfZU60bY4l9dtPlmOWwxK_oGSF0,8
81
+ quasarr-2.1.4.dist-info/RECORD,,