quasarr 2.4.9__tar.gz → 2.4.11__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 (97) hide show
  1. quasarr-2.4.11/.github/workflows/PullRequests.yml +341 -0
  2. {quasarr-2.4.9 → quasarr-2.4.11}/.github/workflows/Release.yml +55 -67
  3. {quasarr-2.4.9 → quasarr-2.4.11}/.gitignore +4 -0
  4. quasarr-2.4.11/.pre-commit-config.yaml +9 -0
  5. quasarr-2.4.9/docker/dev-setup.md → quasarr-2.4.11/CONTRIBUTING.md +10 -17
  6. {quasarr-2.4.9 → quasarr-2.4.11}/PKG-INFO +3 -2
  7. {quasarr-2.4.9 → quasarr-2.4.11}/README.md +2 -1
  8. quasarr-2.4.11/pre-commit.py +273 -0
  9. {quasarr-2.4.9 → quasarr-2.4.11}/pyproject.toml +5 -2
  10. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/__init__.py +3 -3
  11. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/api/__init__.py +1 -1
  12. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/api/captcha/__init__.py +1 -1
  13. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/api/config/__init__.py +1 -1
  14. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/api/sponsors_helper/__init__.py +2 -2
  15. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/downloads/linkcrypters/hide.py +1 -1
  16. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/downloads/packages/__init__.py +5 -5
  17. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/downloads/sources/al.py +1 -1
  18. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/downloads/sources/dw.py +1 -1
  19. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/downloads/sources/sf.py +1 -1
  20. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/providers/notifications.py +1 -1
  21. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/providers/shared_state.py +0 -6
  22. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/providers/version.py +1 -1
  23. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/search/sources/al.py +0 -5
  24. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/search/sources/he.py +1 -2
  25. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/storage/sqlite_database.py +1 -1
  26. {quasarr-2.4.9 → quasarr-2.4.11}/uv.lock +135 -1
  27. quasarr-2.4.9/.github/workflows/PullRequests.yml +0 -434
  28. {quasarr-2.4.9 → quasarr-2.4.11}/.github/FUNDING.yml +0 -0
  29. {quasarr-2.4.9 → quasarr-2.4.11}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  30. {quasarr-2.4.9 → quasarr-2.4.11}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  31. {quasarr-2.4.9 → quasarr-2.4.11}/.github/workflows/HostnameRedaction.yml +0 -0
  32. {quasarr-2.4.9 → quasarr-2.4.11}/LICENSE +0 -0
  33. {quasarr-2.4.9 → quasarr-2.4.11}/Quasarr.png +0 -0
  34. {quasarr-2.4.9 → quasarr-2.4.11}/Quasarr.py +0 -0
  35. {quasarr-2.4.9 → quasarr-2.4.11}/docker/Dockerfile +0 -0
  36. {quasarr-2.4.9 → quasarr-2.4.11}/docker/dev-services-compose.yml +0 -0
  37. {quasarr-2.4.9 → quasarr-2.4.11}/docker/docker-compose.yml +0 -0
  38. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/api/arr/__init__.py +0 -0
  39. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/api/packages/__init__.py +0 -0
  40. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/api/statistics/__init__.py +0 -0
  41. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/downloads/__init__.py +0 -0
  42. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/downloads/linkcrypters/__init__.py +0 -0
  43. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/downloads/linkcrypters/al.py +0 -0
  44. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/downloads/linkcrypters/filecrypt.py +0 -0
  45. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/downloads/sources/__init__.py +0 -0
  46. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/downloads/sources/by.py +0 -0
  47. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/downloads/sources/dd.py +0 -0
  48. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/downloads/sources/dj.py +0 -0
  49. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/downloads/sources/dl.py +0 -0
  50. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/downloads/sources/dt.py +0 -0
  51. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/downloads/sources/he.py +0 -0
  52. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/downloads/sources/mb.py +0 -0
  53. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/downloads/sources/nk.py +0 -0
  54. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/downloads/sources/nx.py +0 -0
  55. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/downloads/sources/sj.py +0 -0
  56. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/downloads/sources/sl.py +0 -0
  57. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/downloads/sources/wd.py +0 -0
  58. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/downloads/sources/wx.py +0 -0
  59. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/providers/__init__.py +0 -0
  60. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/providers/auth.py +0 -0
  61. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/providers/cloudflare.py +0 -0
  62. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/providers/hostname_issues.py +0 -0
  63. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/providers/html_images.py +0 -0
  64. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/providers/html_templates.py +0 -0
  65. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/providers/imdb_metadata.py +0 -0
  66. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/providers/jd_cache.py +0 -0
  67. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/providers/log.py +0 -0
  68. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/providers/myjd_api.py +0 -0
  69. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/providers/obfuscated.py +0 -0
  70. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/providers/sessions/__init__.py +0 -0
  71. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/providers/sessions/al.py +0 -0
  72. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/providers/sessions/dd.py +0 -0
  73. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/providers/sessions/dl.py +0 -0
  74. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/providers/sessions/nx.py +0 -0
  75. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/providers/statistics.py +0 -0
  76. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/providers/utils.py +0 -0
  77. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/providers/web_server.py +0 -0
  78. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/search/__init__.py +0 -0
  79. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/search/sources/__init__.py +0 -0
  80. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/search/sources/by.py +0 -0
  81. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/search/sources/dd.py +0 -0
  82. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/search/sources/dj.py +0 -0
  83. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/search/sources/dl.py +0 -0
  84. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/search/sources/dt.py +0 -0
  85. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/search/sources/dw.py +0 -0
  86. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/search/sources/fx.py +0 -0
  87. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/search/sources/mb.py +0 -0
  88. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/search/sources/nk.py +0 -0
  89. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/search/sources/nx.py +0 -0
  90. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/search/sources/sf.py +0 -0
  91. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/search/sources/sj.py +0 -0
  92. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/search/sources/sl.py +0 -0
  93. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/search/sources/wd.py +0 -0
  94. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/search/sources/wx.py +0 -0
  95. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/storage/__init__.py +0 -0
  96. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/storage/config.py +0 -0
  97. {quasarr-2.4.9 → quasarr-2.4.11}/quasarr/storage/setup.py +0 -0
@@ -0,0 +1,341 @@
1
+ name: Pull Requests
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
+ - run: |
38
+ echo "🐍 Installing Python 3.12..."
39
+ uv python install 3.12
40
+
41
+ - name: Run Maintenance
42
+ id: manager
43
+ env:
44
+ GH_TOKEN: ${{ github.token }}
45
+ PR_NUMBER: ${{ github.event.pull_request.number }}
46
+ TARGET_REF: ${{ github.head_ref || github.ref_name }}
47
+ GITHUB_REPO: ${{ github.repository }}
48
+ WORKFLOW_NAME: ${{ github.workflow }}
49
+ run: |
50
+ echo "🛠️ Running pre-commit.py..."
51
+ uv run pre-commit.py --ci
52
+ echo "✨ Maintenance complete."
53
+
54
+ version:
55
+ needs: [ quality-check ]
56
+ if: needs.quality-check.outputs.changes_pushed != 'true' && (github.head_ref || github.ref_name) == 'dev'
57
+ runs-on: ubuntu-latest
58
+ outputs:
59
+ version: ${{ steps.version.outputs.version }}
60
+ steps:
61
+ - uses: actions/checkout@v6
62
+ - uses: actions/setup-python@v5
63
+ with:
64
+ python-version: '3.12'
65
+ - uses: astral-sh/setup-uv@v5
66
+ with:
67
+ enable-cache: true
68
+ - id: version
69
+ run: |
70
+ VERSION=$(uv run python quasarr/providers/version.py)
71
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
72
+ echo "🏷️ Detected version: $VERSION"
73
+
74
+ build-wheel:
75
+ needs: [ quality-check, version ]
76
+ if: needs.quality-check.outputs.changes_pushed != 'true' && (github.head_ref || github.ref_name) == 'dev'
77
+ runs-on: ubuntu-latest
78
+ outputs:
79
+ attestation-id: ${{ steps.attest.outputs.attestation-id }}
80
+ permissions:
81
+ contents: read
82
+ id-token: write
83
+ attestations: write
84
+ steps:
85
+ - uses: actions/checkout@v6
86
+ - uses: actions/setup-python@v5
87
+ with:
88
+ python-version: '3.12'
89
+ - uses: astral-sh/setup-uv@v5
90
+ with:
91
+ enable-cache: true
92
+ - run: |
93
+ echo "📦 Building Python Wheel..."
94
+ uv build
95
+ - id: attest
96
+ uses: actions/attest-build-provenance@v2
97
+ with:
98
+ subject-path: "dist/*.whl"
99
+ - uses: actions/upload-artifact@v4
100
+ with:
101
+ name: wheel
102
+ path: ./dist/*
103
+
104
+ build-exe:
105
+ needs: [ quality-check, version ]
106
+ if: needs.quality-check.outputs.changes_pushed != 'true' && (github.head_ref || github.ref_name) == 'dev'
107
+ runs-on: windows-latest
108
+ env:
109
+ TMP: "D:\\a\\temp"
110
+ TEMP: "D:\\a\\temp"
111
+ steps:
112
+ - run: mkdir D:\a\temp -Force
113
+ - uses: actions/checkout@v6
114
+ - uses: actions/setup-python@v5
115
+ with:
116
+ python-version: '3.12'
117
+ - uses: astral-sh/setup-uv@v5
118
+ with:
119
+ enable-cache: true
120
+ cache-suffix: "win-build"
121
+ - name: Cache PyInstaller Analysis
122
+ uses: actions/cache@v4
123
+ with:
124
+ path: |
125
+ build
126
+ ~\AppData\Local\pyinstaller
127
+ key: pyinstaller-analysis-${{ runner.os }}-${{ hashFiles('uv.lock') }}
128
+ restore-keys: |
129
+ pyinstaller-analysis-${{ runner.os }}-
130
+ - shell: powershell
131
+ run: |
132
+ echo "🛡️ Disabling Real-time Monitoring..."
133
+ Set-MpPreference -DisableRealtimeMonitoring $true
134
+ - run: |
135
+ echo "📥 Syncing dependencies..."
136
+ uv sync --group build
137
+ - run: |
138
+ echo "🪟 Starting PyInstaller build..."
139
+ uv run python -c "from PIL import Image; Image.open('Quasarr.png').save('Quasarr.ico')"
140
+ uv run python quasarr/providers/version.py --create-version-file
141
+ 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"
142
+ echo "✅ EXE build finished."
143
+ - uses: actions/upload-artifact@v4
144
+ with:
145
+ name: exe-amd64
146
+ path: ./dist/*.exe
147
+
148
+ beta-release:
149
+ needs: [ version, build-wheel, build-exe ]
150
+ runs-on: ubuntu-latest
151
+ permissions: { contents: write }
152
+ steps:
153
+ - uses: actions/checkout@v6
154
+ with:
155
+ fetch-depth: 0
156
+ - uses: actions/download-artifact@v4
157
+ with:
158
+ name: wheel
159
+ path: ./wheel
160
+ - uses: actions/download-artifact@v4
161
+ with:
162
+ name: exe-amd64
163
+ path: ./exe-amd64
164
+ - id: changelog
165
+ uses: metcalfc/changelog-generator@v4.6.2
166
+ with:
167
+ myToken: ${{ secrets.GITHUB_TOKEN }}
168
+ - name: Create Release Body
169
+ run: |
170
+ echo "📝 Generating Release Body..."
171
+ echo "### Docker:" > release_body.md
172
+ echo "\`docker pull ${{ env.GHCR_ENDPOINT }}:beta\`" >> release_body.md
173
+ echo "### Python:" >> release_body.md
174
+ echo "\`uv tool upgrade quasarr\`" >> release_body.md
175
+ echo "### Changelog:" >> release_body.md
176
+ echo "${{ steps.changelog.outputs.changelog }}" >> release_body.md
177
+ echo "[Attestation](https://github.com/${{ github.repository }}/attestations/${{ needs.build-wheel.outputs.attestation-id }})" >> release_body.md
178
+ - uses: ncipollo/release-action@v1
179
+ with:
180
+ artifacts: "./wheel/*.whl,./exe-amd64/*.exe"
181
+ allowUpdates: true
182
+ removeArtifacts: true
183
+ replacesArtifacts: true
184
+ tag: beta
185
+ name: Beta Build
186
+ bodyFile: "release_body.md"
187
+ prerelease: true
188
+ token: ${{ secrets.GITHUB_TOKEN }}
189
+
190
+ build-docker-amd64:
191
+ needs: [ quality-check, version, build-wheel ]
192
+ if: needs.quality-check.outputs.changes_pushed != 'true' && (github.head_ref || github.ref_name) == 'dev'
193
+ runs-on: ubuntu-latest
194
+ steps:
195
+ - uses: actions/checkout@v6
196
+ - uses: actions/download-artifact@v4
197
+ with:
198
+ name: wheel
199
+ path: ./docker/dist
200
+ - uses: docker/setup-buildx-action@v3
201
+ - uses: docker/login-action@v3
202
+ with:
203
+ registry: ghcr.io
204
+ username: ${{ github.actor }}
205
+ password: ${{ secrets.GITHUB_TOKEN }}
206
+ - name: Build and Push
207
+ uses: docker/build-push-action@v6
208
+ with:
209
+ context: ./docker
210
+ platforms: linux/amd64
211
+ push: true
212
+ provenance: false
213
+ sbom: false
214
+ annotations: org.opencontainers.image.description=${{ env.DESCRIPTION }}
215
+ tags: |
216
+ ${{ env.GHCR_ENDPOINT }}:beta-amd64
217
+ ${{ env.GHCR_ENDPOINT }}:${{ needs.version.outputs.version }}-beta-amd64
218
+ build-args: VS=${{ needs.version.outputs.version }}
219
+ cache-from: type=gha,scope=beta-amd64
220
+ cache-to: type=gha,mode=max,scope=beta-amd64
221
+
222
+ build-docker-arm64:
223
+ needs: [ quality-check, version, build-wheel ]
224
+ if: needs.quality-check.outputs.changes_pushed != 'true' && (github.head_ref || github.ref_name) == 'dev'
225
+ runs-on: ubuntu-24.04-arm
226
+ steps:
227
+ - uses: actions/checkout@v6
228
+ - uses: actions/download-artifact@v4
229
+ with:
230
+ name: wheel
231
+ path: ./docker/dist
232
+ - uses: docker/setup-buildx-action@v3
233
+ - uses: docker/login-action@v3
234
+ with:
235
+ registry: ghcr.io
236
+ username: ${{ github.actor }}
237
+ password: ${{ secrets.GITHUB_TOKEN }}
238
+ - name: Build and Push
239
+ uses: docker/build-push-action@v6
240
+ with:
241
+ context: ./docker
242
+ platforms: linux/arm64
243
+ push: true
244
+ provenance: false
245
+ sbom: false
246
+ annotations: org.opencontainers.image.description=${{ env.DESCRIPTION }}
247
+ tags: |
248
+ ${{ env.GHCR_ENDPOINT }}:beta-arm64
249
+ ${{ env.GHCR_ENDPOINT }}:${{ needs.version.outputs.version }}-beta-arm64
250
+ build-args: VS=${{ needs.version.outputs.version }}
251
+ cache-from: type=gha,scope=beta-arm64
252
+ cache-to: type=gha,mode=max,scope=beta-arm64
253
+
254
+ merge-docker-manifest:
255
+ needs: [ version, build-docker-amd64, build-docker-arm64 ]
256
+ runs-on: ubuntu-latest
257
+ steps:
258
+ - uses: docker/setup-buildx-action@v3
259
+ - uses: docker/login-action@v3
260
+ with:
261
+ registry: ghcr.io
262
+ username: ${{ github.actor }}
263
+ password: ${{ secrets.GITHUB_TOKEN }}
264
+ - run: |
265
+ echo "🔗 Merging Docker manifests..."
266
+ TAG_AMD64="${{ needs.version.outputs.version }}-beta-amd64"
267
+ TAG_ARM64="${{ needs.version.outputs.version }}-beta-arm64"
268
+ ANNOTATION="index:org.opencontainers.image.description=$DESCRIPTION"
269
+
270
+ docker buildx imagetools create -t ${{ env.GHCR_ENDPOINT }}:beta \
271
+ --annotation "$ANNOTATION" \
272
+ ${{ env.GHCR_ENDPOINT }}:beta-amd64 \
273
+ ${{ env.GHCR_ENDPOINT }}:beta-arm64
274
+
275
+ docker buildx imagetools create -t ${{ env.GHCR_ENDPOINT }}:${{ needs.version.outputs.version }}-beta \
276
+ --annotation "$ANNOTATION" \
277
+ ${{ env.GHCR_ENDPOINT }}:${TAG_AMD64} \
278
+ ${{ env.GHCR_ENDPOINT }}:${TAG_ARM64}
279
+
280
+ notify:
281
+ name: Notify Discord & PR
282
+ needs: [ quality-check, version, beta-release, merge-docker-manifest ]
283
+ if: needs.quality-check.outputs.changes_pushed != 'true' && needs.beta-release.result == 'success'
284
+ runs-on: ubuntu-latest
285
+ permissions:
286
+ pull-requests: write
287
+ contents: read
288
+ steps:
289
+ - uses: actions/checkout@v6
290
+ - name: Send Notifications
291
+ env:
292
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
293
+ DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
294
+ VERSION: ${{ needs.version.outputs.version }}
295
+ REPO: ${{ github.repository }}
296
+ run: |
297
+ echo "📢 Notifying stakeholders..."
298
+ RELEASE_BODY=$(gh release view beta --json body --jq .body)
299
+ if [ -n "$DISCORD_WEBHOOK" ]; then
300
+ jq -n --arg title "🚀 New Beta Build: $VERSION" --arg desc "$RELEASE_BODY" --arg url "https://github.com/$REPO/releases/tag/beta" '{content: null, embeds: [{title: $title, description: $desc, url: $url, color: 5814783}]}' > discord_payload.json
301
+ curl -H "Content-Type: application/json" -d @discord_payload.json "$DISCORD_WEBHOOK"
302
+ fi
303
+ PR_NUMBER=$(gh pr list --search "${{ github.sha }}" --state merged --json number --jq '.[0].number')
304
+ if [ -n "$PR_NUMBER" ]; then
305
+ echo "## 🚀 Beta Release $VERSION is Live!" > pr_comment.md
306
+ echo "$RELEASE_BODY" >> pr_comment.md
307
+ gh pr comment "$PR_NUMBER" --body-file pr_comment.md
308
+ fi
309
+
310
+ job-summary:
311
+ name: 📊 Beta Summary
312
+ runs-on: ubuntu-latest
313
+ needs: [ quality-check, version, beta-release ]
314
+ if: always()
315
+ steps:
316
+ - name: Generate Summary
317
+ run: |
318
+ echo "## 🧪 Beta Build Summary" >> $GITHUB_STEP_SUMMARY
319
+
320
+ # Maintenance Outcome
321
+ if [[ "${{ needs.quality-check.outputs.changes_pushed }}" == "true" ]]; then
322
+ echo "### 🛠️ Maintenance Status: **Auto-Fixed**" >> $GITHUB_STEP_SUMMARY
323
+ echo "The script found formatting or dependency issues and pushed fixes directly. The current build was skipped to allow the new commit to run." >> $GITHUB_STEP_SUMMARY
324
+ else
325
+ echo "### ✨ Maintenance Status: **Clean**" >> $GITHUB_STEP_SUMMARY
326
+ echo "No formatting or maintenance issues were detected." >> $GITHUB_STEP_SUMMARY
327
+ fi
328
+
329
+ # Decision Logic
330
+ echo "### 🚦 Workflow Decision" >> $GITHUB_STEP_SUMMARY
331
+ if [[ "${{ needs.version.result }}" == "success" ]]; then
332
+ echo "✅ **Proceeded:** The build moved to beta release (Dev branch detected)." >> $GITHUB_STEP_SUMMARY
333
+ else
334
+ echo "🛑 **Stopped:** Build did not proceed to release (Not on dev or quality-check failed)." >> $GITHUB_STEP_SUMMARY
335
+ fi
336
+
337
+ echo "### 📦 Artifact Details" >> $GITHUB_STEP_SUMMARY
338
+ echo "| Metric | Value |" >> $GITHUB_STEP_SUMMARY
339
+ echo "| --- | --- |" >> $GITHUB_STEP_SUMMARY
340
+ echo "| **Version** | \`${{ needs.version.outputs.version || 'N/A' }}\` |" >> $GITHUB_STEP_SUMMARY
341
+ echo "| **Release Job** | ${{ needs.beta-release.result || 'Skipped' }} |" >> $GITHUB_STEP_SUMMARY
@@ -37,7 +37,9 @@ jobs:
37
37
  - name: Get Version
38
38
  id: version
39
39
  run: |
40
- echo "version=$(uv run python quasarr/providers/version.py)" >> $GITHUB_OUTPUT
40
+ VERSION=$(uv run python quasarr/providers/version.py)
41
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
42
+ echo "🏷️ Version: $VERSION"
41
43
 
42
44
  build-wheel:
43
45
  name: Build Wheel
@@ -58,7 +60,9 @@ jobs:
58
60
  with:
59
61
  enable-cache: true
60
62
  - name: Build wheel
61
- run: uv build
63
+ run: |
64
+ echo "📦 Starting Wheel build..."
65
+ uv build
62
66
  - name: Generate artifact attestation
63
67
  id: attest
64
68
  uses: actions/attest-build-provenance@v2
@@ -74,35 +78,41 @@ jobs:
74
78
  runs-on: windows-latest
75
79
  needs: version
76
80
  env:
77
- TMP: D:\a\temp
78
- TEMP: D:\a\temp
81
+ BUILD_PATH: "build"
79
82
  steps:
80
- - name: Create Temp Dir
81
- run: mkdir D:\a\temp -Force
82
83
  - uses: actions/checkout@v6
83
84
  - uses: actions/setup-python@v5
84
85
  with:
85
86
  python-version: '3.12'
86
-
87
87
  - name: Install uv
88
88
  uses: astral-sh/setup-uv@v5
89
89
  with:
90
90
  enable-cache: true
91
-
91
+ cache-suffix: "win-build"
92
+ - name: Cache PyInstaller Analysis
93
+ uses: actions/cache@v4
94
+ id: pyinstaller-cache
95
+ with:
96
+ path: |
97
+ build
98
+ ~\AppData\Local\pyinstaller
99
+ key: pyinstaller-analysis-${{ runner.os }}-${{ hashFiles('uv.lock') }}
100
+ restore-keys: |
101
+ pyinstaller-analysis-${{ runner.os }}-
92
102
  - name: Disable Windows Defender
93
103
  shell: powershell
94
104
  run: Set-MpPreference -DisableRealtimeMonitoring $true
95
-
96
105
  - name: Install dependencies
97
106
  run: |
107
+ echo "📥 Installing build dependencies..."
98
108
  uv sync --group build
99
-
100
109
  - name: Build exe
101
110
  run: |
111
+ echo "🪟 Building Windows Binary..."
102
112
  uv run python -c "from PIL import Image; Image.open('Quasarr.png').save('Quasarr.ico')"
103
113
  uv run python quasarr/providers/version.py --create-version-file
104
- 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"
105
-
114
+ 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"
115
+ echo "✨ Windows binary created."
106
116
  - uses: actions/upload-artifact@v4
107
117
  with:
108
118
  name: exe-amd64
@@ -203,27 +213,14 @@ jobs:
203
213
  password: ${{ secrets.GITHUB_TOKEN }}
204
214
  - name: Create and Push Manifests
205
215
  run: |
216
+ echo "🔗 Linking Multi-arch images..."
206
217
  TAG_AMD64="${{ needs.version.outputs.version }}-amd64"
207
218
  TAG_ARM64="${{ needs.version.outputs.version }}-arm64"
208
219
  ANNOTATION="index:org.opencontainers.image.description=$DESCRIPTION"
209
-
210
- docker buildx imagetools create -t ${{ env.ENDPOINT }}:latest \
211
- ${{ env.ENDPOINT }}:latest-amd64 \
212
- ${{ env.ENDPOINT }}:latest-arm64
213
-
214
- docker buildx imagetools create -t ${{ env.ENDPOINT }}:${{ needs.version.outputs.version }} \
215
- ${{ env.ENDPOINT }}:${TAG_AMD64} \
216
- ${{ env.ENDPOINT }}:${TAG_ARM64}
217
-
218
- docker buildx imagetools create -t ${{ env.GHCR_ENDPOINT }}:latest \
219
- --annotation "$ANNOTATION" \
220
- ${{ env.GHCR_ENDPOINT }}:latest-amd64 \
221
- ${{ env.GHCR_ENDPOINT }}:latest-arm64
222
-
223
- docker buildx imagetools create -t ${{ env.GHCR_ENDPOINT }}:${{ needs.version.outputs.version }} \
224
- --annotation "$ANNOTATION" \
225
- ${{ env.GHCR_ENDPOINT }}:${TAG_AMD64} \
226
- ${{ env.GHCR_ENDPOINT }}:${TAG_ARM64}
220
+ docker buildx imagetools create -t ${{ env.ENDPOINT }}:latest ${{ env.ENDPOINT }}:latest-amd64 ${{ env.ENDPOINT }}:latest-arm64
221
+ docker buildx imagetools create -t ${{ env.ENDPOINT }}:${{ needs.version.outputs.version }} ${{ env.ENDPOINT }}:${TAG_AMD64} ${{ env.ENDPOINT }}:${TAG_ARM64}
222
+ docker buildx imagetools create -t ${{ env.GHCR_ENDPOINT }}:latest --annotation "$ANNOTATION" ${{ env.GHCR_ENDPOINT }}:latest-amd64 ${{ env.GHCR_ENDPOINT }}:latest-arm64
223
+ docker buildx imagetools create -t ${{ env.GHCR_ENDPOINT }}:${{ needs.version.outputs.version }} --annotation "$ANNOTATION" ${{ env.GHCR_ENDPOINT }}:${TAG_AMD64} ${{ env.GHCR_ENDPOINT }}:${TAG_ARM64}
227
224
 
228
225
  release:
229
226
  name: Create Release
@@ -235,7 +232,6 @@ jobs:
235
232
  - uses: actions/checkout@v6
236
233
  with:
237
234
  fetch-depth: 0
238
-
239
235
  - uses: actions/download-artifact@v4
240
236
  with:
241
237
  name: wheel
@@ -244,16 +240,15 @@ jobs:
244
240
  with:
245
241
  name: exe-amd64
246
242
  path: ./exe-amd64
247
-
248
243
  - name: Install uv
249
244
  uses: astral-sh/setup-uv@v5
250
245
  with:
251
246
  enable-cache: true
252
-
253
247
  - name: Publish to PyPI
254
248
  if: ${{ !inputs.skip_pypi }}
255
- run: uv publish ./wheel/* --token ${{ secrets.PYPI_TOKEN }}
256
-
249
+ run: |
250
+ echo "🚀 Publishing to PyPI..."
251
+ uv publish ./wheel/* --token ${{ secrets.PYPI_TOKEN }}
257
252
  - name: Generate changelog
258
253
  id: changelog
259
254
  uses: metcalfc/changelog-generator@v4.6.2
@@ -264,25 +259,16 @@ jobs:
264
259
  GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
265
260
  run: |
266
261
  PR_BODY=$(gh pr list --search "${{ github.sha }}" --state merged --json body --jq '.[0].body // empty')
267
- if [ -n "$PR_BODY" ]; then
268
- echo -e "\n$PR_BODY" >> .github/Changelog.md
269
- fi
262
+ if [ -n "$PR_BODY" ]; then echo -e "\n$PR_BODY" >> .github/Changelog.md; fi
270
263
  - name: Create Release Body
271
264
  run: |
272
265
  echo "### Docker:" > release_body.md
273
- echo "" >> release_body.md
274
266
  echo "\`docker pull ${{ env.GHCR_ENDPOINT }}:latest\`" >> release_body.md
275
- echo "" >> release_body.md
276
267
  echo "### Python:" >> release_body.md
277
- echo "" >> release_body.md
278
268
  echo "\`uv tool upgrade quasarr\`" >> release_body.md
279
- echo "" >> release_body.md
280
269
  echo "### Changelog:" >> release_body.md
281
- echo "" >> release_body.md
282
270
  echo "${{ steps.changelog.outputs.changelog }}" >> release_body.md
283
- echo "" >> release_body.md
284
271
  echo "[Attestation](https://github.com/${{ github.repository }}/attestations/${{ needs.build-wheel.outputs.attestation-id }})" >> release_body.md
285
-
286
272
  - name: Create Release
287
273
  uses: ncipollo/release-action@v1
288
274
  with:
@@ -298,7 +284,6 @@ jobs:
298
284
  runs-on: ubuntu-latest
299
285
  steps:
300
286
  - uses: actions/checkout@v6
301
-
302
287
  - name: Send Discord Webhook
303
288
  env:
304
289
  GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -306,28 +291,31 @@ jobs:
306
291
  VERSION: ${{ needs.version.outputs.version }}
307
292
  REPO: ${{ github.repository }}
308
293
  run: |
309
- # Use the exact tag format defined in the release job (v.X.X.X)
310
294
  TAG="v.$VERSION"
311
- echo "Fetching release details for $TAG..."
312
-
313
- # Fetch the body from the release we just created
314
295
  RELEASE_BODY=$(gh release view "$TAG" --json body --jq .body)
315
-
316
296
  if [ -n "$DISCORD_WEBHOOK" ]; then
317
- echo "Sending notification..."
318
-
319
- # Construct JSON payload using jq
320
- # Color 5763719 is 'Green'
321
- jq -n \
322
- --arg title "🚀 New Release: $TAG" \
323
- --arg desc "$RELEASE_BODY" \
324
- --arg url "https://github.com/$REPO/releases/tag/$TAG" \
325
- '{content: null, embeds: [{title: $title, description: $desc, url: $url, color: 5763719}]}' \
326
- > discord_payload.json
327
-
328
- curl -H "Content-Type: application/json" \
329
- -d @discord_payload.json \
330
- "$DISCORD_WEBHOOK"
331
- else
332
- echo "::warning::Skipping Discord notification (DISCORD_WEBHOOK secret not set)"
297
+ jq -n --arg title "🚀 New Release: $TAG" --arg desc "$RELEASE_BODY" --arg url "https://github.com/$REPO/releases/tag/$TAG" '{content: null, embeds: [{title: $title, description: $desc, url: $url, color: 5763719}]}' > discord_payload.json
298
+ curl -H "Content-Type: application/json" -d @discord_payload.json "$DISCORD_WEBHOOK"
333
299
  fi
300
+
301
+ job-summary:
302
+ name: 📈 Build Report
303
+ runs-on: ubuntu-latest
304
+ needs: [ version, build-wheel, build-exe, build-docker-amd64, build-docker-arm64, release ]
305
+ if: always()
306
+ steps:
307
+ - name: Generate Job Summary
308
+ run: |
309
+ echo "## 📊 Release Production Report" >> $GITHUB_STEP_SUMMARY
310
+ echo "| Artifact | Status |" >> $GITHUB_STEP_SUMMARY
311
+ echo "| --- | --- |" >> $GITHUB_STEP_SUMMARY
312
+ echo "| **Python Wheel** | ${{ needs.build-wheel.result == 'success' && '✅' || '❌' }} |" >> $GITHUB_STEP_SUMMARY
313
+ echo "| **Windows Standalone** | ${{ needs.build-exe.result == 'success' && '✅' || '❌' }} |" >> $GITHUB_STEP_SUMMARY
314
+ echo "| **Docker AMD64** | ${{ needs.build-docker-amd64.result == 'success' && '✅' || '❌' }} |" >> $GITHUB_STEP_SUMMARY
315
+ echo "| **Docker ARM64** | ${{ needs.build-docker-arm64.result == 'success' && '✅' || '❌' }} |" >> $GITHUB_STEP_SUMMARY
316
+ echo "| **GitHub Release** | ${{ needs.release.result == 'success' && '🚀 Published' || '⚠️ Failed' }} |" >> $GITHUB_STEP_SUMMARY
317
+
318
+ echo "### ⚡ Cache Performance" >> $GITHUB_STEP_SUMMARY
319
+ # This assumes you use the default GITHUB_TOKEN permissions to read cache API if you wanted complex stats,
320
+ # but for simplicity we report on the PyInstaller cache key match.
321
+ echo "* **PyInstaller Cache:** ${{ needs.build-exe.outputs.cache-hit == 'true' && 'Hit (Fast 🚀)' || 'Miss (Full Build 🐢)' }}" >> $GITHUB_STEP_SUMMARY
@@ -10,6 +10,10 @@
10
10
  # PyCharm
11
11
  .idea
12
12
 
13
+ # MacOS
14
+ .DS_Store
15
+ **/.DS_Store
16
+
13
17
  # Quasarr
14
18
  *.conf
15
19
  *.db
@@ -0,0 +1,9 @@
1
+ repos:
2
+ - repo: local
3
+ hooks:
4
+ - id: pre-commit
5
+ name: Pre-Commit Check
6
+ entry: uv run python pre-commit.py
7
+ language: system
8
+ pass_filenames: false
9
+ always_run: true
@@ -10,6 +10,12 @@ Ensure you have the development tools (like `ruff`) installed and your environme
10
10
  uv sync --group dev
11
11
  ```
12
12
 
13
+ Install the pre-commit hook that ensures linting, formatting and version upgrades through pre-commit.py
14
+
15
+ ```bash
16
+ uv run pre-commit install
17
+ ```
18
+
13
19
  **2. Run Quasarr with the `--internal_address` parameter**
14
20
 
15
21
  ```bash
@@ -32,24 +38,11 @@ The `CONFIG_VOLUMES` environment variable is **mandatory**.
32
38
 
33
39
  ### Code Quality & Maintenance
34
40
 
35
- The CI pipeline enforces strict code styling and import optimization. Please run these commands before pushing your
36
- changes:
41
+ The CI pipeline enforces strict code styling and import optimization. Please run this commands before pushing your
42
+ changes. Alternatively, you should just set up the pre-commit hook as described above.
37
43
 
38
- **Optimize Imports and Fix Linting:**
44
+ **Format code AND upgrade dependencie manually:**
39
45
 
40
46
  ```bash
41
- uv run ruff check --fix .
47
+ uv run pre-commit.py --upgrade
42
48
  ```
43
-
44
- **Format Code Layout:**
45
-
46
- ```bash
47
- uv run ruff format .
48
- ```
49
-
50
- **Update Dependencies:**
51
- To update the project lockfile to the latest versions of all packages without manually editing `pyproject.toml`:
52
-
53
- ```bash
54
- uv lock --upgrade
55
- ```
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quasarr
3
- Version: 2.4.9
3
+ Version: 2.4.11
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
@@ -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
@@ -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