quasarr 2.4.8__tar.gz → 2.4.10__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 (99) hide show
  1. {quasarr-2.4.8 → quasarr-2.4.10}/.github/workflows/HostnameRedaction.yml +1 -1
  2. quasarr-2.4.10/.github/workflows/PullRequests.yml +334 -0
  3. {quasarr-2.4.8 → quasarr-2.4.10}/.github/workflows/Release.yml +68 -12
  4. {quasarr-2.4.8 → quasarr-2.4.10}/.gitignore +1 -2
  5. quasarr-2.4.10/CONTRIBUTING.md +42 -0
  6. {quasarr-2.4.8 → quasarr-2.4.10}/PKG-INFO +4 -3
  7. {quasarr-2.4.8 → quasarr-2.4.10}/Quasarr.py +1 -1
  8. {quasarr-2.4.8 → quasarr-2.4.10}/README.md +2 -1
  9. {quasarr-2.4.8 → quasarr-2.4.10}/docker/Dockerfile +5 -4
  10. quasarr-2.4.10/maintenance.py +284 -0
  11. {quasarr-2.4.8 → quasarr-2.4.10}/pyproject.toml +13 -3
  12. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/__init__.py +134 -70
  13. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/api/__init__.py +40 -31
  14. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/api/arr/__init__.py +116 -108
  15. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/api/captcha/__init__.py +262 -137
  16. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/api/config/__init__.py +76 -46
  17. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/api/packages/__init__.py +138 -102
  18. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/api/sponsors_helper/__init__.py +29 -16
  19. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/api/statistics/__init__.py +19 -19
  20. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/downloads/__init__.py +165 -72
  21. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/downloads/linkcrypters/al.py +35 -18
  22. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/downloads/linkcrypters/filecrypt.py +107 -52
  23. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/downloads/linkcrypters/hide.py +5 -6
  24. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/downloads/packages/__init__.py +342 -177
  25. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/downloads/sources/al.py +191 -100
  26. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/downloads/sources/by.py +31 -13
  27. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/downloads/sources/dd.py +27 -14
  28. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/downloads/sources/dj.py +1 -3
  29. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/downloads/sources/dl.py +126 -71
  30. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/downloads/sources/dt.py +11 -5
  31. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/downloads/sources/dw.py +28 -14
  32. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/downloads/sources/he.py +32 -24
  33. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/downloads/sources/mb.py +19 -9
  34. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/downloads/sources/nk.py +14 -10
  35. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/downloads/sources/nx.py +8 -18
  36. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/downloads/sources/sf.py +45 -20
  37. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/downloads/sources/sj.py +1 -3
  38. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/downloads/sources/sl.py +9 -5
  39. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/downloads/sources/wd.py +32 -12
  40. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/downloads/sources/wx.py +35 -21
  41. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/providers/auth.py +42 -37
  42. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/providers/cloudflare.py +28 -30
  43. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/providers/hostname_issues.py +2 -1
  44. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/providers/html_images.py +2 -2
  45. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/providers/html_templates.py +22 -14
  46. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/providers/imdb_metadata.py +149 -80
  47. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/providers/jd_cache.py +131 -39
  48. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/providers/log.py +1 -1
  49. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/providers/myjd_api.py +260 -196
  50. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/providers/notifications.py +53 -41
  51. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/providers/obfuscated.py +9 -4
  52. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/providers/sessions/al.py +71 -55
  53. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/providers/sessions/dd.py +21 -14
  54. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/providers/sessions/dl.py +30 -19
  55. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/providers/sessions/nx.py +23 -14
  56. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/providers/shared_state.py +292 -141
  57. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/providers/statistics.py +75 -43
  58. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/providers/utils.py +33 -27
  59. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/providers/version.py +45 -14
  60. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/providers/web_server.py +10 -5
  61. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/search/__init__.py +30 -18
  62. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/search/sources/al.py +124 -73
  63. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/search/sources/by.py +110 -59
  64. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/search/sources/dd.py +57 -35
  65. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/search/sources/dj.py +69 -48
  66. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/search/sources/dl.py +159 -100
  67. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/search/sources/dt.py +110 -74
  68. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/search/sources/dw.py +121 -61
  69. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/search/sources/fx.py +108 -62
  70. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/search/sources/he.py +78 -49
  71. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/search/sources/mb.py +96 -48
  72. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/search/sources/nk.py +80 -50
  73. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/search/sources/nx.py +91 -62
  74. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/search/sources/sf.py +171 -106
  75. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/search/sources/sj.py +69 -48
  76. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/search/sources/sl.py +115 -71
  77. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/search/sources/wd.py +67 -44
  78. quasarr-2.4.10/quasarr/search/sources/wx.py +417 -0
  79. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/storage/config.py +65 -52
  80. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/storage/setup.py +238 -140
  81. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/storage/sqlite_database.py +10 -4
  82. quasarr-2.4.10/uv.lock +431 -0
  83. quasarr-2.4.8/.github/workflows/Beta.yml +0 -240
  84. quasarr-2.4.8/.github/workflows/PrVersionBumpCheck.yml +0 -138
  85. quasarr-2.4.8/docker/dev-setup.md +0 -21
  86. quasarr-2.4.8/quasarr/search/sources/wx.py +0 -352
  87. {quasarr-2.4.8 → quasarr-2.4.10}/.github/FUNDING.yml +0 -0
  88. {quasarr-2.4.8 → quasarr-2.4.10}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  89. {quasarr-2.4.8 → quasarr-2.4.10}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  90. {quasarr-2.4.8 → quasarr-2.4.10}/LICENSE +0 -0
  91. {quasarr-2.4.8 → quasarr-2.4.10}/Quasarr.png +0 -0
  92. {quasarr-2.4.8 → quasarr-2.4.10}/docker/dev-services-compose.yml +0 -0
  93. {quasarr-2.4.8 → quasarr-2.4.10}/docker/docker-compose.yml +0 -0
  94. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/downloads/linkcrypters/__init__.py +0 -0
  95. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/downloads/sources/__init__.py +0 -0
  96. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/providers/__init__.py +0 -0
  97. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/providers/sessions/__init__.py +0 -0
  98. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/search/sources/__init__.py +0 -0
  99. {quasarr-2.4.8 → quasarr-2.4.10}/quasarr/storage/__init__.py +0 -0
@@ -4,7 +4,7 @@ on:
4
4
  issues:
5
5
  types: [ opened, edited ]
6
6
  pull_request:
7
- types: [ opened, edited ]
7
+ types: [ opened, closed, reopened, synchronize, edited ]
8
8
  issue_comment:
9
9
  types: [ created, edited ]
10
10
  pull_request_review_comment:
@@ -0,0 +1,334 @@
1
+ name: CI/CD & Beta Build
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ pull_request:
6
+
7
+ concurrency:
8
+ group: ${{ github.workflow }}-${{ github.ref }}
9
+ cancel-in-progress: true
10
+
11
+ env:
12
+ GHCR_ENDPOINT: "ghcr.io/rix1337/quasarr"
13
+ DESCRIPTION: "Quasarr connects JDownloader with Radarr, Sonarr and LazyLibrarian."
14
+
15
+ jobs:
16
+ quality-check:
17
+ name: Check & Auto-Fix
18
+ runs-on: ubuntu-latest
19
+ permissions:
20
+ contents: write
21
+ pull-requests: write
22
+ actions: write
23
+ outputs:
24
+ changes_pushed: ${{ steps.manager.outputs.changes_pushed }}
25
+ steps:
26
+ - uses: actions/checkout@v6
27
+ with:
28
+ repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
29
+ ref: ${{ github.head_ref || github.ref_name }}
30
+ fetch-depth: 0
31
+
32
+ - name: Install uv
33
+ uses: astral-sh/setup-uv@v5
34
+ with:
35
+ enable-cache: true
36
+
37
+ # We just install python here so uv run has something to target
38
+ - run: uv python install 3.12
39
+
40
+ - name: Run Maintenance
41
+ id: manager
42
+ env:
43
+ GH_TOKEN: ${{ github.token }}
44
+ PR_NUMBER: ${{ github.event.pull_request.number }}
45
+ TARGET_REF: ${{ github.head_ref || github.ref_name }}
46
+ GITHUB_REPO: ${{ github.repository }}
47
+ WORKFLOW_NAME: ${{ github.workflow }}
48
+ run: |
49
+ uv run maintenance.py --ci
50
+
51
+ version:
52
+ needs: [ quality-check ]
53
+ if: needs.quality-check.outputs.changes_pushed != 'true' && (github.head_ref || github.ref_name) == 'dev'
54
+ runs-on: ubuntu-latest
55
+ outputs:
56
+ version: ${{ steps.version.outputs.version }}
57
+ steps:
58
+ - uses: actions/checkout@v6
59
+ - uses: actions/setup-python@v5
60
+ with:
61
+ python-version: '3.12'
62
+ - uses: astral-sh/setup-uv@v5
63
+ with:
64
+ enable-cache: true
65
+ - id: version
66
+ run: echo "version=$(uv run python quasarr/providers/version.py)" >> $GITHUB_OUTPUT
67
+
68
+ build-wheel:
69
+ needs: [ quality-check, version ]
70
+ if: needs.quality-check.outputs.changes_pushed != 'true' && (github.head_ref || github.ref_name) == 'dev'
71
+ runs-on: ubuntu-latest
72
+ outputs:
73
+ attestation-id: ${{ steps.attest.outputs.attestation-id }}
74
+ permissions:
75
+ contents: read
76
+ id-token: write
77
+ attestations: write
78
+ steps:
79
+ - uses: actions/checkout@v6
80
+ - uses: actions/setup-python@v5
81
+ with:
82
+ python-version: '3.12'
83
+ - uses: astral-sh/setup-uv@v5
84
+ with:
85
+ enable-cache: true
86
+ - run: uv build
87
+ - id: attest
88
+ uses: actions/attest-build-provenance@v2
89
+ with:
90
+ subject-path: "dist/*.whl"
91
+ - uses: actions/upload-artifact@v4
92
+ with:
93
+ name: wheel
94
+ path: ./dist/*
95
+
96
+ build-exe:
97
+ needs: [ quality-check, version ]
98
+ if: needs.quality-check.outputs.changes_pushed != 'true' && (github.head_ref || github.ref_name) == 'dev'
99
+ runs-on: windows-latest
100
+ env:
101
+ TMP: "D:\\a\\temp"
102
+ TEMP: "D:\\a\\temp"
103
+ steps:
104
+ - run: mkdir D:\a\temp -Force
105
+ - uses: actions/checkout@v6
106
+ - uses: actions/setup-python@v5
107
+ with:
108
+ python-version: '3.12'
109
+
110
+ - uses: astral-sh/setup-uv@v5
111
+ with:
112
+ enable-cache: true
113
+ cache-suffix: "win-build" # Isolate this cache from Linux builds if you share keys
114
+
115
+ # --- CACHE ---
116
+ - name: Cache PyInstaller Analysis
117
+ uses: actions/cache@v4
118
+ with:
119
+ path: |
120
+ build
121
+ ~\AppData\Local\pyinstaller
122
+ # Invalidates cache only if dependencies (uv.lock) change
123
+ key: pyinstaller-analysis-${{ runner.os }}-${{ hashFiles('uv.lock') }}
124
+ restore-keys: |
125
+ pyinstaller-analysis-${{ runner.os }}-
126
+
127
+ - shell: powershell
128
+ run: Set-MpPreference -DisableRealtimeMonitoring $true
129
+
130
+ - run: uv sync --group build
131
+
132
+ # --- BUILD COMMAND ---
133
+ - run: |
134
+ uv run python -c "from PIL import Image; Image.open('Quasarr.png').save('Quasarr.ico')"
135
+ uv run python quasarr/providers/version.py --create-version-file
136
+ # 1. Removed '--clean'
137
+ # 2. Added '--workpath "build"' (Matches the cached path above)
138
+ # 3. Added '--distpath "dist"' (Explicit output folder)
139
+ uv run pyinstaller --onefile -y --version-file "file_version_info.txt" --workpath "build" --distpath "dist" --icon "Quasarr.ico" "Quasarr.py" -n "quasarr-${{ needs.version.outputs.version }}-standalone-win64"
140
+
141
+ - uses: actions/upload-artifact@v4
142
+ with:
143
+ name: exe-amd64
144
+ path: ./dist/*.exe
145
+
146
+ beta-release:
147
+ needs: [ version, build-wheel, build-exe ]
148
+ runs-on: ubuntu-latest
149
+ permissions: { contents: write }
150
+ steps:
151
+ - uses: actions/checkout@v6
152
+ with:
153
+ fetch-depth: 0
154
+ - uses: actions/download-artifact@v4
155
+ with:
156
+ name: wheel
157
+ path: ./wheel
158
+ - uses: actions/download-artifact@v4
159
+ with:
160
+ name: exe-amd64
161
+ path: ./exe-amd64
162
+ - id: changelog
163
+ uses: metcalfc/changelog-generator@v4.6.2
164
+ with:
165
+ myToken: ${{ secrets.GITHUB_TOKEN }}
166
+ - name: Create Release Body
167
+ run: |
168
+ echo "### Docker:" > release_body.md
169
+ echo "\`docker pull ${{ env.GHCR_ENDPOINT }}:beta\`" >> release_body.md
170
+ echo "### Python:" >> release_body.md
171
+ echo "\`uv tool upgrade quasarr\`" >> release_body.md
172
+ echo "### Changelog:" >> release_body.md
173
+ echo "${{ steps.changelog.outputs.changelog }}" >> release_body.md
174
+ echo "[Attestation](https://github.com/${{ github.repository }}/attestations/${{ needs.build-wheel.outputs.attestation-id }})" >> release_body.md
175
+ - uses: ncipollo/release-action@v1
176
+ with:
177
+ artifacts: "./wheel/*.whl,./exe-amd64/*.exe"
178
+ allowUpdates: true
179
+ removeArtifacts: true
180
+ replacesArtifacts: true
181
+ tag: beta
182
+ name: Beta Build
183
+ bodyFile: "release_body.md"
184
+ prerelease: true
185
+ token: ${{ secrets.GITHUB_TOKEN }}
186
+
187
+ build-docker-amd64:
188
+ needs: [ quality-check, version, build-wheel ]
189
+ if: needs.quality-check.outputs.changes_pushed != 'true' && (github.head_ref || github.ref_name) == 'dev'
190
+ runs-on: ubuntu-latest
191
+ steps:
192
+ - uses: actions/checkout@v6
193
+ - uses: actions/download-artifact@v4
194
+ with:
195
+ name: wheel
196
+ path: ./docker/dist
197
+ - uses: docker/setup-buildx-action@v3
198
+ - uses: docker/login-action@v3
199
+ with:
200
+ registry: ghcr.io
201
+ username: ${{ github.actor }}
202
+ password: ${{ secrets.GITHUB_TOKEN }}
203
+ - uses: docker/build-push-action@v6
204
+ with:
205
+ context: ./docker
206
+ platforms: linux/amd64
207
+ push: true
208
+ provenance: false
209
+ sbom: false
210
+ annotations: org.opencontainers.image.description=${{ env.DESCRIPTION }}
211
+ tags: |
212
+ ${{ env.GHCR_ENDPOINT }}:beta-amd64
213
+ ${{ env.GHCR_ENDPOINT }}:${{ needs.version.outputs.version }}-beta-amd64
214
+ build-args: VS=${{ needs.version.outputs.version }}
215
+ cache-from: type=gha,scope=beta-amd64
216
+ cache-to: type=gha,mode=max,scope=beta-amd64
217
+
218
+ build-docker-arm64:
219
+ needs: [ quality-check, version, build-wheel ]
220
+ if: needs.quality-check.outputs.changes_pushed != 'true' && (github.head_ref || github.ref_name) == 'dev'
221
+ runs-on: ubuntu-24.04-arm
222
+ steps:
223
+ - uses: actions/checkout@v6
224
+ - uses: actions/download-artifact@v4
225
+ with:
226
+ name: wheel
227
+ path: ./docker/dist
228
+ - uses: docker/setup-buildx-action@v3
229
+ - uses: docker/login-action@v3
230
+ with:
231
+ registry: ghcr.io
232
+ username: ${{ github.actor }}
233
+ password: ${{ secrets.GITHUB_TOKEN }}
234
+ - uses: docker/build-push-action@v6
235
+ with:
236
+ context: ./docker
237
+ platforms: linux/arm64
238
+ push: true
239
+ provenance: false
240
+ sbom: false
241
+ annotations: org.opencontainers.image.description=${{ env.DESCRIPTION }}
242
+ tags: |
243
+ ${{ env.GHCR_ENDPOINT }}:beta-arm64
244
+ ${{ env.GHCR_ENDPOINT }}:${{ needs.version.outputs.version }}-beta-arm64
245
+ build-args: VS=${{ needs.version.outputs.version }}
246
+ cache-from: type=gha,scope=beta-arm64
247
+ cache-to: type=gha,mode=max,scope=beta-arm64
248
+
249
+ merge-docker-manifest:
250
+ needs: [ version, build-docker-amd64, build-docker-arm64 ]
251
+ runs-on: ubuntu-latest
252
+ steps:
253
+ - uses: docker/setup-buildx-action@v3
254
+ - uses: docker/login-action@v3
255
+ with:
256
+ registry: ghcr.io
257
+ username: ${{ github.actor }}
258
+ password: ${{ secrets.GITHUB_TOKEN }}
259
+ - run: |
260
+ TAG_AMD64="${{ needs.version.outputs.version }}-beta-amd64"
261
+ TAG_ARM64="${{ needs.version.outputs.version }}-beta-arm64"
262
+ ANNOTATION="index:org.opencontainers.image.description=$DESCRIPTION"
263
+
264
+ docker buildx imagetools create -t ${{ env.GHCR_ENDPOINT }}:beta \
265
+ --annotation "$ANNOTATION" \
266
+ ${{ env.GHCR_ENDPOINT }}:beta-amd64 \
267
+ ${{ env.GHCR_ENDPOINT }}:beta-arm64
268
+
269
+ docker buildx imagetools create -t ${{ env.GHCR_ENDPOINT }}:${{ needs.version.outputs.version }}-beta \
270
+ --annotation "$ANNOTATION" \
271
+ ${{ env.GHCR_ENDPOINT }}:${TAG_AMD64} \
272
+ ${{ env.GHCR_ENDPOINT }}:${TAG_ARM64}
273
+
274
+ notify:
275
+ name: Notify Discord & PR
276
+ needs: [ quality-check, version, beta-release, merge-docker-manifest ]
277
+ # Only run if the build wasn't skipped by the auto-fixer and the release succeeded
278
+ if: needs.quality-check.outputs.changes_pushed != 'true' && needs.beta-release.result == 'success'
279
+ runs-on: ubuntu-latest
280
+ permissions:
281
+ pull-requests: write # Required to comment on the PR
282
+ contents: read
283
+ steps:
284
+ - uses: actions/checkout@v6
285
+
286
+ - name: Send Notifications
287
+ env:
288
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
289
+ DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
290
+ VERSION: ${{ needs.version.outputs.version }}
291
+ REPO: ${{ github.repository }}
292
+ run: |
293
+ echo "Fetching release details..."
294
+ # Get the body of the release we just created (beta tag)
295
+ RELEASE_BODY=$(gh release view beta --json body --jq .body)
296
+
297
+ # --- 1. DISCORD NOTIFICATION ---
298
+ if [ -n "$DISCORD_WEBHOOK" ]; then
299
+ echo "Sending Discord Webhook..."
300
+
301
+ # Construct a JSON payload safely using jq (handles escaping quotes/newlines)
302
+ # We create a simple embed with the version and the release body
303
+ jq -n \
304
+ --arg title "🚀 New Beta Build: $VERSION" \
305
+ --arg desc "$RELEASE_BODY" \
306
+ --arg url "https://github.com/$REPO/releases/tag/beta" \
307
+ '{content: null, embeds: [{title: $title, description: $desc, url: $url, color: 5814783}]}' \
308
+ > discord_payload.json
309
+
310
+ curl -H "Content-Type: application/json" \
311
+ -d @discord_payload.json \
312
+ "$DISCORD_WEBHOOK"
313
+ else
314
+ echo "::warning::Skipping Discord notification (DISCORD_WEBHOOK secret not set)"
315
+ fi
316
+
317
+ # --- 2. PR COMMENT FALLBACK ---
318
+ # Find the PR associated with the commit that triggered this push
319
+ echo "Looking for associated PR..."
320
+ PR_NUMBER=$(gh pr list --search "${{ github.sha }}" --state merged --json number --jq '.[0].number')
321
+
322
+ if [ -n "$PR_NUMBER" ]; then
323
+ echo "Found PR #$PR_NUMBER. Posting comment..."
324
+
325
+ echo "## 🚀 Beta Release $VERSION is Live!" > pr_comment.md
326
+ echo "" >> pr_comment.md
327
+ echo "$RELEASE_BODY" >> pr_comment.md
328
+ echo "" >> pr_comment.md
329
+ echo "[View Release on GitHub](https://github.com/$REPO/releases/tag/beta)" >> pr_comment.md
330
+
331
+ gh pr comment "$PR_NUMBER" --body-file pr_comment.md
332
+ else
333
+ echo "No merged PR found for commit ${{ github.sha }}. Skipping PR comment."
334
+ fi
@@ -34,7 +34,6 @@ jobs:
34
34
  uses: astral-sh/setup-uv@v5
35
35
  with:
36
36
  enable-cache: true
37
- cache-dependency-glob: "pyproject.toml"
38
37
  - name: Get Version
39
38
  id: version
40
39
  run: |
@@ -58,7 +57,6 @@ jobs:
58
57
  uses: astral-sh/setup-uv@v5
59
58
  with:
60
59
  enable-cache: true
61
- cache-dependency-glob: "pyproject.toml"
62
60
  - name: Build wheel
63
61
  run: uv build
64
62
  - name: Generate artifact attestation
@@ -76,21 +74,33 @@ jobs:
76
74
  runs-on: windows-latest
77
75
  needs: version
78
76
  env:
79
- TMP: D:\a\temp
80
- TEMP: D:\a\temp
77
+ # We define a consistent build path to make caching reliable
78
+ BUILD_PATH: "build"
81
79
  steps:
82
- - name: Create Temp Dir
83
- run: mkdir D:\a\temp -Force
84
80
  - uses: actions/checkout@v6
85
81
  - uses: actions/setup-python@v5
86
82
  with:
87
83
  python-version: '3.12'
88
84
 
85
+ # 1. Install uv with its own persistent cache
89
86
  - name: Install uv
90
87
  uses: astral-sh/setup-uv@v5
91
88
  with:
92
89
  enable-cache: true
93
- cache-dependency-glob: "pyproject.toml"
90
+ cache-suffix: "win-build"
91
+
92
+ # 2. PyInstaller Caching
93
+ # We cache the local 'build' folder AND the global PyInstaller cache.
94
+ # The key invalidates if 'uv.lock' changes, forcing a re-analysis only when deps update.
95
+ - name: Cache PyInstaller Analysis
96
+ uses: actions/cache@v4
97
+ with:
98
+ path: |
99
+ build
100
+ ~\AppData\Local\pyinstaller
101
+ key: pyinstaller-analysis-${{ runner.os }}-${{ hashFiles('uv.lock') }}
102
+ restore-keys: |
103
+ pyinstaller-analysis-${{ runner.os }}-
94
104
 
95
105
  - name: Disable Windows Defender
96
106
  shell: powershell
@@ -101,10 +111,14 @@ jobs:
101
111
  uv sync --group build
102
112
 
103
113
  - name: Build exe
114
+ # CHANGES:
115
+ # 1. Removed '--clean' (Critical for speed)
116
+ # 2. Added '--workpath' to point to our cached folder
117
+ # 3. Added '--distpath' explicitly
104
118
  run: |
105
119
  uv run python -c "from PIL import Image; Image.open('Quasarr.png').save('Quasarr.ico')"
106
120
  uv run python quasarr/providers/version.py --create-version-file
107
- uv run pyinstaller --clean --onefile -y --version-file "file_version_info.txt" --icon "Quasarr.ico" "Quasarr.py" -n "quasarr-${{ needs.version.outputs.version }}-standalone-win64"
121
+ uv run pyinstaller --onefile -y --version-file "file_version_info.txt" --workpath "build" --distpath "dist" --icon "Quasarr.ico" "Quasarr.py" -n "quasarr-${{ needs.version.outputs.version }}-standalone-win64"
108
122
 
109
123
  - uses: actions/upload-artifact@v4
110
124
  with:
@@ -252,7 +266,6 @@ jobs:
252
266
  uses: astral-sh/setup-uv@v5
253
267
  with:
254
268
  enable-cache: true
255
- cache-dependency-glob: "pyproject.toml"
256
269
 
257
270
  - name: Publish to PyPI
258
271
  if: ${{ !inputs.skip_pypi }}
@@ -273,7 +286,11 @@ jobs:
273
286
  fi
274
287
  - name: Create Release Body
275
288
  run: |
276
- echo "### Install / Update:" > release_body.md
289
+ echo "### Docker:" > release_body.md
290
+ echo "" >> release_body.md
291
+ echo "\`docker pull ${{ env.GHCR_ENDPOINT }}:latest\`" >> release_body.md
292
+ echo "" >> release_body.md
293
+ echo "### Python:" >> release_body.md
277
294
  echo "" >> release_body.md
278
295
  echo "\`uv tool upgrade quasarr\`" >> release_body.md
279
296
  echo "" >> release_body.md
@@ -282,8 +299,6 @@ jobs:
282
299
  echo "${{ steps.changelog.outputs.changelog }}" >> release_body.md
283
300
  echo "" >> release_body.md
284
301
  echo "[Attestation](https://github.com/${{ github.repository }}/attestations/${{ needs.build-wheel.outputs.attestation-id }})" >> release_body.md
285
- echo "" >> release_body.md
286
- echo "\`docker pull ${{ env.GHCR_ENDPOINT }}:latest\`" >> release_body.md
287
302
 
288
303
  - name: Create Release
289
304
  uses: ncipollo/release-action@v1
@@ -292,3 +307,44 @@ jobs:
292
307
  artifactErrorsFailBuild: true
293
308
  bodyFile: "release_body.md"
294
309
  tag: v.${{ needs.version.outputs.version }}
310
+
311
+ notify:
312
+ name: Notify Discord
313
+ needs: [ version, release, merge-docker-manifest ]
314
+ if: always() && needs.release.result == 'success'
315
+ runs-on: ubuntu-latest
316
+ steps:
317
+ - uses: actions/checkout@v6
318
+
319
+ - name: Send Discord Webhook
320
+ env:
321
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
322
+ DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
323
+ VERSION: ${{ needs.version.outputs.version }}
324
+ REPO: ${{ github.repository }}
325
+ run: |
326
+ # Use the exact tag format defined in the release job (v.X.X.X)
327
+ TAG="v.$VERSION"
328
+ echo "Fetching release details for $TAG..."
329
+
330
+ # Fetch the body from the release we just created
331
+ RELEASE_BODY=$(gh release view "$TAG" --json body --jq .body)
332
+
333
+ if [ -n "$DISCORD_WEBHOOK" ]; then
334
+ echo "Sending notification..."
335
+
336
+ # Construct JSON payload using jq
337
+ # Color 5763719 is 'Green'
338
+ jq -n \
339
+ --arg title "🚀 New Release: $TAG" \
340
+ --arg desc "$RELEASE_BODY" \
341
+ --arg url "https://github.com/$REPO/releases/tag/$TAG" \
342
+ '{content: null, embeds: [{title: $title, description: $desc, url: $url, color: 5763719}]}' \
343
+ > discord_payload.json
344
+
345
+ curl -H "Content-Type: application/json" \
346
+ -d @discord_payload.json \
347
+ "$DISCORD_WEBHOOK"
348
+ else
349
+ echo "::warning::Skipping Discord notification (DISCORD_WEBHOOK secret not set)"
350
+ fi
@@ -4,8 +4,7 @@
4
4
  *.pyc
5
5
  *.bak
6
6
 
7
- # Virtual Environment by uv
8
- uv.lock
7
+ # Virtual Environment
9
8
  .venv
10
9
 
11
10
  # PyCharm
@@ -0,0 +1,42 @@
1
+ # Development Setup for Pull Requests
2
+
3
+ To test your changes before submitting a pull request:
4
+
5
+ **1. Prepare your Environment with `uv`**
6
+
7
+ Ensure you have the development tools (like `ruff`) installed and your environment synced:
8
+
9
+ ```bash
10
+ uv sync --group dev
11
+ ```
12
+
13
+ **2. Run Quasarr with the `--internal_address` parameter**
14
+
15
+ ```bash
16
+ uv run Quasarr.py --internal_address=http://<host-ip>:<port>
17
+ ```
18
+
19
+ Replace `<host-ip>` and `<port>` with the scheme, IP, and port of your host machine.
20
+ The `--internal_address` parameter is **mandatory**.
21
+
22
+ **3. Start the required services using the `dev-services-compose.yml` file**
23
+
24
+ ```bash
25
+ CONFIG_VOLUMES=/path/to/config docker-compose -f docker/dev-services-compose.yml up
26
+ ```
27
+
28
+ Replace `/path/to/config` with your desired configuration location.
29
+ The `CONFIG_VOLUMES` environment variable is **mandatory**.
30
+
31
+ ---
32
+
33
+ ### Code Quality & Maintenance
34
+
35
+ The CI pipeline enforces strict code styling and import optimization. Please run this commands before pushing your
36
+ changes:
37
+
38
+ **Format code AND upgrade dependencies:**
39
+
40
+ ```bash
41
+ uv run maintenance.py --upgrade
42
+ ```
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quasarr
3
- Version: 2.4.8
3
+ Version: 2.4.10
4
4
  Summary: Quasarr connects JDownloader with Radarr, Sonarr and LazyLibrarian. It also decrypts links protected by CAPTCHAs.
5
5
  Author-email: rix1337 <rix1337@users.noreply.github.com>
6
6
  License-File: LICENSE
@@ -11,7 +11,7 @@ Requires-Python: >=3.12
11
11
  Requires-Dist: beautifulsoup4>=4.14.3
12
12
  Requires-Dist: bottle>=0.13.4
13
13
  Requires-Dist: dukpy>=0.5.0
14
- Requires-Dist: pillow>=12.0.0
14
+ Requires-Dist: pillow>=12.1.0
15
15
  Requires-Dist: pycryptodomex>=3.23.0
16
16
  Requires-Dist: requests>=2.32.5
17
17
  Description-Content-Type: text/markdown
@@ -243,11 +243,12 @@ Most feature requests can be satisfied by:
243
243
  [here](https://github.com/rix1337/Quasarr/pulls).
244
244
  - **Pull requests are welcome!** Especially for popular hostnames.
245
245
  - A short guide to set up required dev services is found
246
- in [/docker/dev-setup.md](https://github.com/rix1337/Quasarr/blob/main/docker/dev-setup.md)
246
+ [here](https://github.com/rix1337/Quasarr/blob/main/CONTRIBUTING.md).
247
247
  - Always reach out on Discord before starting work on a new feature to prevent waste of time.
248
248
  - Please follow the existing code style and project structure.
249
249
  - Anti-bot measures must be circumvented fully by Quasarr. Thus, you will need to provide a working solution for new
250
250
  CAPTCHA types by integrating it in the Quasarr Web UI.
251
+ The simplest CAPTCHA bypass involves creating a Tampermonkey user script.
251
252
  - Please provide proof of functionality (screenshots/examples) when submitting your pull request.
252
253
 
253
254
  # SponsorsHelper
@@ -6,6 +6,6 @@ import multiprocessing
6
6
 
7
7
  import quasarr
8
8
 
9
- if __name__ == '__main__':
9
+ if __name__ == "__main__":
10
10
  multiprocessing.freeze_support()
11
11
  quasarr.run()
@@ -225,11 +225,12 @@ Most feature requests can be satisfied by:
225
225
  [here](https://github.com/rix1337/Quasarr/pulls).
226
226
  - **Pull requests are welcome!** Especially for popular hostnames.
227
227
  - A short guide to set up required dev services is found
228
- in [/docker/dev-setup.md](https://github.com/rix1337/Quasarr/blob/main/docker/dev-setup.md)
228
+ [here](https://github.com/rix1337/Quasarr/blob/main/CONTRIBUTING.md).
229
229
  - Always reach out on Discord before starting work on a new feature to prevent waste of time.
230
230
  - Please follow the existing code style and project structure.
231
231
  - Anti-bot measures must be circumvented fully by Quasarr. Thus, you will need to provide a working solution for new
232
232
  CAPTCHA types by integrating it in the Quasarr Web UI.
233
+ The simplest CAPTCHA bypass involves creating a Tampermonkey user script.
233
234
  - Please provide proof of functionality (screenshots/examples) when submitting your pull request.
234
235
 
235
236
  # SponsorsHelper
@@ -13,13 +13,14 @@ COPY --from=uv /uv /usr/local/bin/uv
13
13
  # install local package
14
14
  COPY dist/*.whl /tmp/
15
15
 
16
- # Updated: Added cache mount for uv to speed up installation
16
+ # Configure uv to install tools in globally accessible paths
17
+ ENV UV_TOOL_DIR=/opt/uv-tools
18
+ ENV UV_TOOL_BIN_DIR=/usr/local/bin
19
+
20
+ # The binary will now automatically appear in /usr/local/bin
17
21
  RUN --mount=type=cache,target=/root/.cache/uv \
18
22
  uv tool install /tmp/*.whl --force && rm /tmp/*.whl
19
23
 
20
- # Ensure the binary is in the PATH
21
- ENV PATH="/root/.local/bin:$PATH"
22
-
23
24
  # volumes and ports
24
25
  VOLUME /config
25
26
  EXPOSE 8080