diff --git a/.github/workflows/pyinstaller.yaml b/.github/workflows/pyinstaller.yaml
index a51c6da..2a90c65 100644
--- a/.github/workflows/pyinstaller.yaml
+++ b/.github/workflows/pyinstaller.yaml
@@ -24,7 +24,7 @@ jobs:
pathInArchive: "upx-4.2.2-win64/upx.exe"
- run: pip install -r requirements.txt
- - run: pip install pyinstaller garth
+ - run: pip install pyinstaller garth==0.6.3
- run: pyinstaller standalone.spec
- uses: actions/upload-artifact@v4
diff --git a/Dockerfile b/Dockerfile
index acf2340..1a873d4 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -5,7 +5,7 @@ WORKDIR /usr/src/app/zwift-offline
COPY . .
RUN pip install --no-cache-dir --root-user-action=ignore -r requirements.txt
-RUN pip install --no-cache-dir --root-user-action=ignore garth
+RUN pip install --no-cache-dir --root-user-action=ignore garth==0.6.3
RUN chmod 777 storage
diff --git a/README.md b/README.md
index e9fac56..2eb62d9 100644
--- a/README.md
+++ b/README.md
@@ -152,6 +152,7 @@ to generate your own certificates and do the same.
* Patch after every installation or update:
* Install/update Zwift from Google play, but do not start it yet.
* If you have already started it go to `Android Settings > Applications > Zwift` and clear data or uninstall and reinstall the app.
+ * __NOTE:__ ZofflineObb doesn't work on Android 15 and later versions. As a workaround, you can patch the OBB file on Windows. See [#505](https://github.com/zoffline/zwift-offline/issues/505) for details.
* Open the `ZofflineObb` app and run it (allow access to storage)
* Wait for process to finish (5-10min)
* Run Zwift, hopefully it verifies download and runs
@@ -234,12 +235,9 @@ To obtain your current profile:
Garmin Connect
-* If running from source, install garth: ``pip install garth``
-* If needed, create a file ``garmin_domain.txt`` in the ``storage`` directory containing the domain
- * For China use ``garmin.cn``
-* Use the "Settings - Garmin" button in the launcher window to enter your credentials (if using Android, access ``https:///garmin/zoffline/``).
-* If your account has multi-factor authentication, run the script ``garmin_auth.py`` and move the resulting ``garth`` folder (saved in whatever directory you ran ``garmin_auth.py`` in) into the ``storage/1`` directory.
- * Or, if using the Windows zoffline.exe version without Python installed you can run ``garmin_auth.exe`` obtained from https://github.com/oldnapalm/zoffline-helper/releases/latest instead.
+* __NOTE:__ Garmin Connect login is no longer supported ([matin/garth#222](https://github.com/matin/garth/discussions/222)).
+* Use [this script](https://gist.github.com/coleman8er/5c8e192d2aa3c8a3a6220c5702e8a5e6) to login and save tokens.
+* Move the resulting ``oauth1_token.json`` and ``oauth2_token.json`` from `~/.garth` (`C:\Users\\.garth`) to `storage/1/garth`.
diff --git a/cdn/static/web/launcher/settings.html b/cdn/static/web/launcher/settings.html
index 380b0bc..91fa9ec 100644
--- a/cdn/static/web/launcher/settings.html
+++ b/cdn/static/web/launcher/settings.html
@@ -13,7 +13,6 @@
Power curves
Zwift
Strava
- Garmin
Intervals
diff --git a/scripts/garmin_auth.py b/scripts/garmin_auth.py
deleted file mode 100644
index a97a2c7..0000000
--- a/scripts/garmin_auth.py
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/usr/bin/env python
-
-import os
-import sys
-import getpass
-import garth
-
-domain = input("Garmin domain [garmin.com]: ") or 'garmin.com'
-username = input("Username (e-mail): ")
-if not sys.stdin.isatty(): # This terminal cannot support input without displaying text
- print(f'*WARNING* The current shell ({os.name}) cannot support hidden text entry.')
- print(f'Your password entry WILL BE VISIBLE.')
- print(f'If you are running a bash shell under windows, try executing this program via winpty:')
- print(f'>winpty python {sys.argv[0]}')
- password = input("Password (will be shown): ")
-else:
- password = getpass.getpass("Password: ")
-
-garth.configure(domain=domain)
-try:
- garth.login(username, password)
- garth.save('./garth')
-except Exception as e:
- print(e)
diff --git a/zwift_offline.py b/zwift_offline.py
index a7162b8..c9eafc9 100644
--- a/zwift_offline.py
+++ b/zwift_offline.py
@@ -2344,22 +2344,11 @@ def garmin_upload(player_id, activity):
if garth.client.oauth2_token.expired:
garth.client.refresh_oauth2()
garth.save(tokens_dir)
- except:
- garmin_credentials = '%s/%s/garmin_credentials.bin' % (STORAGE_DIR, player_id)
- if not os.path.exists(garmin_credentials):
- logger.info("garmin_credentials.bin missing, skip Garmin activity update")
- return
- username, password = decrypt_credentials(garmin_credentials)
- try:
- garth.login(username, password)
- garth.save(tokens_dir)
- except Exception as exc:
- logger.warning("Garmin login failed: %s" % repr(exc))
- return
+ except Exception as exc:
+ logger.warning("garmin_upload: %s" % repr(exc))
+ return
try:
- requests.post('https://connectapi.%s/upload-service/upload' % GARMIN_DOMAIN,
- files={"file": (activity.fit_filename, BytesIO(activity.fit))},
- headers={'authorization': str(garth.client.oauth2_token)})
+ garth.client.post("connectapi", "/upload-service/upload", api=True, files={"file": (activity.fit_filename, BytesIO(activity.fit))})
except Exception as exc:
logger.warning("Garmin upload failed. No internet? %s" % repr(exc))