quasarr 2.0.0__tar.gz → 2.1.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.

Files changed (87) hide show
  1. {quasarr-2.0.0 → quasarr-2.1.0}/PKG-INFO +36 -23
  2. {quasarr-2.0.0 → quasarr-2.1.0}/README.md +35 -22
  3. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/api/__init__.py +3 -3
  4. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/api/arr/__init__.py +56 -20
  5. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/api/config/__init__.py +1 -1
  6. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/api/packages/__init__.py +115 -54
  7. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/downloads/__init__.py +96 -8
  8. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/downloads/linkcrypters/filecrypt.py +1 -1
  9. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/providers/html_templates.py +65 -10
  10. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/providers/version.py +1 -1
  11. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/search/sources/al.py +1 -1
  12. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/search/sources/by.py +1 -1
  13. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/search/sources/dd.py +2 -1
  14. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/search/sources/dj.py +2 -2
  15. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/search/sources/dl.py +8 -2
  16. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/search/sources/dt.py +1 -1
  17. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/search/sources/dw.py +6 -7
  18. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/search/sources/fx.py +4 -4
  19. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/search/sources/he.py +1 -1
  20. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/search/sources/mb.py +1 -1
  21. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/search/sources/nk.py +1 -1
  22. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/search/sources/nx.py +1 -1
  23. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/search/sources/sf.py +4 -2
  24. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/search/sources/sj.py +2 -2
  25. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/search/sources/sl.py +3 -3
  26. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/search/sources/wd.py +1 -1
  27. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/search/sources/wx.py +4 -3
  28. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr.egg-info/PKG-INFO +36 -23
  29. {quasarr-2.0.0 → quasarr-2.1.0}/LICENSE +0 -0
  30. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/__init__.py +0 -0
  31. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/api/captcha/__init__.py +0 -0
  32. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/api/sponsors_helper/__init__.py +0 -0
  33. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/api/statistics/__init__.py +0 -0
  34. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/downloads/linkcrypters/__init__.py +0 -0
  35. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/downloads/linkcrypters/al.py +0 -0
  36. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/downloads/linkcrypters/hide.py +0 -0
  37. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/downloads/packages/__init__.py +0 -0
  38. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/downloads/sources/__init__.py +0 -0
  39. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/downloads/sources/al.py +0 -0
  40. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/downloads/sources/by.py +0 -0
  41. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/downloads/sources/dd.py +0 -0
  42. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/downloads/sources/dj.py +0 -0
  43. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/downloads/sources/dl.py +0 -0
  44. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/downloads/sources/dt.py +0 -0
  45. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/downloads/sources/dw.py +0 -0
  46. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/downloads/sources/he.py +0 -0
  47. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/downloads/sources/mb.py +0 -0
  48. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/downloads/sources/nk.py +0 -0
  49. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/downloads/sources/nx.py +0 -0
  50. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/downloads/sources/sf.py +0 -0
  51. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/downloads/sources/sj.py +0 -0
  52. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/downloads/sources/sl.py +0 -0
  53. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/downloads/sources/wd.py +0 -0
  54. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/downloads/sources/wx.py +0 -0
  55. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/providers/__init__.py +0 -0
  56. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/providers/auth.py +0 -0
  57. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/providers/cloudflare.py +0 -0
  58. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/providers/html_images.py +0 -0
  59. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/providers/imdb_metadata.py +0 -0
  60. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/providers/jd_cache.py +0 -0
  61. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/providers/log.py +0 -0
  62. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/providers/myjd_api.py +0 -0
  63. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/providers/notifications.py +0 -0
  64. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/providers/obfuscated.py +0 -0
  65. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/providers/sessions/__init__.py +0 -0
  66. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/providers/sessions/al.py +0 -0
  67. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/providers/sessions/dd.py +0 -0
  68. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/providers/sessions/dl.py +0 -0
  69. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/providers/sessions/nx.py +0 -0
  70. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/providers/shared_state.py +0 -0
  71. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/providers/statistics.py +0 -0
  72. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/providers/utils.py +0 -0
  73. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/providers/web_server.py +0 -0
  74. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/search/__init__.py +0 -0
  75. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/search/sources/__init__.py +0 -0
  76. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/storage/__init__.py +0 -0
  77. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/storage/config.py +0 -0
  78. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/storage/setup.py +0 -0
  79. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr/storage/sqlite_database.py +0 -0
  80. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr.egg-info/SOURCES.txt +0 -0
  81. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr.egg-info/dependency_links.txt +0 -0
  82. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr.egg-info/entry_points.txt +0 -0
  83. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr.egg-info/not-zip-safe +0 -0
  84. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr.egg-info/requires.txt +0 -0
  85. {quasarr-2.0.0 → quasarr-2.1.0}/quasarr.egg-info/top_level.txt +0 -0
  86. {quasarr-2.0.0 → quasarr-2.1.0}/setup.cfg +0 -0
  87. {quasarr-2.0.0 → quasarr-2.1.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quasarr
3
- Version: 2.0.0
3
+ Version: 2.1.0
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
@@ -25,7 +25,7 @@ Dynamic: license-file
25
25
  Dynamic: requires-dist
26
26
  Dynamic: summary
27
27
 
28
- #
28
+ #
29
29
 
30
30
  <img src="https://raw.githubusercontent.com/rix1337/Quasarr/main/Quasarr.png" data-canonical-src="https://raw.githubusercontent.com/rix1337/Quasarr/main/Quasarr.png" width="64" height="64" />
31
31
 
@@ -41,7 +41,8 @@ indexers. It simply does not know what NZB files are.
41
41
  Quasarr includes a solution to quickly and easily decrypt protected links.
42
42
  [Active monthly Sponsors get access to SponsorsHelper to do so automatically.](https://github.com/rix1337/Quasarr?tab=readme-ov-file#sponsorshelper)
43
43
  Alternatively, follow the link from the console output (or discord notification) to solve CAPTCHAs manually.
44
- Quasarr will confidently handle the rest. Some CAPTCHA types require [Tampermonkey](https://www.tampermonkey.net/) to be installed in your browser.
44
+ Quasarr will confidently handle the rest. Some CAPTCHA types require [Tampermonkey](https://www.tampermonkey.net/) to be
45
+ installed in your browser.
45
46
 
46
47
  # Instructions
47
48
 
@@ -56,9 +57,11 @@ Quasarr will confidently handle the rest. Some CAPTCHA types require [Tampermonk
56
57
 
57
58
  ## FlareSolverr (Optional)
58
59
 
59
- FlareSolverr is **optional** but **required for some sites** (e.g., AL) that use Cloudflare protection. You can skip FlareSolverr during setup and configure it later via the web UI.
60
+ FlareSolverr is **optional** but **required for some sites** (e.g., AL) that use Cloudflare protection. You can skip
61
+ FlareSolverr during setup and configure it later via the web UI.
60
62
 
61
63
  If using FlareSolverr, provide your URL including the version path:
64
+
62
65
  ```
63
66
  http://192.168.1.1:8191/v1
64
67
  ```
@@ -69,11 +72,13 @@ http://192.168.1.1:8191/v1
69
72
 
70
73
  ## Quasarr
71
74
 
72
- > ⚠️ Quasarr requires at least one valid hostname to start. It does not provide or endorse any specific sources, but community-maintained lists are available:
75
+ > ⚠️ Quasarr requires at least one valid hostname to start. It does not provide or endorse any specific sources, but
76
+ > community-maintained lists are available:
73
77
 
74
78
  🔗 **[https://quasarr-host.name](https://quasarr-host.name)** — community guide for finding hostnames
75
79
 
76
- 📋 Alternatively, browse community suggestions via [pastebin search](https://pastebin.com/search?q=hostnames+quasarr) (login required).
80
+ 📋 Alternatively, browse community suggestions via [pastebin search](https://pastebin.com/search?q=hostnames+quasarr) (
81
+ login required).
77
82
 
78
83
  > Authentication is optional but strongly recommended.
79
84
  >
@@ -84,8 +89,9 @@ http://192.168.1.1:8191/v1
84
89
 
85
90
  ## JDownloader
86
91
 
87
- > ⚠️ If using Docker:
88
- > JDownloader's download path must be available to Radarr/Sonarr/LazyLibrarian with **identical internal and external path mappings**!
92
+ > ⚠️ If using Docker:
93
+ > JDownloader's download path must be available to Radarr/Sonarr/LazyLibrarian with **identical internal and external
94
+ path mappings**!
89
95
  > Matching only the external path is not sufficient.
90
96
 
91
97
  1. Start and connect JDownloader to [My JDownloader](https://my.jdownloader.org)
@@ -94,7 +100,8 @@ http://192.168.1.1:8191/v1
94
100
  <details>
95
101
  <summary>Fresh install recommended</summary>
96
102
 
97
- Consider setting up a fresh JDownloader instance. Quasarr will modify JDownloader's settings to enable Radarr/Sonarr/LazyLibrarian integration.
103
+ Consider setting up a fresh JDownloader instance. Quasarr will modify JDownloader's settings to enable
104
+ Radarr/Sonarr/LazyLibrarian integration.
98
105
 
99
106
  </details>
100
107
 
@@ -102,7 +109,8 @@ Consider setting up a fresh JDownloader instance. Quasarr will modify JDownloade
102
109
 
103
110
  ## Radarr / Sonarr
104
111
 
105
- > ⚠️ **Sonarr users:** Set all shows (including anime) to the **Standard** series type. Quasarr cannot find releases for shows set to Anime/Absolute.
112
+ > ⚠️ **Sonarr users:** Set all shows (including anime) to the **Standard** series type. Quasarr cannot find releases for
113
+ > shows set to Anime/Absolute.
106
114
 
107
115
 
108
116
  Add Quasarr as both a **Newznab Indexer** and **SABnzbd Download Client** using your Quasarr URL and API Key.
@@ -118,9 +126,11 @@ Add Quasarr as both a **Newznab Indexer** and **SABnzbd Download Client** using
118
126
  <summary>Restrict results to a specific mirror</summary>
119
127
 
120
128
  Append the mirror name to your Newznab URL:
129
+
121
130
  ```
122
131
  /api/dropbox/
123
132
  ```
133
+
124
134
  Only releases with `dropbox` in a link will be returned. If the mirror isn't available, the release will fail.
125
135
 
126
136
  </details>
@@ -136,27 +146,29 @@ Only releases with `dropbox` in a link will be returned. If the mirror isn't ava
136
146
 
137
147
  ### SABnzbd+ Downloader
138
148
 
139
- | Setting | Value |
140
- |---------|-------|
149
+ | Setting | Value |
150
+ |----------|----------------------------|
141
151
  | URL/Port | Your Quasarr host and port |
142
- | API Key | Your Quasarr API Key |
143
- | Category | `docs` |
152
+ | API Key | Your Quasarr API Key |
153
+ | Category | `docs` |
144
154
 
145
155
  ### Newznab Provider
146
156
 
147
- | Setting | Value |
148
- |---------|-------|
149
- | URL | Your Quasarr URL |
150
- | API | Your Quasarr API Key |
157
+ | Setting | Value |
158
+ |---------|----------------------|
159
+ | URL | Your Quasarr URL |
160
+ | API | Your Quasarr API Key |
151
161
 
152
162
  ### Fix Import & Processing
153
163
 
154
164
  **Importing:**
165
+
155
166
  - Enable `OpenLibrary api for book/author information`
156
167
  - Set Primary Information Source to `OpenLibrary`
157
168
  - Add to Import languages: `, Unknown` (German users: `, de, ger, de-DE`)
158
169
 
159
170
  **Processing → Folders:**
171
+
160
172
  - Add your Quasarr download path (typically `/downloads/Quasarr/`)
161
173
 
162
174
  </details>
@@ -236,7 +248,8 @@ Most feature requests can be satisfied by:
236
248
  - There are no hostname integrations in active development unless you see an open pull request
237
249
  [here](https://github.com/rix1337/Quasarr/pulls).
238
250
  - **Pull requests are welcome!** Especially for popular hostnames.
239
- - A short guide to set up required dev services is found in [/docker/dev-setup.md](https://github.com/rix1337/Quasarr/blob/main/docker/dev-setup.md)
251
+ - A short guide to set up required dev services is found
252
+ in [/docker/dev-setup.md](https://github.com/rix1337/Quasarr/blob/main/docker/dev-setup.md)
240
253
  - Always reach out on Discord before starting work on a new feature to prevent waste of time.
241
254
  - Please follow the existing code style and project structure.
242
255
  - Anti-bot measures must be circumvented fully by Quasarr. Thus, you will need to provide a working solution for new
@@ -258,11 +271,11 @@ Image access is limited to [active monthly GitHub sponsors](https://github.com/u
258
271
 
259
272
  1. Start your [sponsorship](https://github.com/users/rix1337/sponsorship) first.
260
273
  2. Open [GitHub Classic Token Settings](https://github.com/settings/tokens/new?type=classic)
261
- 3. Name it (e.g., `SponsorsHelper`) and choose unlimited expiration
274
+ 3. Name it (e.g., `SponsorsHelper`) and choose unlimited expiration
262
275
  4. Enable these scopes:
263
- - `read:packages`
264
- - `read:user`
265
- - `read:org`
276
+ - `read:packages`
277
+ - `read:user`
278
+ - `read:org`
266
279
  5. Click **Generate token** and copy it for the next steps
267
280
 
268
281
  ---
@@ -1,4 +1,4 @@
1
- #
1
+ #
2
2
 
3
3
  <img src="https://raw.githubusercontent.com/rix1337/Quasarr/main/Quasarr.png" data-canonical-src="https://raw.githubusercontent.com/rix1337/Quasarr/main/Quasarr.png" width="64" height="64" />
4
4
 
@@ -14,7 +14,8 @@ indexers. It simply does not know what NZB files are.
14
14
  Quasarr includes a solution to quickly and easily decrypt protected links.
15
15
  [Active monthly Sponsors get access to SponsorsHelper to do so automatically.](https://github.com/rix1337/Quasarr?tab=readme-ov-file#sponsorshelper)
16
16
  Alternatively, follow the link from the console output (or discord notification) to solve CAPTCHAs manually.
17
- Quasarr will confidently handle the rest. Some CAPTCHA types require [Tampermonkey](https://www.tampermonkey.net/) to be installed in your browser.
17
+ Quasarr will confidently handle the rest. Some CAPTCHA types require [Tampermonkey](https://www.tampermonkey.net/) to be
18
+ installed in your browser.
18
19
 
19
20
  # Instructions
20
21
 
@@ -29,9 +30,11 @@ Quasarr will confidently handle the rest. Some CAPTCHA types require [Tampermonk
29
30
 
30
31
  ## FlareSolverr (Optional)
31
32
 
32
- FlareSolverr is **optional** but **required for some sites** (e.g., AL) that use Cloudflare protection. You can skip FlareSolverr during setup and configure it later via the web UI.
33
+ FlareSolverr is **optional** but **required for some sites** (e.g., AL) that use Cloudflare protection. You can skip
34
+ FlareSolverr during setup and configure it later via the web UI.
33
35
 
34
36
  If using FlareSolverr, provide your URL including the version path:
37
+
35
38
  ```
36
39
  http://192.168.1.1:8191/v1
37
40
  ```
@@ -42,11 +45,13 @@ http://192.168.1.1:8191/v1
42
45
 
43
46
  ## Quasarr
44
47
 
45
- > ⚠️ Quasarr requires at least one valid hostname to start. It does not provide or endorse any specific sources, but community-maintained lists are available:
48
+ > ⚠️ Quasarr requires at least one valid hostname to start. It does not provide or endorse any specific sources, but
49
+ > community-maintained lists are available:
46
50
 
47
51
  🔗 **[https://quasarr-host.name](https://quasarr-host.name)** — community guide for finding hostnames
48
52
 
49
- 📋 Alternatively, browse community suggestions via [pastebin search](https://pastebin.com/search?q=hostnames+quasarr) (login required).
53
+ 📋 Alternatively, browse community suggestions via [pastebin search](https://pastebin.com/search?q=hostnames+quasarr) (
54
+ login required).
50
55
 
51
56
  > Authentication is optional but strongly recommended.
52
57
  >
@@ -57,8 +62,9 @@ http://192.168.1.1:8191/v1
57
62
 
58
63
  ## JDownloader
59
64
 
60
- > ⚠️ If using Docker:
61
- > JDownloader's download path must be available to Radarr/Sonarr/LazyLibrarian with **identical internal and external path mappings**!
65
+ > ⚠️ If using Docker:
66
+ > JDownloader's download path must be available to Radarr/Sonarr/LazyLibrarian with **identical internal and external
67
+ path mappings**!
62
68
  > Matching only the external path is not sufficient.
63
69
 
64
70
  1. Start and connect JDownloader to [My JDownloader](https://my.jdownloader.org)
@@ -67,7 +73,8 @@ http://192.168.1.1:8191/v1
67
73
  <details>
68
74
  <summary>Fresh install recommended</summary>
69
75
 
70
- Consider setting up a fresh JDownloader instance. Quasarr will modify JDownloader's settings to enable Radarr/Sonarr/LazyLibrarian integration.
76
+ Consider setting up a fresh JDownloader instance. Quasarr will modify JDownloader's settings to enable
77
+ Radarr/Sonarr/LazyLibrarian integration.
71
78
 
72
79
  </details>
73
80
 
@@ -75,7 +82,8 @@ Consider setting up a fresh JDownloader instance. Quasarr will modify JDownloade
75
82
 
76
83
  ## Radarr / Sonarr
77
84
 
78
- > ⚠️ **Sonarr users:** Set all shows (including anime) to the **Standard** series type. Quasarr cannot find releases for shows set to Anime/Absolute.
85
+ > ⚠️ **Sonarr users:** Set all shows (including anime) to the **Standard** series type. Quasarr cannot find releases for
86
+ > shows set to Anime/Absolute.
79
87
 
80
88
 
81
89
  Add Quasarr as both a **Newznab Indexer** and **SABnzbd Download Client** using your Quasarr URL and API Key.
@@ -91,9 +99,11 @@ Add Quasarr as both a **Newznab Indexer** and **SABnzbd Download Client** using
91
99
  <summary>Restrict results to a specific mirror</summary>
92
100
 
93
101
  Append the mirror name to your Newznab URL:
102
+
94
103
  ```
95
104
  /api/dropbox/
96
105
  ```
106
+
97
107
  Only releases with `dropbox` in a link will be returned. If the mirror isn't available, the release will fail.
98
108
 
99
109
  </details>
@@ -109,27 +119,29 @@ Only releases with `dropbox` in a link will be returned. If the mirror isn't ava
109
119
 
110
120
  ### SABnzbd+ Downloader
111
121
 
112
- | Setting | Value |
113
- |---------|-------|
122
+ | Setting | Value |
123
+ |----------|----------------------------|
114
124
  | URL/Port | Your Quasarr host and port |
115
- | API Key | Your Quasarr API Key |
116
- | Category | `docs` |
125
+ | API Key | Your Quasarr API Key |
126
+ | Category | `docs` |
117
127
 
118
128
  ### Newznab Provider
119
129
 
120
- | Setting | Value |
121
- |---------|-------|
122
- | URL | Your Quasarr URL |
123
- | API | Your Quasarr API Key |
130
+ | Setting | Value |
131
+ |---------|----------------------|
132
+ | URL | Your Quasarr URL |
133
+ | API | Your Quasarr API Key |
124
134
 
125
135
  ### Fix Import & Processing
126
136
 
127
137
  **Importing:**
138
+
128
139
  - Enable `OpenLibrary api for book/author information`
129
140
  - Set Primary Information Source to `OpenLibrary`
130
141
  - Add to Import languages: `, Unknown` (German users: `, de, ger, de-DE`)
131
142
 
132
143
  **Processing → Folders:**
144
+
133
145
  - Add your Quasarr download path (typically `/downloads/Quasarr/`)
134
146
 
135
147
  </details>
@@ -209,7 +221,8 @@ Most feature requests can be satisfied by:
209
221
  - There are no hostname integrations in active development unless you see an open pull request
210
222
  [here](https://github.com/rix1337/Quasarr/pulls).
211
223
  - **Pull requests are welcome!** Especially for popular hostnames.
212
- - A short guide to set up required dev services is found in [/docker/dev-setup.md](https://github.com/rix1337/Quasarr/blob/main/docker/dev-setup.md)
224
+ - A short guide to set up required dev services is found
225
+ in [/docker/dev-setup.md](https://github.com/rix1337/Quasarr/blob/main/docker/dev-setup.md)
213
226
  - Always reach out on Discord before starting work on a new feature to prevent waste of time.
214
227
  - Please follow the existing code style and project structure.
215
228
  - Anti-bot measures must be circumvented fully by Quasarr. Thus, you will need to provide a working solution for new
@@ -231,11 +244,11 @@ Image access is limited to [active monthly GitHub sponsors](https://github.com/u
231
244
 
232
245
  1. Start your [sponsorship](https://github.com/users/rix1337/sponsorship) first.
233
246
  2. Open [GitHub Classic Token Settings](https://github.com/settings/tokens/new?type=classic)
234
- 3. Name it (e.g., `SponsorsHelper`) and choose unlimited expiration
247
+ 3. Name it (e.g., `SponsorsHelper`) and choose unlimited expiration
235
248
  4. Enable these scopes:
236
- - `read:packages`
237
- - `read:user`
238
- - `read:org`
249
+ - `read:packages`
250
+ - `read:user`
251
+ - `read:org`
239
252
  5. Click **Generate token** and copy it for the next steps
240
253
 
241
254
  ---
@@ -66,7 +66,7 @@ def get_api(shared_state_dict, shared_state_lock):
66
66
  # JDownloader status
67
67
  jd_status = f"""
68
68
  <div class="status-bar">
69
- <span class="status-item {'status-ok' if jd_connected else 'status-error'}">
69
+ <span class="status-pill {'success' if jd_connected else 'error'}">
70
70
  {'✅' if jd_connected else '❌'} JDownloader {'Connected' if jd_connected else 'Disconnected'}
71
71
  </span>
72
72
  </div>
@@ -389,8 +389,8 @@ def get_api(shared_state_dict, shared_state_lock):
389
389
  </script>
390
390
  """
391
391
  # Add logout link for form auth
392
- logout_html = '<div class="logout-link"><a href="/logout">Logout</a></div>' if show_logout_link() else ''
393
- return render_centered_html(info + logout_html)
392
+ logout_html = '<a href="/logout">Logout</a>' if show_logout_link() else ''
393
+ return render_centered_html(info, footer_content=logout_html)
394
394
 
395
395
  @app.get('/regenerate-api-key')
396
396
  def regenerate_api_key():
@@ -34,18 +34,57 @@ def require_api_key(func):
34
34
  return decorated
35
35
 
36
36
 
37
+ def parse_payload(payload_str):
38
+ """
39
+ Parse the base64-encoded payload string into its components.
40
+
41
+ Supports both legacy 6-field format and new 7-field format:
42
+ - Legacy (6 fields): title|url|mirror|size_mb|password|imdb_id
43
+ - New (7 fields): title|url|mirror|size_mb|password|imdb_id|source_key
44
+
45
+ Returns:
46
+ dict with keys: title, url, mirror, size_mb, password, imdb_id, source_key
47
+ """
48
+ decoded = urlsafe_b64decode(payload_str.encode()).decode()
49
+ parts = decoded.split("|")
50
+
51
+ if len(parts) == 6:
52
+ # Legacy format - no source_key provided
53
+ title, url, mirror, size_mb, password, imdb_id = parts
54
+ source_key = None
55
+ elif len(parts) == 7:
56
+ # New format with source_key
57
+ title, url, mirror, size_mb, password, imdb_id, source_key = parts
58
+ else:
59
+ raise ValueError(f"expected 6 or 7 fields, got {len(parts)}")
60
+
61
+ return {
62
+ "title": title,
63
+ "url": url,
64
+ "mirror": None if mirror == "None" else mirror,
65
+ "size_mb": size_mb,
66
+ "password": password if password else None,
67
+ "imdb_id": imdb_id if imdb_id else None,
68
+ "source_key": source_key if source_key else None
69
+ }
70
+
71
+
37
72
  def setup_arr_routes(app):
38
73
  @app.get('/download/')
39
74
  def fake_nzb_file():
40
75
  payload = request.query.payload
41
76
  decoded_payload = urlsafe_b64decode(payload).decode("utf-8").split("|")
77
+
78
+ # Support both 6 and 7 field formats
42
79
  title = decoded_payload[0]
43
80
  url = decoded_payload[1]
44
81
  mirror = decoded_payload[2]
45
82
  size_mb = decoded_payload[3]
46
83
  password = decoded_payload[4]
47
84
  imdb_id = decoded_payload[5]
48
- return f'<nzb><file title="{title}" url="{url}" mirror="{mirror}" size_mb="{size_mb}" password="{password}" imdb_id="{imdb_id}"/></nzb>'
85
+ source_key = decoded_payload[6] if len(decoded_payload) > 6 else ""
86
+
87
+ return f'<nzb><file title="{title}" url="{url}" mirror="{mirror}" size_mb="{size_mb}" password="{password}" imdb_id="{imdb_id}" source_key="{source_key}"/></nzb>'
49
88
 
50
89
  @app.post('/api')
51
90
  @require_api_key
@@ -65,10 +104,12 @@ def setup_arr_routes(app):
65
104
  size_mb = root.find(".//file").attrib["size_mb"]
66
105
  password = root.find(".//file").attrib.get("password")
67
106
  imdb_id = root.find(".//file").attrib.get("imdb_id")
107
+ source_key = root.find(".//file").attrib.get("source_key") or None
68
108
 
69
109
  info(f'Attempting download for "{title}"')
70
110
  request_from = request.headers.get('User-Agent')
71
- downloaded = download(shared_state, request_from, title, url, mirror, size_mb, password, imdb_id)
111
+ downloaded = download(shared_state, request_from, title, url, mirror, size_mb, password, imdb_id,
112
+ source_key)
72
113
  try:
73
114
  success = downloaded["success"]
74
115
  package_id = downloaded["package_id"]
@@ -166,37 +207,31 @@ def setup_arr_routes(app):
166
207
  if not payload:
167
208
  abort(400, "missing 'payload' parameter in URL")
168
209
 
169
- title = url = mirror = size_mb = password = imdb_id = None
170
210
  try:
171
- decoded = urlsafe_b64decode(payload.encode()).decode()
172
- parts = decoded.split("|")
173
- if len(parts) != 6:
174
- raise ValueError(f"expected 6 fields, got {len(parts)}")
175
- title, url, mirror, size_mb, password, imdb_id = parts
211
+ parsed_payload = parse_payload(payload)
176
212
  except Exception as e:
177
213
  abort(400, f"invalid payload format: {e}")
178
214
 
179
- mirror = None if mirror == "None" else mirror
180
-
181
215
  nzo_ids = []
182
- info(f'Attempting download for "{title}"')
216
+ info(f'Attempting download for "{parsed_payload["title"]}"')
183
217
  request_from = "lazylibrarian"
184
218
 
185
219
  downloaded = download(
186
220
  shared_state,
187
221
  request_from,
188
- title,
189
- url,
190
- mirror,
191
- size_mb,
192
- password or None,
193
- imdb_id or None,
222
+ parsed_payload["title"],
223
+ parsed_payload["url"],
224
+ parsed_payload["mirror"],
225
+ parsed_payload["size_mb"],
226
+ parsed_payload["password"],
227
+ parsed_payload["imdb_id"],
228
+ parsed_payload["source_key"],
194
229
  )
195
230
 
196
231
  try:
197
232
  success = downloaded["success"]
198
233
  package_id = downloaded["package_id"]
199
- title = downloaded.get("title", title)
234
+ title = downloaded.get("title", parsed_payload["title"])
200
235
 
201
236
  if success:
202
237
  info(f'"{title}" added successfully!')
@@ -204,7 +239,7 @@ def setup_arr_routes(app):
204
239
  info(f'"{title}" added unsuccessfully! See log for details.')
205
240
  nzo_ids.append(package_id)
206
241
  except KeyError:
207
- info(f'Failed to download "{title}" - no package_id returned')
242
+ info(f'Failed to download "{parsed_payload["title"]}" - no package_id returned')
208
243
 
209
244
  return {
210
245
  "status": True,
@@ -353,7 +388,8 @@ def setup_arr_routes(app):
353
388
  <enclosure url="{release.get("link", "")}" length="{release.get("size", 0)}" type="application/x-nzb" />
354
389
  </item>'''
355
390
 
356
- requires_placeholder_item = not getattr(request.query, 'imdbid', '') and not getattr(request.query, 'q', '')
391
+ requires_placeholder_item = not getattr(request.query, 'imdbid', '') and not getattr(request.query,
392
+ 'q', '')
357
393
  if requires_placeholder_item and not items:
358
394
  items = f'''
359
395
  <item>
@@ -235,7 +235,7 @@ def setup_config(app, shared_state):
235
235
  }}
236
236
  </script>
237
237
  '''
238
- return render_form("Configure FlareSolverr", form_html)
238
+ return render_form("FlareSolverr", form_html)
239
239
 
240
240
  @app.post('/api/flaresolverr')
241
241
  def set_flaresolverr_url():