redfetch 1.2.0__tar.gz → 1.3.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.
Files changed (54) hide show
  1. {redfetch-1.2.0 → redfetch-1.3.0}/.github/workflows/pipeline.yml +37 -4
  2. {redfetch-1.2.0 → redfetch-1.3.0}/CHANGELOG.md +17 -0
  3. {redfetch-1.2.0 → redfetch-1.3.0}/PKG-INFO +37 -15
  4. {redfetch-1.2.0 → redfetch-1.3.0}/README.md +23 -2
  5. {redfetch-1.2.0 → redfetch-1.3.0}/pyproject.toml +12 -11
  6. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/__about__.py +2 -2
  7. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/api.py +3 -4
  8. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/auth.py +1 -1
  9. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/config.py +211 -85
  10. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/config_firstrun.py +24 -9
  11. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/desktop_shortcut.py +0 -7
  12. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/listener.py +2 -0
  13. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/main.py +103 -3
  14. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/meta.py +4 -0
  15. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/processes.py +27 -15
  16. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/push.py +2 -0
  17. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/settings.toml +15 -5
  18. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/special.py +2 -0
  19. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/sync.py +25 -4
  20. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/sync_discovery.py +15 -2
  21. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/sync_executor.py +2 -0
  22. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/sync_planner.py +2 -0
  23. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/sync_remote.py +3 -0
  24. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/sync_types.py +20 -9
  25. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/terminal_ui.py +172 -103
  26. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/terminal_ui.tcss +13 -11
  27. redfetch-1.3.0/src/redfetch/update_status.py +62 -0
  28. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/utils.py +127 -20
  29. redfetch-1.3.0/tests/test_breadcrumb.py +56 -0
  30. redfetch-1.3.0/tests/test_check.py +144 -0
  31. redfetch-1.3.0/tests/test_env_selection.py +164 -0
  32. {redfetch-1.2.0 → redfetch-1.3.0}/tests/test_first_run_setup.py +20 -39
  33. {redfetch-1.2.0 → redfetch-1.3.0}/tests/test_licensed_resources_filtering.py +84 -2
  34. redfetch-1.3.0/tests/test_settings_local_deltas.py +56 -0
  35. {redfetch-1.2.0 → redfetch-1.3.0}/tests/test_sync_pipeline_regressions.py +65 -0
  36. redfetch-1.2.0/src/redfetch/ResourceInstallBtn.js +0 -237
  37. redfetch-1.2.0/tests/test_special_resources_e2e.py +0 -506
  38. {redfetch-1.2.0 → redfetch-1.3.0}/.gitignore +0 -0
  39. {redfetch-1.2.0 → redfetch-1.3.0}/LICENSE +0 -0
  40. {redfetch-1.2.0 → redfetch-1.3.0}/redfetch.ico +0 -0
  41. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/__init__.py +0 -0
  42. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/detecteq.py +0 -0
  43. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/download.py +0 -0
  44. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/navmesh.py +0 -0
  45. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/net.py +0 -0
  46. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/runtime_errors.py +0 -0
  47. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/store.py +0 -0
  48. {redfetch-1.2.0 → redfetch-1.3.0}/src/redfetch/unloadmq.py +0 -0
  49. {redfetch-1.2.0 → redfetch-1.3.0}/tests/test_cancellation_e2e.py +0 -0
  50. {redfetch-1.2.0 → redfetch-1.3.0}/tests/test_is_special_or_dependency.py +0 -0
  51. {redfetch-1.2.0 → redfetch-1.3.0}/tests/test_path_reset.py +0 -0
  52. {redfetch-1.2.0 → redfetch-1.3.0}/tests/test_publish_message_file_fallback.py +0 -0
  53. {redfetch-1.2.0 → redfetch-1.3.0}/tests/test_sync_queue_rules.py +0 -0
  54. {redfetch-1.2.0 → redfetch-1.3.0}/tests/test_uninstall_e2e.py +0 -0
@@ -184,11 +184,36 @@ jobs:
184
184
  --set-version-string "InternalName" "redfetch" `
185
185
  --set-icon "redfetch.ico"
186
186
 
187
+ - name: Install Google Cloud KMS CNG Provider
188
+ shell: pwsh
189
+ run: |
190
+ if (Test-Path "$env:SystemRoot\System32\kmscng.dll") {
191
+ Write-Host "kmscng already installed."
192
+ return
193
+ }
194
+ $url = "https://github.com/GoogleCloudPlatform/kms-integrations/releases/download/cng-v1.3/kmscng-1.3-windows-amd64.zip"
195
+ $zip = Join-Path $env:RUNNER_TEMP "kmscng.zip"
196
+ $dest = Join-Path $env:RUNNER_TEMP "kmscng"
197
+ Invoke-WebRequest $url -OutFile $zip
198
+ Expand-Archive -Path $zip -DestinationPath $dest -Force
199
+ $msi = Get-ChildItem -Path $dest -Recurse -Filter *.msi | Select-Object -First 1
200
+ if (-not $msi) { throw "kmscng MSI not found in archive" }
201
+ Start-Process msiexec.exe -ArgumentList "/i `"$($msi.FullName)`" /qn /norestart" -Wait -NoNewWindow
202
+ if (-not (Test-Path "$env:SystemRoot\System32\kmscng.dll")) { throw "kmscng installation failed" }
203
+ Write-Host "kmscng installed."
204
+
187
205
  - name: Sign Executable
188
206
  shell: pwsh
207
+ env:
208
+ KMS_KEY: projects/code-signing-rg/locations/global/keyRings/redkeys/cryptoKeys/rgkey/cryptoKeyVersions/1
209
+ SIGNING_CERT: ${{ secrets.SIGNING_CERT }}
210
+ GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }}
189
211
  run: |
190
- $certPath = Join-Path $env:RUNNER_TEMP "cert.pfx"
191
- [IO.File]::WriteAllBytes($certPath, [Convert]::FromBase64String("${{ secrets.CERTIFICATE_PFX }}"))
212
+ $CertFile = Join-Path $env:RUNNER_TEMP "user.crt"
213
+ $KeyFile = Join-Path $env:RUNNER_TEMP "gcp-sa.json"
214
+ [IO.File]::WriteAllBytes($CertFile, [Convert]::FromBase64String($env:SIGNING_CERT))
215
+ [IO.File]::WriteAllText($KeyFile, $env:GCP_SA_KEY)
216
+ $env:GOOGLE_APPLICATION_CREDENTIALS = $KeyFile
192
217
 
193
218
  $signtool = Get-ChildItem -Path "${env:ProgramFiles(x86)}\Windows Kits" -Recurse -Filter "signtool.exe" |
194
219
  Where-Object { $_.FullName -match "\\x64\\" } |
@@ -198,10 +223,18 @@ jobs:
198
223
  if (-not $signtool) { throw "signtool.exe not found" }
199
224
  Write-Host "Using signtool: $signtool"
200
225
 
201
- & $signtool sign /f $certPath /p "${{ secrets.CERTIFICATE_PFX_PASSWORD }}" /fd sha256 /tr "http://timestamp.digicert.com" /td sha256 /v redfetch.exe
226
+ $tsaServers = @('http://timestamp.digicert.com', 'http://timestamp.sectigo.com')
227
+ $maxAttempts = 5
228
+ for ($attempt = 1; $attempt -le $maxAttempts; $attempt++) {
229
+ $tsa = $tsaServers[($attempt - 1) % $tsaServers.Count]
230
+ & $signtool sign /fd SHA256 /f $CertFile /csp "Google Cloud KMS Provider" /kc $env:KMS_KEY /tr $tsa /td sha256 /v redfetch.exe
231
+ if ($LASTEXITCODE -eq 0) { break }
232
+ if ($attempt -eq $maxAttempts) { throw "Signing failed after $maxAttempts attempts" }
233
+ Start-Sleep -Seconds 2
234
+ }
202
235
  & $signtool verify /pa /v redfetch.exe
203
236
 
204
- Remove-Item $certPath
237
+ Remove-Item -Force $CertFile, $KeyFile
205
238
 
206
239
  - name: Upload Executable Artifact
207
240
  uses: actions/upload-artifact@v7
@@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.3.0] - 2026-06-26
9
+
10
+ ### Added
11
+ - `--server` on `update` and `download`: use a different server for one run.
12
+ - TUI: "Also start post-update" — launch EQBCS, MySEQ, or a custom program after a successful update. ([#18](https://github.com/RedGuides/redfetch/issues/18))
13
+ - Staff picks: Ninjadvloot.inc is now on LIVE/TEST/EMU.
14
+
15
+ ### Changed
16
+ - Config paths that contain `eqgame.exe` are allowed with a warning instead of being blocked outright. ([#22](https://github.com/RedGuides/redfetch/issues/22))
17
+ - TUI: "Close MQ pre-update" and "Start MQ post-update" are now No / Ask / Yes toggles, so you can pick the prompt-each-time ("Ask") behavior from the UI instead of only on/off.
18
+ - Only settings you've actually changed are written to `settings.local.toml`, keeping the file tidy.
19
+
20
+ ### Fixed
21
+ - Licensed resources will now download even if you have duplicates. ([#24](https://github.com/RedGuides/redfetch/issues/24))
22
+ - Update checks notice when a resource's subfolder changes.
23
+ - Fixed "RecursionError" on startup by rolling back a dependency.
24
+
8
25
  ## [1.2.0] - 2026-04-05
9
26
 
10
27
  ### Added
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: redfetch
3
- Version: 1.2.0
3
+ Version: 1.3.0
4
4
  Summary: Download and publish EverQuest scripts and software using the RedGuides API
5
5
  Project-URL: Homepage, https://www.redguides.com
6
6
  Project-URL: Documentation, https://www.redguides.com/community/resources/redfetch.3177/
7
7
  Project-URL: Repository, https://github.com/RedGuides/redfetch
8
8
  Project-URL: Issues, https://github.com/RedGuides/redfetch/issues
9
9
  Project-URL: Changelog, https://github.com/RedGuides/redfetch/blob/main/CHANGELOG.md
10
- Project-URL: Source_archive, https://github.com/RedGuides/redfetch/archive/35e27c4778b6d07b5be189be22877ad5bb541d27.zip
10
+ Project-URL: Source_archive, https://github.com/RedGuides/redfetch/archive/aaf2d42ab82d45abeadfafa943e2b61abba2cb60.zip
11
11
  Author-email: Redbot <ask@redguides.com>
12
12
  License-Expression: GPL-3.0-or-later
13
13
  License-File: LICENSE
@@ -17,28 +17,29 @@ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (G
17
17
  Classifier: Operating System :: OS Independent
18
18
  Classifier: Programming Language :: Python :: 3.12
19
19
  Classifier: Topic :: Utilities
20
+ Requires-Python: >=3.12
20
21
  Requires-Dist: aiofiles~=25.1
21
- Requires-Dist: aiohttp~=3.13
22
+ Requires-Dist: aiohttp~=3.14
22
23
  Requires-Dist: aiosqlite~=0.22
23
- Requires-Dist: cachetools~=7.0
24
+ Requires-Dist: cachetools~=7.1
24
25
  Requires-Dist: diskcache~=5.6
25
- Requires-Dist: dynaconf~=3.2
26
+ Requires-Dist: dynaconf<3.3,~=3.2
26
27
  Requires-Dist: httpx[http2]~=0.28
27
28
  Requires-Dist: keepachangelog~=2.0
28
- Requires-Dist: keyring~=25.6
29
+ Requires-Dist: keyring~=25.7
29
30
  Requires-Dist: md2bbcode
30
- Requires-Dist: packaging~=26.0
31
- Requires-Dist: platformdirs~=4.5
31
+ Requires-Dist: packaging~=26.2
32
+ Requires-Dist: platformdirs~=4.10
32
33
  Requires-Dist: psutil~=7.2
33
- Requires-Dist: pydantic~=2.12
34
+ Requires-Dist: pydantic~=2.13
34
35
  Requires-Dist: pyperclip~=1.11
35
36
  Requires-Dist: pywin32; sys_platform == 'win32'
36
- Requires-Dist: rich~=14.3
37
+ Requires-Dist: rich~=15.0
37
38
  Requires-Dist: tenacity~=9.1
38
39
  Requires-Dist: textual-fspicker~=1.0
39
- Requires-Dist: textual~=8.1
40
- Requires-Dist: tomlkit~=0.14
41
- Requires-Dist: typer~=0.21
40
+ Requires-Dist: textual~=8.2
41
+ Requires-Dist: tomlkit~=0.15
42
+ Requires-Dist: typer~=0.26
42
43
  Description-Content-Type: text/markdown
43
44
 
44
45
  ![six wizards levitating a package, the word redfetch underneath](https://www.redguides.com/images/redfetchlogo.png)
@@ -109,8 +110,10 @@ To run redfetch from the command line:
109
110
  > ### 📦 Resource Management
110
111
  > - `update` - Update all watched and special resources
111
112
  > - `--force` / `-f` - Force re-download of all watched resources
113
+ > - `--server` / `-s` - Switch to this server before updating (`LIVE`, `TEST`, `EMU`)
112
114
  > - `download <ID_OR_URL>` - Download a specific resource by ID or URL
113
115
  > - `--force` / `-f` - Force re-download by resetting this resource's download date
116
+ > - `--server` / `-s` - Switch to this server before downloading (`LIVE`, `TEST`, `EMU`)
114
117
  > - `list` - List resources and dependencies in the cache database
115
118
  > - `reset` - Reset download dates for watched resources
116
119
  >
@@ -197,12 +200,31 @@ redfetch.exe config SPECIAL_RESOURCES.2218.opt_in false --server TEST
197
200
 
198
201
  Then assign the *Very Vanilla MQ* path to your self-compiled MacroQuest.
199
202
 
203
+ ### Custom post-update launch
204
+
205
+ redfetch can launch extra programs after an update completes. Aside from the normal UI toggles, you can add `custom` to `POST_UPDATE_LAUNCH.targets` in `settings.local.toml`, then set `command` to whatever redfetch should run:
206
+
207
+ ```toml
208
+ [LIVE.POST_UPDATE_LAUNCH]
209
+ targets = ["custom"]
210
+ command = ['C:\Tools\AfterRedfetch\after-update.exe', '--server', 'LIVE']
211
+ ```
212
+
213
+ You can also combine it with the built-in post-update launches. For example, to start EQBCS and MySEQ and run your own Python script:
214
+
215
+ ```toml
216
+ [LIVE.POST_UPDATE_LAUNCH]
217
+ targets = ["myseq", "custom", "eqbcs"]
218
+ command = ["C:\\Users\\Public\\Python\\python.exe", "C:\\Users\\Public\\redfetch\\after_update.py"]
219
+ ```
220
+
221
+ You can set these per-server, e.g. `[TEST.POST_UPDATE_LAUNCH]`, or global `[DEFAULT.POST_UPDATE_LAUNCH]`.
222
+
223
+
200
224
  ## Trailmap
201
225
  - Add custom buttons for "fetch" tab.
202
226
  - Option: Close after update
203
- - Launch programs with cli options
204
227
  - Indicate when updated VV is available
205
- - Launch more than just mq (eqbcs, etc) upon update.
206
228
  - Run from MQ
207
229
  - Deeper integration with the forums
208
230
 
@@ -66,8 +66,10 @@ To run redfetch from the command line:
66
66
  > ### 📦 Resource Management
67
67
  > - `update` - Update all watched and special resources
68
68
  > - `--force` / `-f` - Force re-download of all watched resources
69
+ > - `--server` / `-s` - Switch to this server before updating (`LIVE`, `TEST`, `EMU`)
69
70
  > - `download <ID_OR_URL>` - Download a specific resource by ID or URL
70
71
  > - `--force` / `-f` - Force re-download by resetting this resource's download date
72
+ > - `--server` / `-s` - Switch to this server before downloading (`LIVE`, `TEST`, `EMU`)
71
73
  > - `list` - List resources and dependencies in the cache database
72
74
  > - `reset` - Reset download dates for watched resources
73
75
  >
@@ -154,12 +156,31 @@ redfetch.exe config SPECIAL_RESOURCES.2218.opt_in false --server TEST
154
156
 
155
157
  Then assign the *Very Vanilla MQ* path to your self-compiled MacroQuest.
156
158
 
159
+ ### Custom post-update launch
160
+
161
+ redfetch can launch extra programs after an update completes. Aside from the normal UI toggles, you can add `custom` to `POST_UPDATE_LAUNCH.targets` in `settings.local.toml`, then set `command` to whatever redfetch should run:
162
+
163
+ ```toml
164
+ [LIVE.POST_UPDATE_LAUNCH]
165
+ targets = ["custom"]
166
+ command = ['C:\Tools\AfterRedfetch\after-update.exe', '--server', 'LIVE']
167
+ ```
168
+
169
+ You can also combine it with the built-in post-update launches. For example, to start EQBCS and MySEQ and run your own Python script:
170
+
171
+ ```toml
172
+ [LIVE.POST_UPDATE_LAUNCH]
173
+ targets = ["myseq", "custom", "eqbcs"]
174
+ command = ["C:\\Users\\Public\\Python\\python.exe", "C:\\Users\\Public\\redfetch\\after_update.py"]
175
+ ```
176
+
177
+ You can set these per-server, e.g. `[TEST.POST_UPDATE_LAUNCH]`, or global `[DEFAULT.POST_UPDATE_LAUNCH]`.
178
+
179
+
157
180
  ## Trailmap
158
181
  - Add custom buttons for "fetch" tab.
159
182
  - Option: Close after update
160
- - Launch programs with cli options
161
183
  - Indicate when updated VV is available
162
- - Launch more than just mq (eqbcs, etc) upon update.
163
184
  - Run from MQ
164
185
  - Deeper integration with the forums
165
186
 
@@ -3,6 +3,7 @@ name = "redfetch"
3
3
  description = "Download and publish EverQuest scripts and software using the RedGuides API"
4
4
  readme = "README.md"
5
5
  license = "GPL-3.0-or-later"
6
+ requires-python = ">=3.12"
6
7
  dynamic = ["version", "urls"]
7
8
  authors = [
8
9
  { name = "Redbot", email = "ask@redguides.com" }
@@ -19,25 +20,25 @@ classifiers = [
19
20
  dependencies = [
20
21
  "aiofiles~=25.1",
21
22
  "aiosqlite~=0.22",
22
- "aiohttp~=3.13",
23
- "cachetools~=7.0",
23
+ "aiohttp~=3.14",
24
+ "cachetools~=7.1",
24
25
  "diskcache~=5.6",
25
- "dynaconf~=3.2",
26
+ "dynaconf~=3.2,<3.3", # 3.3 has a bug
26
27
  "httpx[http2]~=0.28",
27
28
  "keepachangelog~=2.0",
28
- "keyring~=25.6",
29
+ "keyring~=25.7",
29
30
  "md2bbcode",
30
- "packaging~=26.0",
31
- "pydantic~=2.12",
32
- "platformdirs~=4.5",
31
+ "packaging~=26.2",
32
+ "pydantic~=2.13",
33
+ "platformdirs~=4.10",
33
34
  "psutil~=7.2",
34
35
  "pyperclip~=1.11",
35
- "rich~=14.3",
36
+ "rich~=15.0",
36
37
  "tenacity~=9.1",
37
- "textual~=8.1",
38
+ "textual~=8.2",
38
39
  "textual-fspicker~=1.0",
39
- "tomlkit~=0.14",
40
- "typer~=0.21",
40
+ "tomlkit~=0.15",
41
+ "typer~=0.26",
41
42
  "pywin32; sys_platform == 'win32'"
42
43
  ]
43
44
 
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '1.2.0'
22
- __version_tuple__ = version_tuple = (1, 2, 0)
21
+ __version__ = version = '1.3.0'
22
+ __version_tuple__ = version_tuple = (1, 3, 0)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -1,17 +1,16 @@
1
1
  """Resource API client: fetch_*() takes a client, get_*() is self-contained."""
2
+
2
3
  import asyncio
3
4
 
4
5
  import httpx
5
- from pydantic import BaseModel
6
-
7
6
  from redfetch import auth
8
7
  from redfetch import net
9
- from redfetch.sync_types import RemoteStatus
8
+ from redfetch.sync_types import RemoteStatus, SyncModel
10
9
 
11
10
  BASE_URL = net.BASE_URL
12
11
 
13
12
 
14
- class ResourceRecord(BaseModel):
13
+ class ResourceRecord(SyncModel):
15
14
  """Result of a single-resource API check: status plus optional payload or error."""
16
15
  resource_id: str
17
16
  status: RemoteStatus
@@ -553,7 +553,7 @@ def initialize_keyring():
553
553
  raise RuntimeError(
554
554
  "No suitable keyring backend found, probably because you're not on Windows.\n\n"
555
555
  "Please install `keyrings.alt` by running:\n"
556
- " pip install keyrings.alt\n\n"
556
+ " pipx inject redfetch keyrings.alt\n\n"
557
557
  "Then restart the application."
558
558
  )
559
559
  except Exception as e: