quasarr 2.6.0__tar.gz → 2.7.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 (102) hide show
  1. quasarr-2.7.0/.env.example +54 -0
  2. {quasarr-2.6.0 → quasarr-2.7.0}/.github/workflows/HostnameRedaction.yml +1 -0
  3. {quasarr-2.6.0 → quasarr-2.7.0}/.github/workflows/PullRequests.yml +12 -1
  4. {quasarr-2.6.0 → quasarr-2.7.0}/.github/workflows/Release.yml +18 -0
  5. {quasarr-2.6.0 → quasarr-2.7.0}/.gitignore +1 -0
  6. {quasarr-2.6.0 → quasarr-2.7.0}/.pre-commit-config.yaml +1 -1
  7. {quasarr-2.6.0 → quasarr-2.7.0}/PKG-INFO +4 -1
  8. {quasarr-2.6.0 → quasarr-2.7.0}/docker/Dockerfile +1 -0
  9. {quasarr-2.6.0 → quasarr-2.7.0}/pre-commit.py +24 -33
  10. {quasarr-2.6.0 → quasarr-2.7.0}/pyproject.toml +8 -2
  11. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/__init__.py +71 -61
  12. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/api/__init__.py +3 -4
  13. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/api/arr/__init__.py +159 -56
  14. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/api/captcha/__init__.py +203 -154
  15. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/api/config/__init__.py +1 -1
  16. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/api/jdownloader/__init__.py +19 -12
  17. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/downloads/__init__.py +12 -8
  18. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/downloads/linkcrypters/al.py +3 -3
  19. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/downloads/linkcrypters/filecrypt.py +1 -2
  20. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/downloads/packages/__init__.py +62 -88
  21. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/downloads/sources/al.py +3 -3
  22. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/downloads/sources/by.py +3 -3
  23. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/downloads/sources/he.py +8 -9
  24. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/downloads/sources/nk.py +3 -3
  25. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/downloads/sources/sl.py +6 -1
  26. quasarr-2.7.0/quasarr/downloads/sources/wd.py +225 -0
  27. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/downloads/sources/wx.py +11 -17
  28. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/providers/auth.py +9 -13
  29. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/providers/cloudflare.py +50 -4
  30. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/providers/imdb_metadata.py +0 -2
  31. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/providers/jd_cache.py +64 -90
  32. quasarr-2.7.0/quasarr/providers/log.py +237 -0
  33. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/providers/myjd_api.py +116 -94
  34. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/providers/sessions/al.py +20 -22
  35. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/providers/sessions/dd.py +1 -1
  36. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/providers/sessions/dl.py +8 -10
  37. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/providers/sessions/nx.py +1 -1
  38. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/providers/shared_state.py +26 -15
  39. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/providers/utils.py +15 -6
  40. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/providers/version.py +1 -1
  41. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/search/__init__.py +91 -78
  42. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/search/sources/al.py +19 -23
  43. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/search/sources/by.py +6 -6
  44. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/search/sources/dd.py +8 -10
  45. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/search/sources/dj.py +15 -18
  46. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/search/sources/dl.py +25 -37
  47. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/search/sources/dt.py +13 -15
  48. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/search/sources/dw.py +24 -16
  49. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/search/sources/fx.py +25 -11
  50. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/search/sources/he.py +16 -14
  51. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/search/sources/hs.py +7 -7
  52. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/search/sources/mb.py +7 -7
  53. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/search/sources/nk.py +24 -25
  54. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/search/sources/nx.py +22 -15
  55. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/search/sources/sf.py +18 -9
  56. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/search/sources/sj.py +7 -7
  57. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/search/sources/sl.py +26 -14
  58. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/search/sources/wd.py +63 -9
  59. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/search/sources/wx.py +33 -47
  60. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/storage/config.py +1 -3
  61. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/storage/setup.py +13 -4
  62. {quasarr-2.6.0 → quasarr-2.7.0}/uv.lock +55 -0
  63. quasarr-2.6.0/quasarr/downloads/sources/wd.py +0 -155
  64. quasarr-2.6.0/quasarr/providers/log.py +0 -19
  65. {quasarr-2.6.0 → quasarr-2.7.0}/.github/FUNDING.yml +0 -0
  66. {quasarr-2.6.0 → quasarr-2.7.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  67. {quasarr-2.6.0 → quasarr-2.7.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  68. {quasarr-2.6.0 → quasarr-2.7.0}/CONTRIBUTING.md +0 -0
  69. {quasarr-2.6.0 → quasarr-2.7.0}/LICENSE +0 -0
  70. {quasarr-2.6.0 → quasarr-2.7.0}/Quasarr.png +0 -0
  71. {quasarr-2.6.0 → quasarr-2.7.0}/Quasarr.py +0 -0
  72. {quasarr-2.6.0 → quasarr-2.7.0}/README.md +0 -0
  73. {quasarr-2.6.0 → quasarr-2.7.0}/docker/dev-services-compose.yml +0 -0
  74. {quasarr-2.6.0 → quasarr-2.7.0}/docker/docker-compose.yml +0 -0
  75. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/api/packages/__init__.py +0 -0
  76. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/api/sponsors_helper/__init__.py +0 -0
  77. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/api/statistics/__init__.py +0 -0
  78. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/downloads/linkcrypters/__init__.py +0 -0
  79. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/downloads/linkcrypters/hide.py +0 -0
  80. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/downloads/sources/__init__.py +0 -0
  81. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/downloads/sources/dd.py +0 -0
  82. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/downloads/sources/dj.py +0 -0
  83. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/downloads/sources/dl.py +0 -0
  84. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/downloads/sources/dt.py +0 -0
  85. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/downloads/sources/dw.py +0 -0
  86. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/downloads/sources/hs.py +0 -0
  87. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/downloads/sources/mb.py +0 -0
  88. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/downloads/sources/nx.py +0 -0
  89. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/downloads/sources/sf.py +0 -0
  90. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/downloads/sources/sj.py +0 -0
  91. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/providers/__init__.py +0 -0
  92. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/providers/hostname_issues.py +0 -0
  93. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/providers/html_images.py +0 -0
  94. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/providers/html_templates.py +0 -0
  95. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/providers/notifications.py +0 -0
  96. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/providers/obfuscated.py +0 -0
  97. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/providers/sessions/__init__.py +0 -0
  98. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/providers/statistics.py +0 -0
  99. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/providers/web_server.py +0 -0
  100. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/search/sources/__init__.py +0 -0
  101. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/storage/__init__.py +0 -0
  102. {quasarr-2.6.0 → quasarr-2.7.0}/quasarr/storage/sqlite_database.py +0 -0
@@ -0,0 +1,54 @@
1
+ # Copy this file to .env and set your environment variables
2
+
3
+ # Available log levels:
4
+ # CRIT 50
5
+ # ERROR 40
6
+ # WARN 30
7
+ # INFO 20 (default)
8
+ # DEBUG 10
9
+ # TRACE 5
10
+ #
11
+ # Each log line can have multiple contexts, each context can have its own log level.
12
+ # The most verbose/lowest log level among the contexts will decide whether to log that line.
13
+
14
+ # Base log level
15
+ LOG=INFO
16
+
17
+ # Enable/disable colored log output
18
+ LOG_COLOR=1
19
+
20
+ # Maximum width of log lines (in characters)
21
+ #LOG_MAX_WIDTH=160
22
+
23
+ # Log levels per action:
24
+ #LOG_SEARCH = DEBUG
25
+ #LOG_SOURCES = DEBUG
26
+ #LOG_PROVIDERS = DEBUG
27
+ #LOG_DOWNLOADS = DEBUG
28
+ #LOG_PACKAGES = DEBUG
29
+ #LOG_SHARED_STATE = DEBUG
30
+ #LOG_API = DEBUG
31
+ #LOG_SESSIONS = DEBUG
32
+ #LOG_JD_CACHE = DEBUG
33
+ #LOG_JDPACKAGECACHE = DEBUG
34
+ #LOG_GET_PACKAGES = DEBUG
35
+
36
+ # Log levels per source:
37
+ #LOG_AL = DEBUG
38
+ #LOG_BY = DEBUG
39
+ #LOG_DD = DEBUG
40
+ #LOG_DJ = DEBUG
41
+ #LOG_DD = DEBUG
42
+ #LOG_DT = DEBUG
43
+ #LOG_DW = DEBUG
44
+ #LOG_FX = DEBUG
45
+ #LOG_HE = DEBUG
46
+ #LOG_HS = DEBUG
47
+ #LOG_MB = DEBUG
48
+ #LOG_NK = DEBUG
49
+ #LOG_NX = DEBUG
50
+ #LOG_SF = DEBUG
51
+ #LOG_SJ = DEBUG
52
+ #LOG_SL = DEBUG
53
+ #LOG_WD = DEBUG
54
+ #LOG_WX = DEBUG
@@ -13,6 +13,7 @@ on:
13
13
  jobs:
14
14
  redact-hostnames:
15
15
  runs-on: ubuntu-latest
16
+ timeout-minutes: 1
16
17
  permissions:
17
18
  issues: write
18
19
  pull-requests: write
@@ -16,6 +16,7 @@ jobs:
16
16
  quality-check:
17
17
  name: Check & Auto-Fix
18
18
  runs-on: ubuntu-latest
19
+ timeout-minutes: 1
19
20
  permissions:
20
21
  contents: write
21
22
  pull-requests: write
@@ -55,6 +56,7 @@ jobs:
55
56
  needs: [ quality-check ]
56
57
  if: needs.quality-check.outputs.changes_pushed != 'true' && ((github.head_ref == 'dev' && github.base_ref == 'main') || (github.event_name == 'workflow_dispatch' && github.ref_name == 'dev'))
57
58
  runs-on: ubuntu-latest
59
+ timeout-minutes: 1
58
60
  outputs:
59
61
  version: ${{ steps.version.outputs.version }}
60
62
  epoch: ${{ steps.version.outputs.epoch }}
@@ -78,6 +80,7 @@ jobs:
78
80
  needs: [ quality-check, version ]
79
81
  if: needs.quality-check.outputs.changes_pushed != 'true' && ((github.head_ref == 'dev' && github.base_ref == 'main') || (github.event_name == 'workflow_dispatch' && github.ref_name == 'dev'))
80
82
  runs-on: ubuntu-latest
83
+ timeout-minutes: 3
81
84
  outputs:
82
85
  attestation-id: ${{ steps.attest.outputs.attestation-id }}
83
86
  permissions:
@@ -108,9 +111,11 @@ jobs:
108
111
  needs: [ quality-check, version ]
109
112
  if: needs.quality-check.outputs.changes_pushed != 'true' && ((github.head_ref == 'dev' && github.base_ref == 'main') || (github.event_name == 'workflow_dispatch' && github.ref_name == 'dev'))
110
113
  runs-on: windows-latest
114
+ timeout-minutes: 3
111
115
  env:
112
116
  TMP: "D:\\a\\temp"
113
117
  TEMP: "D:\\a\\temp"
118
+ PYINSTALLER_CONFIG_DIR: ".pyinstaller-cache"
114
119
  steps:
115
120
  - run: mkdir D:\a\temp -Force
116
121
  - uses: actions/checkout@v6
@@ -126,7 +131,7 @@ jobs:
126
131
  with:
127
132
  path: |
128
133
  build
129
- ~\AppData\Local\pyinstaller
134
+ .pyinstaller-cache
130
135
  key: pyinstaller-analysis-${{ runner.os }}-${{ hashFiles('uv.lock') }}
131
136
  restore-keys: |
132
137
  pyinstaller-analysis-${{ runner.os }}-
@@ -151,6 +156,7 @@ jobs:
151
156
  beta-release:
152
157
  needs: [ version, build-wheel, build-exe ]
153
158
  runs-on: ubuntu-latest
159
+ timeout-minutes: 1
154
160
  permissions: { contents: write }
155
161
  steps:
156
162
  - uses: actions/checkout@v6
@@ -196,6 +202,7 @@ jobs:
196
202
  needs: [ quality-check, version, build-wheel ]
197
203
  if: needs.quality-check.outputs.changes_pushed != 'true' && ((github.head_ref == 'dev' && github.base_ref == 'main') || (github.event_name == 'workflow_dispatch' && github.ref_name == 'dev'))
198
204
  runs-on: ubuntu-latest
205
+ timeout-minutes: 3
199
206
  steps:
200
207
  - uses: actions/checkout@v6
201
208
  - uses: actions/download-artifact@v4
@@ -228,6 +235,7 @@ jobs:
228
235
  needs: [ quality-check, version, build-wheel ]
229
236
  if: needs.quality-check.outputs.changes_pushed != 'true' && ((github.head_ref == 'dev' && github.base_ref == 'main') || (github.event_name == 'workflow_dispatch' && github.ref_name == 'dev'))
230
237
  runs-on: ubuntu-24.04-arm
238
+ timeout-minutes: 3
231
239
  steps:
232
240
  - uses: actions/checkout@v6
233
241
  - uses: actions/download-artifact@v4
@@ -259,6 +267,7 @@ jobs:
259
267
  merge-docker-manifest:
260
268
  needs: [ version, build-docker-amd64, build-docker-arm64 ]
261
269
  runs-on: ubuntu-latest
270
+ timeout-minutes: 1
262
271
  steps:
263
272
  - uses: docker/setup-buildx-action@v3
264
273
  - uses: docker/login-action@v3
@@ -287,6 +296,7 @@ jobs:
287
296
  needs: [ quality-check, version, beta-release, merge-docker-manifest ]
288
297
  if: needs.quality-check.outputs.changes_pushed != 'true' && needs.beta-release.result == 'success'
289
298
  runs-on: ubuntu-latest
299
+ timeout-minutes: 1
290
300
  permissions:
291
301
  pull-requests: write
292
302
  contents: read
@@ -316,6 +326,7 @@ jobs:
316
326
  job-summary:
317
327
  name: 📊 Beta Summary
318
328
  runs-on: ubuntu-latest
329
+ timeout-minutes: 1
319
330
  needs: [ quality-check, version, beta-release ]
320
331
  if: always()
321
332
  steps:
@@ -23,6 +23,7 @@ jobs:
23
23
  version:
24
24
  name: Get Version
25
25
  runs-on: ubuntu-latest
26
+ timeout-minutes: 1
26
27
  outputs:
27
28
  version: ${{ steps.version.outputs.version }}
28
29
  steps:
@@ -44,6 +45,7 @@ jobs:
44
45
  build-wheel:
45
46
  name: Build Wheel
46
47
  runs-on: ubuntu-latest
48
+ timeout-minutes: 3
47
49
  outputs:
48
50
  attestation-id: ${{ steps.attest.outputs.attestation-id }}
49
51
  permissions:
@@ -76,7 +78,10 @@ jobs:
76
78
  build-exe:
77
79
  name: Build Exe (Windows)
78
80
  runs-on: windows-latest
81
+ timeout-minutes: 3
79
82
  needs: version
83
+ outputs:
84
+ cache-hit: ${{ steps.pyinstaller-cache.outputs.cache-hit }}
80
85
  env:
81
86
  BUILD_PATH: "build"
82
87
  steps:
@@ -121,6 +126,7 @@ jobs:
121
126
  build-docker-amd64:
122
127
  name: Build Docker (AMD64)
123
128
  runs-on: ubuntu-latest
129
+ timeout-minutes: 3
124
130
  needs: [ version, build-wheel ]
125
131
  steps:
126
132
  - uses: actions/checkout@v6
@@ -160,6 +166,7 @@ jobs:
160
166
  build-docker-arm64:
161
167
  name: Build Docker (ARM64)
162
168
  runs-on: ubuntu-24.04-arm
169
+ timeout-minutes: 3
163
170
  needs: [ version, build-wheel ]
164
171
  steps:
165
172
  - uses: actions/checkout@v6
@@ -199,6 +206,7 @@ jobs:
199
206
  merge-docker-manifest:
200
207
  name: Merge Docker Manifests
201
208
  runs-on: ubuntu-latest
209
+ timeout-minutes: 1
202
210
  needs: [ version, build-docker-amd64, build-docker-arm64 ]
203
211
  steps:
204
212
  - uses: docker/setup-buildx-action@v3
@@ -225,6 +233,7 @@ jobs:
225
233
  release:
226
234
  name: Create Release
227
235
  runs-on: ubuntu-latest
236
+ timeout-minutes: 1
228
237
  needs: [ version, build-wheel, build-exe, build-docker-amd64, build-docker-arm64 ]
229
238
  permissions:
230
239
  contents: write
@@ -269,6 +278,7 @@ jobs:
269
278
  echo "### Python:" >> release_body.md
270
279
  echo "\`uv tool upgrade quasarr\`" >> release_body.md
271
280
  if [ -f pr_body.txt ]; then
281
+ echo "" >> release_body.md
272
282
  cat pr_body.txt >> release_body.md
273
283
  echo "" >> release_body.md
274
284
  fi
@@ -288,6 +298,7 @@ jobs:
288
298
  needs: [ version, release, merge-docker-manifest ]
289
299
  if: always() && needs.release.result == 'success'
290
300
  runs-on: ubuntu-latest
301
+ timeout-minutes: 1
291
302
  steps:
292
303
  - uses: actions/checkout@v6
293
304
  - name: Send Discord Webhook
@@ -299,6 +310,12 @@ jobs:
299
310
  run: |
300
311
  TAG="v.$VERSION"
301
312
  RELEASE_BODY=$(gh release view "$TAG" --json body --jq .body)
313
+
314
+ # Truncate to 4000 characters to avoid Discord limits
315
+ if [ ${#RELEASE_BODY} -gt 4000 ]; then
316
+ RELEASE_BODY="${RELEASE_BODY:0:4000}..."
317
+ fi
318
+
302
319
  if [ -n "$DISCORD_WEBHOOK" ]; then
303
320
  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
304
321
  curl -H "Content-Type: application/json" -d @discord_payload.json "$DISCORD_WEBHOOK"
@@ -307,6 +324,7 @@ jobs:
307
324
  job-summary:
308
325
  name: 📈 Build Report
309
326
  runs-on: ubuntu-latest
327
+ timeout-minutes: 1
310
328
  needs: [ version, build-wheel, build-exe, build-docker-amd64, build-docker-arm64, release ]
311
329
  if: always()
312
330
  steps:
@@ -18,3 +18,4 @@
18
18
  *.conf
19
19
  *.db
20
20
  *.ini
21
+ .env
@@ -3,7 +3,7 @@ repos:
3
3
  hooks:
4
4
  - id: pre-commit
5
5
  name: Pre-Commit Check
6
- entry: uv run python pre-commit.py
6
+ entry: uv run python -X utf8 pre-commit.py
7
7
  language: system
8
8
  pass_filenames: false
9
9
  always_run: true
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quasarr
3
- Version: 2.6.0
3
+ Version: 2.7.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
@@ -11,9 +11,12 @@ 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: loguru>=0.7.3
14
15
  Requires-Dist: pillow>=12.1.0
15
16
  Requires-Dist: pycryptodomex>=3.23.0
17
+ Requires-Dist: python-dotenv>=1.2.1
16
18
  Requires-Dist: requests>=2.32.5
19
+ Requires-Dist: wcwidth>=0.5.3
17
20
  Description-Content-Type: text/markdown
18
21
 
19
22
  #
@@ -33,6 +33,7 @@ ENV INTERNAL_ADDRESS=""
33
33
  ENV EXTERNAL_ADDRESS=""
34
34
  ENV DISCORD=""
35
35
  ENV HOSTNAMES=""
36
+ ENV LOG_MAX_WIDTH="130"
36
37
 
37
38
  # Restart loop: exit 0 = restart, exit non-zero = stop container
38
39
  ENTRYPOINT ["sh", "-c", "while true; do quasarr --port=8080 --internal_address=$INTERNAL_ADDRESS --external_address=$EXTERNAL_ADDRESS --discord=$DISCORD --hostnames=$HOSTNAMES; ret=$?; if [ $ret -ne 0 ]; then echo \"Quasarr exited with error $ret, stopping...\"; exit $ret; fi; echo \"Quasarr restarting...\"; sleep 2; done"]
@@ -11,16 +11,9 @@ VERSION_FILE = Path("quasarr/providers/version.py")
11
11
  PYPROJECT_FILE = Path("pyproject.toml")
12
12
 
13
13
 
14
- def safe_print(msg):
15
- try:
16
- print(msg)
17
- except Exception:
18
- print(msg.encode("ascii", errors="replace").decode("ascii"))
19
-
20
-
21
14
  def run(cmd, check=True, capture=False, text=True):
22
15
  """Helper to run shell commands comfortably."""
23
- safe_print(f"⚙️ Exec: {' '.join(cmd)}")
16
+ print(f"⚙️ Exec: {' '.join(cmd)}")
24
17
  return subprocess.run(cmd, check=check, capture_output=capture, text=text)
25
18
 
26
19
 
@@ -36,31 +29,29 @@ def git_status_has_changes():
36
29
 
37
30
 
38
31
  def task_format():
39
- safe_print("\n🔍 --- 1. FORMATTING & SYNTAX CHECK ---")
32
+ print("\n🔍 --- 1. FORMATTING & SYNTAX CHECK ---")
40
33
 
41
34
  # Runs Ruff using the rules defined in pyproject.toml
42
35
  result = run(["uv", "run", "ruff", "check", "--fix", "."], check=False)
43
36
 
44
37
  if result.returncode != 0:
45
- safe_print(
46
- "❌ Critical errors or syntax issues found. Fix them before staging."
47
- )
48
- return False
38
+ print("❌ Critical errors or syntax issues found. Fix them before staging.")
39
+ sys.exit(1)
49
40
 
50
41
  # Standard formatting (indentation/spacing)
51
42
  run(["uv", "run", "ruff", "format", "."], check=False)
52
43
 
53
44
  if git_status_has_changes():
54
- safe_print("✅ Linting fixes applied and staged.")
45
+ print("✅ Linting fixes applied and staged.")
55
46
  run(["git", "add", "."])
56
47
  return True
57
48
 
58
- safe_print("✨ Code style is already perfect.")
49
+ print("✨ Code style is already perfect.")
59
50
  return False
60
51
 
61
52
 
62
53
  def task_upgrade_deps():
63
- safe_print("\n📦 --- 2. DEPENDENCIES ---")
54
+ print("\n📦 --- 2. DEPENDENCIES ---")
64
55
  try:
65
56
  with open(PYPROJECT_FILE, "rb") as f:
66
57
  pyproj = tomllib.load(f)
@@ -74,7 +65,7 @@ def task_upgrade_deps():
74
65
  if deps:
75
66
  pkgs = [get_pkg_name(d) for d in deps if get_pkg_name(d)]
76
67
  if pkgs:
77
- safe_print(f"⬆️ Upgrading main: {pkgs}")
68
+ print(f"⬆️ Upgrading main: {pkgs}")
78
69
  run(["uv", "add", "--upgrade"] + pkgs, check=False)
79
70
 
80
71
  # Groups
@@ -83,27 +74,27 @@ def task_upgrade_deps():
83
74
  if g_deps:
84
75
  pkgs = [get_pkg_name(d) for d in g_deps if get_pkg_name(d)]
85
76
  if pkgs:
86
- safe_print(f"🏗️ Upgrading group '{group}': {pkgs}")
77
+ print(f"🏗️ Upgrading group '{group}': {pkgs}")
87
78
  run(
88
79
  ["uv", "add", "--group", group, "--upgrade"] + pkgs, check=False
89
80
  )
90
81
 
91
82
  # Lock file
92
- safe_print("🔒 Refreshing lockfile...")
83
+ print("🔒 Refreshing lockfile...")
93
84
  run(["uv", "lock", "--upgrade"], check=False)
94
85
 
95
86
  except Exception as e:
96
- safe_print(f"⚠️ Dependency upgrade failed: {e}")
87
+ print(f"⚠️ Dependency upgrade failed: {e}")
97
88
 
98
89
  if git_status_has_changes():
99
- safe_print("✅ Dependencies updated.")
90
+ print("✅ Dependencies updated.")
100
91
  run(["git", "add", "."])
101
92
  return True
102
93
  return False
103
94
 
104
95
 
105
96
  def task_version_bump():
106
- safe_print("\n🏷️ --- 3. VERSION CHECK ---")
97
+ print("\n🏷️ --- 3. VERSION CHECK ---")
107
98
  new_v = ""
108
99
 
109
100
  def get_ver(content):
@@ -127,7 +118,7 @@ def task_version_bump():
127
118
  return (0, 0, 0)
128
119
 
129
120
  try:
130
- safe_print("🌐 Fetching remote to compare versions...")
121
+ print("🌐 Fetching remote to compare versions...")
131
122
  run(["git", "fetch", "origin", "main"], check=False)
132
123
  try:
133
124
  base = subprocess.check_output(
@@ -148,11 +139,11 @@ def task_version_bump():
148
139
  # Read Current Version
149
140
  curr_v = get_ver(VERSION_FILE.read_text())
150
141
 
151
- safe_print(f"📊 Main: {main_v} | Current: {curr_v}")
142
+ print(f"📊 Main: {main_v} | Current: {curr_v}")
152
143
 
153
144
  if main_v and curr_v and ver_tuple(curr_v) <= ver_tuple(main_v):
154
145
  new_v = bump(main_v)
155
- safe_print(f"🚀 Bumping version to: {new_v}")
146
+ print(f"🚀 Bumping version to: {new_v}")
156
147
  content = VERSION_FILE.read_text().replace(f'"{curr_v}"', f'"{new_v}"')
157
148
  VERSION_FILE.write_text(content)
158
149
 
@@ -160,7 +151,7 @@ def task_version_bump():
160
151
  return True, new_v
161
152
 
162
153
  except Exception as e:
163
- safe_print(f"⚠️ Version check warning (non-fatal): {e}")
154
+ print(f"⚠️ Version check warning (non-fatal): {e}")
164
155
 
165
156
  return False, new_v
166
157
 
@@ -179,7 +170,7 @@ def main():
179
170
 
180
171
  # --- CI Specific Logic ---
181
172
  if is_ci and (fixed_format or fixed_deps or fixed_version):
182
- safe_print("\n📤 --- 4. PUSH & REPORT ---")
173
+ print("\n📤 --- 4. PUSH & REPORT ---")
183
174
 
184
175
  run(["git", "config", "--global", "user.name", "github-actions[bot]"])
185
176
  run(
@@ -208,7 +199,7 @@ def main():
208
199
  try:
209
200
  run(["git", "commit", "-m", msg])
210
201
  target_ref = get_env("TARGET_REF")
211
- safe_print(f"🔄 Rebase and pushing to {target_ref}...")
202
+ print(f"🔄 Rebase and pushing to {target_ref}...")
212
203
  run(["git", "pull", "--rebase", "origin", target_ref], check=False)
213
204
  run(["git", "push", "origin", f"HEAD:{target_ref}"])
214
205
 
@@ -216,7 +207,7 @@ def main():
216
207
  with open(os.environ["GITHUB_OUTPUT"], "a") as f:
217
208
  f.write("changes_pushed=true\n")
218
209
  except subprocess.CalledProcessError as e:
219
- safe_print(f"❌ ::error::Failed to push fixes. ({e})")
210
+ print(f"❌ ::error::Failed to push fixes. ({e})")
220
211
  sys.exit(1)
221
212
 
222
213
  repo = get_env("GITHUB_REPO")
@@ -236,7 +227,7 @@ def main():
236
227
  pass
237
228
 
238
229
  if pr_num:
239
- safe_print(f"💬 Posting status update to PR #{pr_num}...")
230
+ print(f"💬 Posting status update to PR #{pr_num}...")
240
231
  fixes_list = ""
241
232
  if fixed_format:
242
233
  fixes_list += "- ✅ **Formatted Code**\n"
@@ -265,18 +256,18 @@ def main():
265
256
  check=False,
266
257
  )
267
258
 
268
- safe_print(f"⚡ Triggering workflow: {workflow_name}...")
259
+ print(f"⚡ Triggering workflow: {workflow_name}...")
269
260
  ret = run(
270
261
  ["gh", "workflow", "run", workflow_name, "--ref", target_ref], check=False
271
262
  )
272
263
 
273
264
  if ret.returncode != 0:
274
- safe_print("⚠️ ::warning::Could not auto-trigger next run.")
265
+ print("⚠️ ::warning::Could not auto-trigger next run.")
275
266
 
276
267
  sys.exit(0)
277
268
 
278
269
  else:
279
- safe_print("\n✨ Clean run. No changes needed.")
270
+ print("\n✨ Clean run. No changes needed.")
280
271
  if "GITHUB_OUTPUT" in os.environ:
281
272
  with open(os.environ["GITHUB_OUTPUT"], "a") as f:
282
273
  f.write("changes_pushed=false\n")
@@ -8,9 +8,12 @@ dependencies = [
8
8
  "beautifulsoup4>=4.14.3",
9
9
  "bottle>=0.13.4",
10
10
  "dukpy>=0.5.0",
11
+ "loguru>=0.7.3",
11
12
  "pillow>=12.1.0",
12
13
  "pycryptodomex>=3.23.0",
14
+ "python-dotenv>=1.2.1",
13
15
  "requests>=2.32.5",
16
+ "wcwidth>=0.5.3",
14
17
  ]
15
18
  authors = [
16
19
  { name = "rix1337", email = "rix1337@users.noreply.github.com" }
@@ -45,8 +48,11 @@ build = [
45
48
  ]
46
49
 
47
50
  [tool.ruff]
48
- # This covers syntax and logic (F) + import sorting (I)
49
- lint.select = ["F", "I"]
51
+ # F = Pyflakes (Critical: F821 catches undefined names)
52
+ # I = Isort (Import sorting)
53
+ # PLE = Pylint Errors (Catches robust logic errors like used-before-assignment)
54
+ # B = Bugbear (Catches common runtime crash bugs and potential logical errors)
55
+ lint.select = ["F", "I", "PLE", "B"]
50
56
  lint.fixable = ["F", "I"]
51
57
  lint.ignore = ["E"]
52
58