quasarr 2.4.10__tar.gz → 2.5.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 (96) hide show
  1. {quasarr-2.4.10 → quasarr-2.5.0}/.github/workflows/PullRequests.yml +75 -61
  2. {quasarr-2.4.10 → quasarr-2.5.0}/.github/workflows/Release.yml +43 -72
  3. {quasarr-2.4.10 → quasarr-2.5.0}/.gitignore +4 -0
  4. quasarr-2.5.0/.pre-commit-config.yaml +9 -0
  5. {quasarr-2.4.10 → quasarr-2.5.0}/CONTRIBUTING.md +9 -3
  6. {quasarr-2.4.10 → quasarr-2.5.0}/PKG-INFO +1 -1
  7. quasarr-2.4.10/maintenance.py → quasarr-2.5.0/pre-commit.py +59 -57
  8. {quasarr-2.4.10 → quasarr-2.5.0}/pyproject.toml +5 -2
  9. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/__init__.py +3 -3
  10. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/api/__init__.py +7 -7
  11. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/api/captcha/__init__.py +1 -1
  12. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/api/config/__init__.py +22 -169
  13. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/api/sponsors_helper/__init__.py +2 -2
  14. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/downloads/linkcrypters/hide.py +1 -1
  15. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/downloads/packages/__init__.py +5 -5
  16. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/downloads/sources/al.py +1 -1
  17. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/downloads/sources/dw.py +1 -1
  18. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/downloads/sources/sf.py +1 -1
  19. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/providers/notifications.py +1 -1
  20. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/providers/shared_state.py +0 -6
  21. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/providers/version.py +1 -1
  22. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/search/__init__.py +86 -15
  23. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/search/sources/al.py +0 -5
  24. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/search/sources/he.py +1 -2
  25. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/storage/setup.py +517 -236
  26. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/storage/sqlite_database.py +1 -1
  27. {quasarr-2.4.10 → quasarr-2.5.0}/uv.lock +135 -1
  28. {quasarr-2.4.10 → quasarr-2.5.0}/.github/FUNDING.yml +0 -0
  29. {quasarr-2.4.10 → quasarr-2.5.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  30. {quasarr-2.4.10 → quasarr-2.5.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  31. {quasarr-2.4.10 → quasarr-2.5.0}/.github/workflows/HostnameRedaction.yml +0 -0
  32. {quasarr-2.4.10 → quasarr-2.5.0}/LICENSE +0 -0
  33. {quasarr-2.4.10 → quasarr-2.5.0}/Quasarr.png +0 -0
  34. {quasarr-2.4.10 → quasarr-2.5.0}/Quasarr.py +0 -0
  35. {quasarr-2.4.10 → quasarr-2.5.0}/README.md +0 -0
  36. {quasarr-2.4.10 → quasarr-2.5.0}/docker/Dockerfile +0 -0
  37. {quasarr-2.4.10 → quasarr-2.5.0}/docker/dev-services-compose.yml +0 -0
  38. {quasarr-2.4.10 → quasarr-2.5.0}/docker/docker-compose.yml +0 -0
  39. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/api/arr/__init__.py +0 -0
  40. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/api/packages/__init__.py +0 -0
  41. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/api/statistics/__init__.py +0 -0
  42. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/downloads/__init__.py +0 -0
  43. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/downloads/linkcrypters/__init__.py +0 -0
  44. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/downloads/linkcrypters/al.py +0 -0
  45. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/downloads/linkcrypters/filecrypt.py +0 -0
  46. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/downloads/sources/__init__.py +0 -0
  47. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/downloads/sources/by.py +0 -0
  48. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/downloads/sources/dd.py +0 -0
  49. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/downloads/sources/dj.py +0 -0
  50. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/downloads/sources/dl.py +0 -0
  51. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/downloads/sources/dt.py +0 -0
  52. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/downloads/sources/he.py +0 -0
  53. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/downloads/sources/mb.py +0 -0
  54. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/downloads/sources/nk.py +0 -0
  55. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/downloads/sources/nx.py +0 -0
  56. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/downloads/sources/sj.py +0 -0
  57. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/downloads/sources/sl.py +0 -0
  58. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/downloads/sources/wd.py +0 -0
  59. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/downloads/sources/wx.py +0 -0
  60. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/providers/__init__.py +0 -0
  61. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/providers/auth.py +0 -0
  62. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/providers/cloudflare.py +0 -0
  63. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/providers/hostname_issues.py +0 -0
  64. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/providers/html_images.py +0 -0
  65. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/providers/html_templates.py +0 -0
  66. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/providers/imdb_metadata.py +0 -0
  67. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/providers/jd_cache.py +0 -0
  68. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/providers/log.py +0 -0
  69. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/providers/myjd_api.py +0 -0
  70. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/providers/obfuscated.py +0 -0
  71. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/providers/sessions/__init__.py +0 -0
  72. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/providers/sessions/al.py +0 -0
  73. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/providers/sessions/dd.py +0 -0
  74. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/providers/sessions/dl.py +0 -0
  75. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/providers/sessions/nx.py +0 -0
  76. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/providers/statistics.py +0 -0
  77. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/providers/utils.py +0 -0
  78. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/providers/web_server.py +0 -0
  79. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/search/sources/__init__.py +0 -0
  80. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/search/sources/by.py +0 -0
  81. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/search/sources/dd.py +0 -0
  82. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/search/sources/dj.py +0 -0
  83. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/search/sources/dl.py +0 -0
  84. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/search/sources/dt.py +0 -0
  85. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/search/sources/dw.py +0 -0
  86. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/search/sources/fx.py +0 -0
  87. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/search/sources/mb.py +0 -0
  88. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/search/sources/nk.py +0 -0
  89. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/search/sources/nx.py +0 -0
  90. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/search/sources/sf.py +0 -0
  91. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/search/sources/sj.py +0 -0
  92. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/search/sources/sl.py +0 -0
  93. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/search/sources/wd.py +0 -0
  94. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/search/sources/wx.py +0 -0
  95. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/storage/__init__.py +0 -0
  96. {quasarr-2.4.10 → quasarr-2.5.0}/quasarr/storage/config.py +0 -0
@@ -1,4 +1,4 @@
1
- name: CI/CD & Beta Build
1
+ name: Pull Requests
2
2
 
3
3
  on:
4
4
  workflow_dispatch:
@@ -34,8 +34,9 @@ jobs:
34
34
  with:
35
35
  enable-cache: true
36
36
 
37
- # We just install python here so uv run has something to target
38
- - run: uv python install 3.12
37
+ - run: |
38
+ echo "🐍 Installing Python 3.12..."
39
+ uv python install 3.12
39
40
 
40
41
  - name: Run Maintenance
41
42
  id: manager
@@ -46,7 +47,9 @@ jobs:
46
47
  GITHUB_REPO: ${{ github.repository }}
47
48
  WORKFLOW_NAME: ${{ github.workflow }}
48
49
  run: |
49
- uv run maintenance.py --ci
50
+ echo "🛠️ Running pre-commit.py..."
51
+ uv run pre-commit.py --ci
52
+ echo "✨ Maintenance complete."
50
53
 
51
54
  version:
52
55
  needs: [ quality-check ]
@@ -54,6 +57,7 @@ jobs:
54
57
  runs-on: ubuntu-latest
55
58
  outputs:
56
59
  version: ${{ steps.version.outputs.version }}
60
+ epoch: ${{ steps.version.outputs.epoch }}
57
61
  steps:
58
62
  - uses: actions/checkout@v6
59
63
  - uses: actions/setup-python@v5
@@ -63,7 +67,12 @@ jobs:
63
67
  with:
64
68
  enable-cache: true
65
69
  - id: version
66
- run: echo "version=$(uv run python quasarr/providers/version.py)" >> $GITHUB_OUTPUT
70
+ run: |
71
+ VERSION=$(uv run python quasarr/providers/version.py)
72
+ EPOCH=$(date +%s)
73
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
74
+ echo "epoch=$EPOCH" >> $GITHUB_OUTPUT
75
+ echo "🏷️ Detected version: $VERSION ($EPOCH)"
67
76
 
68
77
  build-wheel:
69
78
  needs: [ quality-check, version ]
@@ -83,7 +92,9 @@ jobs:
83
92
  - uses: astral-sh/setup-uv@v5
84
93
  with:
85
94
  enable-cache: true
86
- - run: uv build
95
+ - run: |
96
+ echo "📦 Building Python Wheel..."
97
+ uv build
87
98
  - id: attest
88
99
  uses: actions/attest-build-provenance@v2
89
100
  with:
@@ -106,38 +117,32 @@ jobs:
106
117
  - uses: actions/setup-python@v5
107
118
  with:
108
119
  python-version: '3.12'
109
-
110
120
  - uses: astral-sh/setup-uv@v5
111
121
  with:
112
122
  enable-cache: true
113
- cache-suffix: "win-build" # Isolate this cache from Linux builds if you share keys
114
-
115
- # --- CACHE ---
123
+ cache-suffix: "win-build"
116
124
  - name: Cache PyInstaller Analysis
117
125
  uses: actions/cache@v4
118
126
  with:
119
127
  path: |
120
128
  build
121
129
  ~\AppData\Local\pyinstaller
122
- # Invalidates cache only if dependencies (uv.lock) change
123
130
  key: pyinstaller-analysis-${{ runner.os }}-${{ hashFiles('uv.lock') }}
124
131
  restore-keys: |
125
132
  pyinstaller-analysis-${{ runner.os }}-
126
-
127
133
  - shell: powershell
128
- run: Set-MpPreference -DisableRealtimeMonitoring $true
129
-
130
- - run: uv sync --group build
131
-
132
- # --- BUILD COMMAND ---
134
+ run: |
135
+ echo "🛡️ Disabling Real-time Monitoring..."
136
+ Set-MpPreference -DisableRealtimeMonitoring $true
137
+ - run: |
138
+ echo "📥 Syncing dependencies..."
139
+ uv sync --group build
133
140
  - run: |
141
+ echo "🪟 Starting PyInstaller build..."
134
142
  uv run python -c "from PIL import Image; Image.open('Quasarr.png').save('Quasarr.ico')"
135
143
  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
144
  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
-
145
+ echo "✅ EXE build finished."
141
146
  - uses: actions/upload-artifact@v4
142
147
  with:
143
148
  name: exe-amd64
@@ -165,10 +170,13 @@ jobs:
165
170
  myToken: ${{ secrets.GITHUB_TOKEN }}
166
171
  - name: Create Release Body
167
172
  run: |
168
- echo "### Docker:" > release_body.md
173
+ echo "📝 Generating Release Body..."
174
+ echo "# ${{ needs.version.outputs.version }} (${{ needs.version.outputs.epoch }})" > release_body.md
175
+ echo "" >> release_body.md
176
+ echo "### Docker:" >> release_body.md
169
177
  echo "\`docker pull ${{ env.GHCR_ENDPOINT }}:beta\`" >> release_body.md
170
178
  echo "### Python:" >> release_body.md
171
- echo "\`uv tool upgrade quasarr\`" >> release_body.md
179
+ echo "\`uv tool install https://github.com/rix1337/Quasarr/releases/download/beta/quasarr-${{ needs.version.outputs.version }}-py3-none-any.whl\`" >> release_body.md
172
180
  echo "### Changelog:" >> release_body.md
173
181
  echo "${{ steps.changelog.outputs.changelog }}" >> release_body.md
174
182
  echo "[Attestation](https://github.com/${{ github.repository }}/attestations/${{ needs.build-wheel.outputs.attestation-id }})" >> release_body.md
@@ -179,7 +187,7 @@ jobs:
179
187
  removeArtifacts: true
180
188
  replacesArtifacts: true
181
189
  tag: beta
182
- name: Beta Build
190
+ name: "${{ needs.version.outputs.version }} (${{ needs.version.outputs.epoch }})"
183
191
  bodyFile: "release_body.md"
184
192
  prerelease: true
185
193
  token: ${{ secrets.GITHUB_TOKEN }}
@@ -200,7 +208,8 @@ jobs:
200
208
  registry: ghcr.io
201
209
  username: ${{ github.actor }}
202
210
  password: ${{ secrets.GITHUB_TOKEN }}
203
- - uses: docker/build-push-action@v6
211
+ - name: Build and Push
212
+ uses: docker/build-push-action@v6
204
213
  with:
205
214
  context: ./docker
206
215
  platforms: linux/amd64
@@ -231,7 +240,8 @@ jobs:
231
240
  registry: ghcr.io
232
241
  username: ${{ github.actor }}
233
242
  password: ${{ secrets.GITHUB_TOKEN }}
234
- - uses: docker/build-push-action@v6
243
+ - name: Build and Push
244
+ uses: docker/build-push-action@v6
235
245
  with:
236
246
  context: ./docker
237
247
  platforms: linux/arm64
@@ -257,6 +267,7 @@ jobs:
257
267
  username: ${{ github.actor }}
258
268
  password: ${{ secrets.GITHUB_TOKEN }}
259
269
  - run: |
270
+ echo "🔗 Merging Docker manifests..."
260
271
  TAG_AMD64="${{ needs.version.outputs.version }}-beta-amd64"
261
272
  TAG_ARM64="${{ needs.version.outputs.version }}-beta-arm64"
262
273
  ANNOTATION="index:org.opencontainers.image.description=$DESCRIPTION"
@@ -274,61 +285,64 @@ jobs:
274
285
  notify:
275
286
  name: Notify Discord & PR
276
287
  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
288
  if: needs.quality-check.outputs.changes_pushed != 'true' && needs.beta-release.result == 'success'
279
289
  runs-on: ubuntu-latest
280
290
  permissions:
281
- pull-requests: write # Required to comment on the PR
291
+ pull-requests: write
282
292
  contents: read
283
293
  steps:
284
294
  - uses: actions/checkout@v6
285
-
286
295
  - name: Send Notifications
287
296
  env:
288
297
  GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
289
298
  DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
290
299
  VERSION: ${{ needs.version.outputs.version }}
300
+ EPOCH: ${{ needs.version.outputs.epoch }}
291
301
  REPO: ${{ github.repository }}
292
302
  run: |
293
- echo "Fetching release details..."
294
- # Get the body of the release we just created (beta tag)
303
+ echo "📢 Notifying stakeholders..."
295
304
  RELEASE_BODY=$(gh release view beta --json body --jq .body)
296
-
297
- # --- 1. DISCORD NOTIFICATION ---
298
305
  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)"
306
+ jq -n --arg title "🚀 New Beta Build: $VERSION ($EPOCH)" --arg url "https://github.com/$REPO/releases/tag/beta" '{content: null, flags: 4096, embeds: [{title: $title, url: $url, color: 5814783}]}' > discord_payload.json
307
+ curl -H "Content-Type: application/json" -d @discord_payload.json "$DISCORD_WEBHOOK"
315
308
  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
309
  PR_NUMBER=$(gh pr list --search "${{ github.sha }}" --state merged --json number --jq '.[0].number')
321
-
322
310
  if [ -n "$PR_NUMBER" ]; then
323
- echo "Found PR #$PR_NUMBER. Posting comment..."
324
-
325
311
  echo "## 🚀 Beta Release $VERSION is Live!" > pr_comment.md
326
- echo "" >> pr_comment.md
327
312
  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
313
  gh pr comment "$PR_NUMBER" --body-file pr_comment.md
314
+ fi
315
+
316
+ job-summary:
317
+ name: 📊 Beta Summary
318
+ runs-on: ubuntu-latest
319
+ needs: [ quality-check, version, beta-release ]
320
+ if: always()
321
+ steps:
322
+ - name: Generate Summary
323
+ run: |
324
+ echo "## 🧪 Beta Build Summary" >> $GITHUB_STEP_SUMMARY
325
+
326
+ # Maintenance Outcome
327
+ if [[ "${{ needs.quality-check.outputs.changes_pushed }}" == "true" ]]; then
328
+ echo "### 🛠️ Maintenance Status: **Auto-Fixed**" >> $GITHUB_STEP_SUMMARY
329
+ 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
332
330
  else
333
- echo "No merged PR found for commit ${{ github.sha }}. Skipping PR comment."
331
+ echo "### Maintenance Status: **Clean**" >> $GITHUB_STEP_SUMMARY
332
+ echo "No formatting or maintenance issues were detected." >> $GITHUB_STEP_SUMMARY
334
333
  fi
334
+
335
+ # Decision Logic
336
+ echo "### 🚦 Workflow Decision" >> $GITHUB_STEP_SUMMARY
337
+ if [[ "${{ needs.version.result }}" == "success" ]]; then
338
+ echo "✅ **Proceeded:** The build moved to beta release (Dev branch detected)." >> $GITHUB_STEP_SUMMARY
339
+ else
340
+ echo "🛑 **Stopped:** Build did not proceed to release (Not on dev or quality-check failed)." >> $GITHUB_STEP_SUMMARY
341
+ fi
342
+
343
+ echo "### 📦 Artifact Details" >> $GITHUB_STEP_SUMMARY
344
+ echo "| Metric | Value |" >> $GITHUB_STEP_SUMMARY
345
+ echo "| --- | --- |" >> $GITHUB_STEP_SUMMARY
346
+ echo "| **Version** | \`${{ needs.version.outputs.version || 'N/A' }}\` |" >> $GITHUB_STEP_SUMMARY
347
+ echo "| **Epoch** | \`${{ needs.version.outputs.epoch || 'N/A' }}\` |" >> $GITHUB_STEP_SUMMARY
348
+ 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,26 +78,20 @@ jobs:
74
78
  runs-on: windows-latest
75
79
  needs: version
76
80
  env:
77
- # We define a consistent build path to make caching reliable
78
81
  BUILD_PATH: "build"
79
82
  steps:
80
83
  - uses: actions/checkout@v6
81
84
  - uses: actions/setup-python@v5
82
85
  with:
83
86
  python-version: '3.12'
84
-
85
- # 1. Install uv with its own persistent cache
86
87
  - name: Install uv
87
88
  uses: astral-sh/setup-uv@v5
88
89
  with:
89
90
  enable-cache: true
90
91
  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
92
  - name: Cache PyInstaller Analysis
96
93
  uses: actions/cache@v4
94
+ id: pyinstaller-cache
97
95
  with:
98
96
  path: |
99
97
  build
@@ -101,25 +99,20 @@ jobs:
101
99
  key: pyinstaller-analysis-${{ runner.os }}-${{ hashFiles('uv.lock') }}
102
100
  restore-keys: |
103
101
  pyinstaller-analysis-${{ runner.os }}-
104
-
105
102
  - name: Disable Windows Defender
106
103
  shell: powershell
107
104
  run: Set-MpPreference -DisableRealtimeMonitoring $true
108
-
109
105
  - name: Install dependencies
110
106
  run: |
107
+ echo "📥 Installing build dependencies..."
111
108
  uv sync --group build
112
-
113
109
  - 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
118
110
  run: |
111
+ echo "🪟 Building Windows Binary..."
119
112
  uv run python -c "from PIL import Image; Image.open('Quasarr.png').save('Quasarr.ico')"
120
113
  uv run python quasarr/providers/version.py --create-version-file
121
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"
122
-
115
+ echo "✨ Windows binary created."
123
116
  - uses: actions/upload-artifact@v4
124
117
  with:
125
118
  name: exe-amd64
@@ -220,27 +213,14 @@ jobs:
220
213
  password: ${{ secrets.GITHUB_TOKEN }}
221
214
  - name: Create and Push Manifests
222
215
  run: |
216
+ echo "🔗 Linking Multi-arch images..."
223
217
  TAG_AMD64="${{ needs.version.outputs.version }}-amd64"
224
218
  TAG_ARM64="${{ needs.version.outputs.version }}-arm64"
225
219
  ANNOTATION="index:org.opencontainers.image.description=$DESCRIPTION"
226
-
227
- docker buildx imagetools create -t ${{ env.ENDPOINT }}:latest \
228
- ${{ env.ENDPOINT }}:latest-amd64 \
229
- ${{ env.ENDPOINT }}:latest-arm64
230
-
231
- docker buildx imagetools create -t ${{ env.ENDPOINT }}:${{ needs.version.outputs.version }} \
232
- ${{ env.ENDPOINT }}:${TAG_AMD64} \
233
- ${{ env.ENDPOINT }}:${TAG_ARM64}
234
-
235
- docker buildx imagetools create -t ${{ env.GHCR_ENDPOINT }}:latest \
236
- --annotation "$ANNOTATION" \
237
- ${{ env.GHCR_ENDPOINT }}:latest-amd64 \
238
- ${{ env.GHCR_ENDPOINT }}:latest-arm64
239
-
240
- docker buildx imagetools create -t ${{ env.GHCR_ENDPOINT }}:${{ needs.version.outputs.version }} \
241
- --annotation "$ANNOTATION" \
242
- ${{ env.GHCR_ENDPOINT }}:${TAG_AMD64} \
243
- ${{ 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}
244
224
 
245
225
  release:
246
226
  name: Create Release
@@ -252,7 +232,6 @@ jobs:
252
232
  - uses: actions/checkout@v6
253
233
  with:
254
234
  fetch-depth: 0
255
-
256
235
  - uses: actions/download-artifact@v4
257
236
  with:
258
237
  name: wheel
@@ -261,16 +240,15 @@ jobs:
261
240
  with:
262
241
  name: exe-amd64
263
242
  path: ./exe-amd64
264
-
265
243
  - name: Install uv
266
244
  uses: astral-sh/setup-uv@v5
267
245
  with:
268
246
  enable-cache: true
269
-
270
247
  - name: Publish to PyPI
271
248
  if: ${{ !inputs.skip_pypi }}
272
- run: uv publish ./wheel/* --token ${{ secrets.PYPI_TOKEN }}
273
-
249
+ run: |
250
+ echo "🚀 Publishing to PyPI..."
251
+ uv publish ./wheel/* --token ${{ secrets.PYPI_TOKEN }}
274
252
  - name: Generate changelog
275
253
  id: changelog
276
254
  uses: metcalfc/changelog-generator@v4.6.2
@@ -281,25 +259,16 @@ jobs:
281
259
  GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
282
260
  run: |
283
261
  PR_BODY=$(gh pr list --search "${{ github.sha }}" --state merged --json body --jq '.[0].body // empty')
284
- if [ -n "$PR_BODY" ]; then
285
- echo -e "\n$PR_BODY" >> .github/Changelog.md
286
- fi
262
+ if [ -n "$PR_BODY" ]; then echo -e "\n$PR_BODY" >> .github/Changelog.md; fi
287
263
  - name: Create Release Body
288
264
  run: |
289
265
  echo "### Docker:" > release_body.md
290
- echo "" >> release_body.md
291
266
  echo "\`docker pull ${{ env.GHCR_ENDPOINT }}:latest\`" >> release_body.md
292
- echo "" >> release_body.md
293
267
  echo "### Python:" >> release_body.md
294
- echo "" >> release_body.md
295
268
  echo "\`uv tool upgrade quasarr\`" >> release_body.md
296
- echo "" >> release_body.md
297
269
  echo "### Changelog:" >> release_body.md
298
- echo "" >> release_body.md
299
270
  echo "${{ steps.changelog.outputs.changelog }}" >> release_body.md
300
- echo "" >> release_body.md
301
271
  echo "[Attestation](https://github.com/${{ github.repository }}/attestations/${{ needs.build-wheel.outputs.attestation-id }})" >> release_body.md
302
-
303
272
  - name: Create Release
304
273
  uses: ncipollo/release-action@v1
305
274
  with:
@@ -315,7 +284,6 @@ jobs:
315
284
  runs-on: ubuntu-latest
316
285
  steps:
317
286
  - uses: actions/checkout@v6
318
-
319
287
  - name: Send Discord Webhook
320
288
  env:
321
289
  GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -323,28 +291,31 @@ jobs:
323
291
  VERSION: ${{ needs.version.outputs.version }}
324
292
  REPO: ${{ github.repository }}
325
293
  run: |
326
- # Use the exact tag format defined in the release job (v.X.X.X)
327
294
  TAG="v.$VERSION"
328
- echo "Fetching release details for $TAG..."
329
-
330
- # Fetch the body from the release we just created
331
295
  RELEASE_BODY=$(gh release view "$TAG" --json body --jq .body)
332
-
333
296
  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)"
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"
350
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
@@ -33,10 +39,10 @@ The `CONFIG_VOLUMES` environment variable is **mandatory**.
33
39
  ### Code Quality & Maintenance
34
40
 
35
41
  The CI pipeline enforces strict code styling and import optimization. Please run this commands before pushing your
36
- changes:
42
+ changes. Alternatively, you should just set up the pre-commit hook as described above.
37
43
 
38
- **Format code AND upgrade dependencies:**
44
+ **Format code AND upgrade dependencie manually:**
39
45
 
40
46
  ```bash
41
- uv run maintenance.py --upgrade
47
+ uv run pre-commit.py --upgrade
42
48
  ```
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quasarr
3
- Version: 2.4.10
3
+ Version: 2.5.0
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