refrain 0.2.6__tar.gz → 0.2.7__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.
- {refrain-0.2.6 → refrain-0.2.7}/CHANGELOG.md +92 -1
- {refrain-0.2.6 → refrain-0.2.7}/PKG-INFO +11 -2
- {refrain-0.2.6 → refrain-0.2.7}/README.md +10 -1
- {refrain-0.2.6 → refrain-0.2.7}/ROADMAP.md +87 -4
- {refrain-0.2.6 → refrain-0.2.7}/docs/screenshots/README.md +4 -2
- refrain-0.2.7/docs/screenshots/live-log.png +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/docs/screenshots/settings-advanced.png +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/docs/screenshots/settings-general.png +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/docs/screenshots/settings-sources.png +0 -0
- refrain-0.2.7/docs/screenshots/settings-updates.png +0 -0
- refrain-0.2.7/docs/screenshots/tray-menu.png +0 -0
- refrain-0.2.7/docs/screenshots/update-dialog.png +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/packaging/appimage/AppImageBuilder.yml +1 -1
- {refrain-0.2.6 → refrain-0.2.7}/packaging/aur/refrain/.SRCINFO +3 -3
- {refrain-0.2.6 → refrain-0.2.7}/packaging/aur/refrain/PKGBUILD +2 -2
- {refrain-0.2.6 → refrain-0.2.7}/packaging/flatpak/io.github.Rockykln.Refrain.metainfo.xml +18 -0
- {refrain-0.2.6 → refrain-0.2.7}/pyproject.toml +1 -1
- refrain-0.2.7/src/refrain/__init__.py +1 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/app.py +39 -26
- refrain-0.2.7/src/refrain/assets/icons/menu-quit.svg +3 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/discord_rpc.py +17 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/i18n/refrain_de.qm +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/i18n/refrain_de.ts +14 -14
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/i18n/refrain_es.qm +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/i18n/refrain_es.ts +14 -14
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/i18n/refrain_fr.qm +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/i18n/refrain_fr.ts +14 -14
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/i18n/refrain_it.qm +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/i18n/refrain_it.ts +14 -14
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/i18n/refrain_ja.qm +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/i18n/refrain_ja.ts +14 -14
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/i18n/refrain_pl.qm +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/i18n/refrain_pl.ts +14 -14
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/i18n/refrain_pt.qm +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/i18n/refrain_pt.ts +14 -14
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/i18n/refrain_ru.qm +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/i18n/refrain_ru.ts +14 -14
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/i18n/refrain_zh_CN.qm +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/i18n/refrain_zh_CN.ts +14 -14
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/ui/settings_window.py +10 -25
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/ui/tray.py +70 -15
- refrain-0.2.6/docs/screenshots/live-log.png +0 -0
- refrain-0.2.6/docs/screenshots/settings-updates.png +0 -0
- refrain-0.2.6/docs/screenshots/tray-menu.png +0 -0
- refrain-0.2.6/docs/screenshots/update-dialog.png +0 -0
- refrain-0.2.6/src/refrain/__init__.py +0 -1
- {refrain-0.2.6 → refrain-0.2.7}/.editorconfig +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/.gitattributes +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/.github/FUNDING.yml +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/.github/codeql/codeql-config.yml +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/.github/dependabot.yml +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/.github/pull_request_template.md +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/.github/workflows/codeql.yml +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/.github/workflows/release.yml +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/.github/workflows/security.yml +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/.github/workflows/tests.yml +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/.gitignore +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/CODE_OF_CONDUCT.md +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/CONTRIBUTING.md +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/LICENSE +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/Makefile +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/SECURITY.md +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/docs/architecture.md +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/docs/bluetooth.md +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/docs/faq.md +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/docs/screenshots/discord-rpc.png +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/docs/screenshots/notification.png +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/docs/screenshots/welcome.png +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/docs/test-matrix.md +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/packaging/README.md +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/packaging/aur/refrain-git/PKGBUILD +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/packaging/flatpak/io.github.Rockykln.Refrain.desktop +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/packaging/flatpak/io.github.Rockykln.Refrain.yaml +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/packaging/flatpak/python-deps.json +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/requirements-dev.txt +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/requirements.txt +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/__main__.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/assets/icons/github-mark.svg +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/assets/icons/menu-update.svg +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/assets/icons/refrain.png +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/assets/icons/refrain.svg +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/assets/icons/tray-paused-dark.svg +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/assets/icons/tray-paused.svg +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/assets/icons/tray-playing-dark.svg +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/assets/icons/tray-playing.svg +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/assets/icons/tray-stopped-dark.svg +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/assets/icons/tray-stopped.svg +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/assets/refrain.desktop +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/autostart.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/config.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/cover_art.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/cover_fetcher.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/daemon.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/logging_setup.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/paths.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/single_instance.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/sources/__init__.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/sources/base.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/sources/bluetooth.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/sources/mpris.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/sources/mpris_server.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/timing.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/ui/__init__.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/ui/log_window.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/ui/update_dialog.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/ui/welcome_dialog.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/src/refrain/updater.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/tests/__init__.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/tests/conftest.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/tests/test_autostart.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/tests/test_config.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/tests/test_cover_art.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/tests/test_cover_fetcher.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/tests/test_daemon_album_format.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/tests/test_daemon_idle.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/tests/test_discord_listening.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/tests/test_discord_rpc.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/tests/test_imports.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/tests/test_mpris_dispatch.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/tests/test_paths.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/tests/test_sources_base.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/tests/test_timing.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/tests/test_tray_init.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/tests/test_update_dialog_body.py +0 -0
- {refrain-0.2.6 → refrain-0.2.7}/tests/test_updater.py +0 -0
|
@@ -7,6 +7,96 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.7] - 2026-05-07
|
|
11
|
+
|
|
12
|
+
Tray-menu polish + Discord-RPC reliability fixes. Every tray action
|
|
13
|
+
now carries an icon, song-info rows render in normal menu text
|
|
14
|
+
colour instead of greyed-out indented rows, middle-click on the
|
|
15
|
+
tray toggles play/pause, and Discord handshake errors no longer
|
|
16
|
+
spam the log with unexpected-exception tracebacks.
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- **Middle-click on the tray icon toggles play/pause.** Clicks the
|
|
21
|
+
PlayPause command on whichever MPRIS source Refrain is currently
|
|
22
|
+
attached to — same path as the tray-menu Play/Pause item, but
|
|
23
|
+
reachable without opening the menu. Plain left-click still opens
|
|
24
|
+
Settings; right-click still shows the menu.
|
|
25
|
+
- **Tray menu actions now all carry icons.** Once any QMenu item
|
|
26
|
+
has an icon, the menu reserves the icon column for *all* items —
|
|
27
|
+
so adding the red ✕ to Quit Refrain made every previously
|
|
28
|
+
text-only action read as misaligned with blank icon space. Action
|
|
29
|
+
items now use freedesktop theme icons (`configure`,
|
|
30
|
+
`view-list-text`, `view-refresh`, `media-skip-backward`,
|
|
31
|
+
`media-playback-start`, `media-playback-pause`,
|
|
32
|
+
`media-skip-forward`) which match the user's Plasma / GNOME /
|
|
33
|
+
Breeze icon set. Update + Quit keep their bundled coloured-accent
|
|
34
|
+
SVGs. Source strings for the playback / restart actions dropped
|
|
35
|
+
their unicode-glyph prefixes (`⏮ ⏵ ⏸ ⏭ ⟳`) so the new icons
|
|
36
|
+
don't read as duplicates; all 9 .ts files updated to match. The
|
|
37
|
+
Quit ✕ glyph was redrawn to fill its 16×16 viewBox edge-to-edge
|
|
38
|
+
so it visually matches the theme icons' pixel weight.
|
|
39
|
+
- **Song-info rows in the tray menu now render with proper icons
|
|
40
|
+
and full-strength text colour.** Title / Artist / Progress /
|
|
41
|
+
Discord-status used to be `setEnabled(False)` so KDE's DBusMenu
|
|
42
|
+
rendered them muted-grey + indented + iconless next to the white
|
|
43
|
+
action labels below. They're now enabled (a stray click opens
|
|
44
|
+
Settings — their natural "tell me more" target) and carry
|
|
45
|
+
`view-media-track`, `view-media-artist`, `chronometer`, and
|
|
46
|
+
`network-connect` / `network-disconnect` icons. The `♪` prefix
|
|
47
|
+
on the title and the `●/○` prefix on the Discord-status row are
|
|
48
|
+
gone — the icons replace them.
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
|
|
52
|
+
- **Settings → Updates "Latest release notes" QTextBrowser was
|
|
53
|
+
parent-less.** `_build_updates_tab` called
|
|
54
|
+
`notes_group.setLayout(QVBoxLayout())` on a QGroupBox that
|
|
55
|
+
already had a QFormLayout installed by `_new_group`. Qt refuses
|
|
56
|
+
to install a second layout (logs "QLayout: Attempting to add
|
|
57
|
+
QLayout to QGroupBox which already has a layout") so the new
|
|
58
|
+
VBoxLayout was discarded and the QTextBrowser ended up as a
|
|
59
|
+
free-floating top-level widget kept alive only by the Python
|
|
60
|
+
reference. In production it still painted because the parent
|
|
61
|
+
page laid it out somewhere reasonable, but it was outside the
|
|
62
|
+
widget tree (`findChildren(QTextBrowser)` returned 0). The view
|
|
63
|
+
is now added via the existing form layout's `addRow`.
|
|
64
|
+
- **Discord handshake errors logged as ERROR-level unexpected
|
|
65
|
+
exceptions with a full traceback every retry.** When Discord
|
|
66
|
+
responded to a `pypresence.Presence.connect()` with an error
|
|
67
|
+
message (e.g. "User logged out" — DiscordError code 1000, or
|
|
68
|
+
"Invalid Client ID"), the bare `except Exception:` clause in
|
|
69
|
+
`_ensure_connected` swallowed it as a programmer bug and emitted
|
|
70
|
+
a noisy traceback every backoff cycle. `pypresence.exceptions.
|
|
71
|
+
DiscordError` is now caught explicitly and logged at INFO; the
|
|
72
|
+
back-off jumps straight to the 15 s ceiling so Refrain doesn't
|
|
73
|
+
retry tightly while the user is signing back into Discord or
|
|
74
|
+
fixing a typo'd client_id.
|
|
75
|
+
- **First Discord push after a forced reconnect could be deduped
|
|
76
|
+
out of existence.** The presence-update dedupe cache lived on
|
|
77
|
+
the orchestrator across `Presence` instance replacements; after
|
|
78
|
+
a reconnect with byte-identical payload data, the new pipe
|
|
79
|
+
carried no state on Discord's side but our cache still claimed
|
|
80
|
+
"we already pushed this", so the user saw "no activity" until
|
|
81
|
+
metadata changed. `_last_payload` is now reset to None in the
|
|
82
|
+
successful-connect path of `_ensure_connected`.
|
|
83
|
+
- **Empty artist row in tray menu when nothing was playing.** The
|
|
84
|
+
artist QAction stayed visible with empty text whenever no track
|
|
85
|
+
was active, rendering as a tall blank line right under
|
|
86
|
+
"(nothing playing)". Now hidden until a real track populates it.
|
|
87
|
+
- **Settings → Updates "Latest release notes" pane stayed empty
|
|
88
|
+
on every Refrain restart within the 24-hour update-check
|
|
89
|
+
cooldown.** `maybe_check_on_startup` short-circuited *before*
|
|
90
|
+
fetching anything when the cooldown was active, so
|
|
91
|
+
`releaseInfoFetched` never fired and `set_latest_release` never
|
|
92
|
+
populated the inline pane. The v0.2.6 workaround — re-fetching
|
|
93
|
+
on Updates-tab activation with `manual=True` — additionally
|
|
94
|
+
fired the "up to date" / "update available" popups on every tab
|
|
95
|
+
visit, which was its own bug. Startup now always fetches the
|
|
96
|
+
release info (silent, no popups) so the pane is populated
|
|
97
|
+
immediately; the cooldown only gates whether that fetch *also*
|
|
98
|
+
triggers the auto-popup. The on-tab-activation fetch is gone.
|
|
99
|
+
|
|
10
100
|
## [0.2.6] - 2026-05-07
|
|
11
101
|
|
|
12
102
|
Localization expansion plus a bundle of reliability fixes accumulated
|
|
@@ -979,7 +1069,8 @@ with a proper, installable Linux app.
|
|
|
979
1069
|
pip-audit, trufflehog, release), Dependabot, issue + PR templates,
|
|
980
1070
|
`CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `SECURITY.md`.
|
|
981
1071
|
|
|
982
|
-
[Unreleased]: https://github.com/Rockykln/refrain/compare/v0.2.
|
|
1072
|
+
[Unreleased]: https://github.com/Rockykln/refrain/compare/v0.2.7...HEAD
|
|
1073
|
+
[0.2.7]: https://github.com/Rockykln/refrain/compare/v0.2.6...v0.2.7
|
|
983
1074
|
[0.2.6]: https://github.com/Rockykln/refrain/compare/v0.2.5...v0.2.6
|
|
984
1075
|
[0.2.5]: https://github.com/Rockykln/refrain/compare/v0.2.4...v0.2.5
|
|
985
1076
|
[0.2.4]: https://github.com/Rockykln/refrain/compare/v0.2.3...v0.2.4
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: refrain
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: Discord Rich Presence for Apple Music on Linux
|
|
5
5
|
Project-URL: Homepage, https://github.com/Rockykln/refrain
|
|
6
6
|
Project-URL: Repository, https://github.com/Rockykln/refrain
|
|
@@ -153,6 +153,15 @@ registers their own (free, takes 30 seconds):
|
|
|
153
153
|
4. Launch Refrain → *Settings → General → Discord Client ID* → paste,
|
|
154
154
|
*Apply*.
|
|
155
155
|
|
|
156
|
+
The first time you launch Refrain without a configured ID, the
|
|
157
|
+
welcome wizard pops up with the setup steps + a live diagnostics
|
|
158
|
+
panel that probes your D-Bus session and Discord IPC socket so you
|
|
159
|
+
know up front whether your environment can host the RPC at all.
|
|
160
|
+
|
|
161
|
+
<p align="center">
|
|
162
|
+
<img src="docs/screenshots/welcome.png" alt="Welcome wizard" width="560"/>
|
|
163
|
+
</p>
|
|
164
|
+
|
|
156
165
|
That's it. The status will appear in Discord on the next track change.
|
|
157
166
|
|
|
158
167
|
## Configuration
|
|
@@ -187,7 +196,7 @@ poll_interval_ms = 500
|
|
|
187
196
|
log_level = "INFO"
|
|
188
197
|
cover_cache_size = 200 # disk cap for cached covers
|
|
189
198
|
idle_grace_s = 30 # clear status when same track plays past duration + grace; 0 disables
|
|
190
|
-
language = "system" # "system" follows QLocale; "en"
|
|
199
|
+
language = "system" # "system" follows QLocale; "en", "de", "es", "fr", "pt", "it", "ru", "pl", "ja", "zh_CN" force a translation
|
|
191
200
|
```
|
|
192
201
|
|
|
193
202
|
Per-source `client_id_*` fields let Apple Music render under one Discord
|
|
@@ -119,6 +119,15 @@ registers their own (free, takes 30 seconds):
|
|
|
119
119
|
4. Launch Refrain → *Settings → General → Discord Client ID* → paste,
|
|
120
120
|
*Apply*.
|
|
121
121
|
|
|
122
|
+
The first time you launch Refrain without a configured ID, the
|
|
123
|
+
welcome wizard pops up with the setup steps + a live diagnostics
|
|
124
|
+
panel that probes your D-Bus session and Discord IPC socket so you
|
|
125
|
+
know up front whether your environment can host the RPC at all.
|
|
126
|
+
|
|
127
|
+
<p align="center">
|
|
128
|
+
<img src="docs/screenshots/welcome.png" alt="Welcome wizard" width="560"/>
|
|
129
|
+
</p>
|
|
130
|
+
|
|
122
131
|
That's it. The status will appear in Discord on the next track change.
|
|
123
132
|
|
|
124
133
|
## Configuration
|
|
@@ -153,7 +162,7 @@ poll_interval_ms = 500
|
|
|
153
162
|
log_level = "INFO"
|
|
154
163
|
cover_cache_size = 200 # disk cap for cached covers
|
|
155
164
|
idle_grace_s = 30 # clear status when same track plays past duration + grace; 0 disables
|
|
156
|
-
language = "system" # "system" follows QLocale; "en"
|
|
165
|
+
language = "system" # "system" follows QLocale; "en", "de", "es", "fr", "pt", "it", "ru", "pl", "ja", "zh_CN" force a translation
|
|
157
166
|
```
|
|
158
167
|
|
|
159
168
|
Per-source `client_id_*` fields let Apple Music render under one Discord
|
|
@@ -285,14 +285,97 @@ What's done, what's next, what's deliberately not in scope.
|
|
|
285
285
|
|
|
286
286
|
## Up next — v0.3
|
|
287
287
|
|
|
288
|
-
- **Polishing the wrapped i18n surface** — wrap the remaining
|
|
289
|
-
fixed-position strings (date formatters, advanced-tab subtitles,
|
|
290
|
-
bluetooth picker labels) so the German build covers everything a
|
|
291
|
-
user sees, not just the high-traffic widgets.
|
|
292
288
|
- **Stable-release AUR build** that doesn't rely on the GitHub
|
|
293
289
|
release tarball — switch to a `git`-source PKGBUILD pinned to the
|
|
294
290
|
signed tag, so AUR users get the exact same commit the release
|
|
295
291
|
workflow ships.
|
|
292
|
+
- **Wrap the remaining fixed-position strings** (date formatters,
|
|
293
|
+
bluetooth picker labels) so every language reaches 100% coverage,
|
|
294
|
+
not just the high-traffic widgets.
|
|
295
|
+
|
|
296
|
+
## Done — v0.2.7
|
|
297
|
+
|
|
298
|
+
- **Tray-menu polish.** Every action carries an icon now —
|
|
299
|
+
freedesktop theme icons (`configure`, `view-list-text`,
|
|
300
|
+
`view-refresh`, `media-skip-{backward,forward}`,
|
|
301
|
+
`media-playback-{start,pause}`) for built-in actions plus the
|
|
302
|
+
bundled coloured-accent SVGs for Update / Quit. Source strings
|
|
303
|
+
for the playback / restart / Discord-status entries dropped
|
|
304
|
+
their unicode-glyph prefixes (`⏮ ⏵ ⏸ ⏭ ⟳ ●/○`); all 9 .ts
|
|
305
|
+
files updated. Quit ✕ glyph redrawn to fill its 16×16 viewBox.
|
|
306
|
+
- **Song-info rows render with proper colour + icons.** Title /
|
|
307
|
+
Artist / Progress / Discord-status used to be `setEnabled(False)`
|
|
308
|
+
so KDE / GNOME's DBusMenu painted them muted-grey + indented +
|
|
309
|
+
iconless. They're now enabled (a click opens Settings) and
|
|
310
|
+
carry `view-media-{track,artist}`, `chronometer`, and
|
|
311
|
+
`network-{connect,disconnect}` icons.
|
|
312
|
+
- **Middle-click on the tray icon toggles play/pause.** Same
|
|
313
|
+
PlayPause command as the tray-menu Play/Pause item, but
|
|
314
|
+
reachable without opening the menu.
|
|
315
|
+
- **Discord handshake errors no longer crash-log.** `pypresence.
|
|
316
|
+
exceptions.DiscordError` (raised when Discord rejects the
|
|
317
|
+
handshake — "User logged out", "Invalid Client ID") fell
|
|
318
|
+
through the bare `except Exception:` and emitted a full
|
|
319
|
+
traceback every retry cycle. Now caught explicitly, logged at
|
|
320
|
+
INFO, with backoff jumping straight to the 15 s ceiling so
|
|
321
|
+
Refrain doesn't retry tightly while you sign back into Discord.
|
|
322
|
+
- **First Discord push after a forced reconnect can no longer be
|
|
323
|
+
deduped out.** `_last_payload` is reset in the connect-success
|
|
324
|
+
path so the dedup cache from a previous Presence instance
|
|
325
|
+
doesn't suppress the first push on the new pipe.
|
|
326
|
+
- **Settings → Updates "Latest release notes" pane populates on
|
|
327
|
+
every restart.** v0.2.6's startup auto-check short-circuited
|
|
328
|
+
before fetching when the 24h cooldown was active; the v0.2.6
|
|
329
|
+
workaround re-fetched on every Updates-tab visit. Both gone —
|
|
330
|
+
startup runs a silent fetch (no popups, no cooldown bump) so
|
|
331
|
+
the pane is populated immediately, while the cooldown still
|
|
332
|
+
gates the auto-nag popup.
|
|
333
|
+
- **Empty artist row in tray menu when nothing was playing**
|
|
334
|
+
(`setVisible(False)` until a real track populates it).
|
|
335
|
+
|
|
336
|
+
## Done — v0.2.6
|
|
337
|
+
|
|
338
|
+
- **8 new UI languages** at 127/127 strings each: Spanish (`es`),
|
|
339
|
+
French (`fr`), Portuguese (`pt`), Italian (`it`), Russian
|
|
340
|
+
(`ru`), Polish (`pl`), Japanese (`ja`), Simplified Chinese
|
|
341
|
+
(`zh_CN`). Settings → Advanced → Language dropdown lists each
|
|
342
|
+
under its native endonym. Together with English + German this
|
|
343
|
+
covers ~3 billion native speakers.
|
|
344
|
+
- **GitHub release bodies were one-line "Full Changelog: …"**
|
|
345
|
+
because the workflow used `generate_release_notes: true`. Now
|
|
346
|
+
extracts the matching `## [X.Y.Z]` section from CHANGELOG.md
|
|
347
|
+
via awk and feeds it as `body_path`; existing v0.1.0 – v0.2.5
|
|
348
|
+
bodies were backfilled out-of-band.
|
|
349
|
+
- **Reliability sweep**: `os.execvp` Restart fallback to
|
|
350
|
+
`python -m refrain` when `argv[0]` isn't runnable;
|
|
351
|
+
Config.save .tmp cleanup on disk-full / read-only;
|
|
352
|
+
`Config._format_value` escapes `\n / \r / \t`;
|
|
353
|
+
`Config._construct` coerces wrongly-typed primitives (e.g.
|
|
354
|
+
`cover_cache_size = "200"`) instead of crashing in
|
|
355
|
+
`_prune_cover_cache`; cover-art `_write_cache` +
|
|
356
|
+
`download_cover_image` clean up `.tmp` siblings on disk
|
|
357
|
+
failure; `_bridge_sandboxed_ipc_socket` permission-error wrap;
|
|
358
|
+
iTunes Search shape-checks; `SessionBusUnavailable` exception
|
|
359
|
+
surfacing instead of bare DBusException; Apply error toast for
|
|
360
|
+
non-writable config dirs; `setup_logging`/`_apply_log_level`
|
|
361
|
+
coerce non-string `log_level`.
|
|
362
|
+
|
|
363
|
+
## Done — v0.2.5
|
|
364
|
+
|
|
365
|
+
- **AUR + Flatpak self-update spawns a terminal automatically**
|
|
366
|
+
running the package-manager command (`yay -Syu refrain` /
|
|
367
|
+
`flatpak update io.github.Rockykln.Refrain`) instead of just
|
|
368
|
+
showing the command in a popup. Falls back to the previous
|
|
369
|
+
message-box hint when no terminal is on PATH (probe list:
|
|
370
|
+
konsole, gnome-terminal, xfce4-terminal, kitty, alacritty,
|
|
371
|
+
foot, xterm, wezterm).
|
|
372
|
+
- **pip auto-update detects "no-op" exits.** PyPI's CDN can lag
|
|
373
|
+
the GitHub Releases API by minutes, so a "0.2.X available"
|
|
374
|
+
check could succeed while pip exited 0 with "Requirement
|
|
375
|
+
already satisfied" (no upgrade). Refrain now parses pip's
|
|
376
|
+
stdout to distinguish "Successfully installed" from
|
|
377
|
+
"Requirement already satisfied" and tells the user to retry
|
|
378
|
+
shortly instead of restarting into the same version.
|
|
296
379
|
|
|
297
380
|
## Done — v0.2.2
|
|
298
381
|
|
|
@@ -4,14 +4,16 @@ The README references screenshots from this directory. To regenerate them:
|
|
|
4
4
|
|
|
5
5
|
| File | What to capture |
|
|
6
6
|
|----------------------------|------------------------------------------------------|
|
|
7
|
-
| `tray-menu.png` | Right-click the Refrain tray icon while a track plays.
|
|
7
|
+
| `tray-menu.png` | Right-click the Refrain tray icon while a track plays. Captures title / artist / progress / Discord-status info rows + Previous / Play-Pause / Next / Settings / Live log / Restart / Quit, all with theme icons. |
|
|
8
8
|
| `settings-general.png` | Settings window → *General* tab, showing Discord client ID, Privacy combo, autostart, notifications, cover art, buttons. |
|
|
9
9
|
| `settings-sources.png` | Settings window → *Sources* tab, showing MPRIS toggle, Bluetooth toggle, and the paired-device dropdown populated. |
|
|
10
|
-
| `settings-updates.png` | Settings window → *Updates* tab. Auto-check on, last-checked timestamp visible,
|
|
10
|
+
| `settings-updates.png` | Settings window → *Updates* tab. Auto-check on, last-checked timestamp visible, the "Latest release notes" pane populated from CHANGELOG. |
|
|
11
|
+
| `settings-advanced.png` | Settings window → *Advanced* tab, showing the Language dropdown (11 entries: System default + 10 native endonyms), poll interval, log level, cover cache size, idle grace, and the Reset-all-settings button. |
|
|
11
12
|
| `update-dialog.png` | The update-available dialog (only appears when a new version is found). Trigger it locally by editing `__version__` to something older and clicking *Check for updates now*. |
|
|
12
13
|
| `discord-rpc.png` | Cropped section of your Discord profile showing the "Listening to" card with cover art + elapsed/total timer. |
|
|
13
14
|
| `notification.png` | A desktop notification fired by Refrain on track change. KDE Plasma's notification with the album cover at left. |
|
|
14
15
|
| `live-log.png` | The live-log window, opened via tray → *Live log…*, with at least 10 lines of streamed log. |
|
|
16
|
+
| `welcome.png` | First-run welcome wizard — shown when no `client_id` is configured yet. Diagnostics panel + Discord-app guidance. |
|
|
15
17
|
|
|
16
18
|
## How to capture on KDE Plasma
|
|
17
19
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
pkgbase = refrain
|
|
2
2
|
pkgdesc = Discord Rich Presence for Apple Music on Linux
|
|
3
|
-
pkgver = 0.2.
|
|
3
|
+
pkgver = 0.2.6
|
|
4
4
|
pkgrel = 1
|
|
5
5
|
url = https://github.com/Rockykln/refrain
|
|
6
6
|
arch = any
|
|
@@ -14,7 +14,7 @@ pkgbase = refrain
|
|
|
14
14
|
depends = python-dbus
|
|
15
15
|
depends = pyside6
|
|
16
16
|
optdepends = python-gobject: enables MPRIS-server publication so Plasma media controls reach Refrain
|
|
17
|
-
source = refrain-0.2.
|
|
18
|
-
sha256sums =
|
|
17
|
+
source = refrain-0.2.6.tar.gz::https://github.com/Rockykln/refrain/archive/v0.2.6.tar.gz
|
|
18
|
+
sha256sums = d5d99a19be2b7414e7d7d1324c7893d2a227a60d15c14969d69102f9d2850294
|
|
19
19
|
|
|
20
20
|
pkgname = refrain
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Maintainer: Rockykln <contact@rockykln.com>
|
|
2
2
|
|
|
3
3
|
pkgname=refrain
|
|
4
|
-
pkgver=0.2.
|
|
4
|
+
pkgver=0.2.7
|
|
5
5
|
pkgrel=1
|
|
6
6
|
pkgdesc="Discord Rich Presence for Apple Music on Linux"
|
|
7
7
|
arch=('any')
|
|
@@ -23,7 +23,7 @@ makedepends=(
|
|
|
23
23
|
'python-wheel'
|
|
24
24
|
)
|
|
25
25
|
source=("$pkgname-$pkgver.tar.gz::https://github.com/Rockykln/refrain/archive/v$pkgver.tar.gz")
|
|
26
|
-
sha256sums=('
|
|
26
|
+
sha256sums=('d5d99a19be2b7414e7d7d1324c7893d2a227a60d15c14969d69102f9d2850294')
|
|
27
27
|
|
|
28
28
|
build() {
|
|
29
29
|
cd "$pkgname-$pkgver"
|
|
@@ -51,6 +51,24 @@
|
|
|
51
51
|
<content_rating type="oars-1.1" />
|
|
52
52
|
|
|
53
53
|
<releases>
|
|
54
|
+
<release version="0.2.7" date="2026-05-07">
|
|
55
|
+
<description>
|
|
56
|
+
<p>
|
|
57
|
+
Tray menu polish + Discord-RPC reliability. Every tray
|
|
58
|
+
action now carries an icon (theme-matched on Plasma /
|
|
59
|
+
GNOME / Breeze), the song-info rows render in normal text
|
|
60
|
+
colour with proper icons instead of greyed-out indented
|
|
61
|
+
rows, and middle-clicking the tray icon toggles
|
|
62
|
+
play/pause. Discord handshake errors (e.g. "User logged
|
|
63
|
+
out", "Invalid Client ID") are now caught explicitly
|
|
64
|
+
instead of crash-logged as unexpected exceptions, with a
|
|
65
|
+
longer back-off so Refrain doesn't retry tightly while
|
|
66
|
+
you're signing back in. The Settings → Updates
|
|
67
|
+
"Latest release notes" pane populates on every restart
|
|
68
|
+
regardless of the 24-hour update-check cooldown.
|
|
69
|
+
</p>
|
|
70
|
+
</description>
|
|
71
|
+
</release>
|
|
54
72
|
<release version="0.2.6" date="2026-05-07">
|
|
55
73
|
<description>
|
|
56
74
|
<p>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.7"
|
|
@@ -390,25 +390,35 @@ class UpdateOrchestrator(QObject):
|
|
|
390
390
|
self._thread: QThread | None = None
|
|
391
391
|
self._worker: _UpdateCheckWorker | None = None
|
|
392
392
|
self._manual = False
|
|
393
|
+
# When True, the in-flight check is purely for populating the
|
|
394
|
+
# in-app release-notes pane — suppress all popups and don't
|
|
395
|
+
# bump last_check_ts (which gates the auto-nag cooldown).
|
|
396
|
+
self._silent = False
|
|
393
397
|
|
|
394
398
|
@property
|
|
395
399
|
def latest(self) -> ReleaseInfo | None:
|
|
396
400
|
return self._latest
|
|
397
401
|
|
|
398
402
|
def maybe_check_on_startup(self) -> None:
|
|
403
|
+
"""Always fire one fetch on startup so the Settings → Updates
|
|
404
|
+
pane has data immediately. The 24-hour cooldown only gates
|
|
405
|
+
whether this fetch can ALSO trigger the auto-popup for new
|
|
406
|
+
releases — within the cooldown the fetch runs silently and
|
|
407
|
+
only refreshes the inline release-notes pane."""
|
|
399
408
|
if not self._config.update.auto_check:
|
|
400
409
|
return
|
|
401
410
|
elapsed = time.time() - self._config.update.last_check_ts
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
self.check_now(manual=False)
|
|
411
|
+
silent = elapsed < self.UPDATE_CHECK_COOLDOWN_S
|
|
412
|
+
if silent:
|
|
413
|
+
log.debug("Auto-update check running silently (cooldown active)")
|
|
414
|
+
self.check_now(manual=False, silent=silent)
|
|
406
415
|
|
|
407
|
-
def check_now(self, manual: bool = True) -> None:
|
|
416
|
+
def check_now(self, manual: bool = True, silent: bool = False) -> None:
|
|
408
417
|
if self._thread is not None:
|
|
409
418
|
log.debug("Update check already in progress")
|
|
410
419
|
return
|
|
411
420
|
self._manual = manual
|
|
421
|
+
self._silent = silent
|
|
412
422
|
self._thread = QThread()
|
|
413
423
|
self._thread.setObjectName("refrain-update-check")
|
|
414
424
|
self._worker = _UpdateCheckWorker()
|
|
@@ -418,11 +428,21 @@ class UpdateOrchestrator(QObject):
|
|
|
418
428
|
self._thread.start()
|
|
419
429
|
|
|
420
430
|
def _on_check_finished(self, release: ReleaseInfo | None) -> None:
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
431
|
+
manual = self._manual
|
|
432
|
+
silent = self._silent
|
|
433
|
+
self._manual = False
|
|
434
|
+
self._silent = False
|
|
435
|
+
|
|
436
|
+
# Only bump the cooldown timestamp when this was a real auto-
|
|
437
|
+
# nag check. A silent pane-refresh shouldn't reset the cooldown
|
|
438
|
+
# — otherwise every startup would block the next day's auto-
|
|
439
|
+
# nag. Manual checks always count as "I just checked".
|
|
440
|
+
if not silent:
|
|
441
|
+
self._config.update.last_check_ts = int(time.time())
|
|
442
|
+
try:
|
|
443
|
+
self._config.save()
|
|
444
|
+
except Exception as e:
|
|
445
|
+
log.debug("Could not persist last_check_ts: %s", e)
|
|
426
446
|
|
|
427
447
|
if self._thread is not None:
|
|
428
448
|
self._thread.quit()
|
|
@@ -430,9 +450,6 @@ class UpdateOrchestrator(QObject):
|
|
|
430
450
|
self._thread = None
|
|
431
451
|
self._worker = None
|
|
432
452
|
|
|
433
|
-
manual = self._manual
|
|
434
|
-
self._manual = False
|
|
435
|
-
|
|
436
453
|
# Always fan out the raw fetch result so subscribers (Settings
|
|
437
454
|
# tab, etc.) can render whatever state they want regardless of
|
|
438
455
|
# whether this constitutes "an update". Cache it too so a
|
|
@@ -441,6 +458,15 @@ class UpdateOrchestrator(QObject):
|
|
|
441
458
|
self._latest = release
|
|
442
459
|
self.releaseInfoFetched.emit(release)
|
|
443
460
|
|
|
461
|
+
# Silent fetches stop here — the pane is populated, no nags.
|
|
462
|
+
if silent:
|
|
463
|
+
log.info(
|
|
464
|
+
"Silent update check finished: latest=%s, current=%s",
|
|
465
|
+
release.version if release else "?",
|
|
466
|
+
__version__,
|
|
467
|
+
)
|
|
468
|
+
return
|
|
469
|
+
|
|
444
470
|
if release is None:
|
|
445
471
|
log.info("Update check: no release info returned")
|
|
446
472
|
if manual:
|
|
@@ -608,19 +634,6 @@ def main() -> int:
|
|
|
608
634
|
)
|
|
609
635
|
updater.releaseInfoFetched.connect(settings.set_latest_release)
|
|
610
636
|
|
|
611
|
-
# Auto-fetch on first visit to Settings → Updates so the inline
|
|
612
|
-
# release-notes pane populates without the user needing to click
|
|
613
|
-
# "Check for updates now". Skipped when we already have a cached
|
|
614
|
-
# release this session — re-fetching every tab open is wasteful
|
|
615
|
-
# and can hit GitHub's unauthenticated rate limit on multi-restart
|
|
616
|
-
# debug sessions. The 24-hour startup cooldown stays in place for
|
|
617
|
-
# actual auto-checks; this is opt-in via tab activation.
|
|
618
|
-
def _maybe_fetch_for_tab() -> None:
|
|
619
|
-
if updater.latest is None and updater._thread is None:
|
|
620
|
-
updater.check_now(manual=True)
|
|
621
|
-
|
|
622
|
-
settings.updatesTabRequested.connect(_maybe_fetch_for_tab)
|
|
623
|
-
|
|
624
637
|
# Log-window wireup
|
|
625
638
|
def _show_log() -> None:
|
|
626
639
|
log_window.show()
|
|
@@ -143,6 +143,12 @@ class DiscordRPC:
|
|
|
143
143
|
p.connect()
|
|
144
144
|
self._presence = p
|
|
145
145
|
self._backoff_s = 2.0
|
|
146
|
+
# A fresh IPC pipe carries no state on Discord's side —
|
|
147
|
+
# so the dedup cache from a *previous* presence object
|
|
148
|
+
# would wrongly skip the first update on the new
|
|
149
|
+
# connection (Discord would then keep showing nothing
|
|
150
|
+
# until the daemon picks up a metadata change).
|
|
151
|
+
self._last_payload = None
|
|
146
152
|
log.info("Discord RPC connected")
|
|
147
153
|
return True
|
|
148
154
|
except (
|
|
@@ -153,6 +159,17 @@ class DiscordRPC:
|
|
|
153
159
|
OSError,
|
|
154
160
|
) as e:
|
|
155
161
|
log.debug("Discord RPC connect failed: %s", e)
|
|
162
|
+
except ppx.DiscordError as e:
|
|
163
|
+
# Discord accepted the IPC pipe but sent back an error
|
|
164
|
+
# response to the handshake. Common reasons:
|
|
165
|
+
# - "User logged out": user signed out of Discord
|
|
166
|
+
# - "Invalid Client ID": client_id is malformed / not a
|
|
167
|
+
# Discord application (Settings → Discord input typo)
|
|
168
|
+
# These aren't bugs in Refrain — log at INFO and back off
|
|
169
|
+
# longer than the standard transient-error retry, since
|
|
170
|
+
# the user has to take action (sign back in, fix ID).
|
|
171
|
+
log.info("Discord RPC handshake rejected: %s", e)
|
|
172
|
+
self._backoff_s = self._max_backoff_s
|
|
156
173
|
except Exception:
|
|
157
174
|
log.exception("Discord RPC connect unexpected error")
|
|
158
175
|
self._presence = None
|
|
Binary file
|
|
@@ -420,24 +420,24 @@ Nach dem Bestätigen unten im Einstellungen-Fenster auf „Übernehmen“ klicke
|
|
|
420
420
|
<message>
|
|
421
421
|
<location filename="../ui/tray.py" line="81"/>
|
|
422
422
|
<location filename="../ui/tray.py" line="174"/>
|
|
423
|
-
<source
|
|
424
|
-
<translation
|
|
423
|
+
<source>Discord: not connected</source>
|
|
424
|
+
<translation>Discord: nicht verbunden</translation>
|
|
425
425
|
</message>
|
|
426
426
|
<message>
|
|
427
427
|
<location filename="../ui/tray.py" line="84"/>
|
|
428
|
-
<source
|
|
429
|
-
<translation
|
|
428
|
+
<source>Previous</source>
|
|
429
|
+
<translation>Zurück</translation>
|
|
430
430
|
</message>
|
|
431
431
|
<message>
|
|
432
432
|
<location filename="../ui/tray.py" line="86"/>
|
|
433
433
|
<location filename="../ui/tray.py" line="159"/>
|
|
434
|
-
<source
|
|
435
|
-
<translation
|
|
434
|
+
<source>Play</source>
|
|
435
|
+
<translation>Wiedergabe</translation>
|
|
436
436
|
</message>
|
|
437
437
|
<message>
|
|
438
438
|
<location filename="../ui/tray.py" line="88"/>
|
|
439
|
-
<source
|
|
440
|
-
<translation
|
|
439
|
+
<source>Next</source>
|
|
440
|
+
<translation>Weiter</translation>
|
|
441
441
|
</message>
|
|
442
442
|
<message>
|
|
443
443
|
<location filename="../ui/tray.py" line="102"/>
|
|
@@ -457,8 +457,8 @@ Nach dem Bestätigen unten im Einstellungen-Fenster auf „Übernehmen“ klicke
|
|
|
457
457
|
</message>
|
|
458
458
|
<message>
|
|
459
459
|
<location filename="../ui/tray.py" line="111"/>
|
|
460
|
-
<source
|
|
461
|
-
<translation
|
|
460
|
+
<source>Restart Refrain</source>
|
|
461
|
+
<translation>Refrain neu starten</translation>
|
|
462
462
|
</message>
|
|
463
463
|
<message>
|
|
464
464
|
<location filename="../ui/tray.py" line="113"/>
|
|
@@ -467,8 +467,8 @@ Nach dem Bestätigen unten im Einstellungen-Fenster auf „Übernehmen“ klicke
|
|
|
467
467
|
</message>
|
|
468
468
|
<message>
|
|
469
469
|
<location filename="../ui/tray.py" line="157"/>
|
|
470
|
-
<source
|
|
471
|
-
<translation
|
|
470
|
+
<source>Pause</source>
|
|
471
|
+
<translation>Pause</translation>
|
|
472
472
|
</message>
|
|
473
473
|
<message>
|
|
474
474
|
<location filename="../ui/tray.py" line="164"/>
|
|
@@ -477,8 +477,8 @@ Nach dem Bestätigen unten im Einstellungen-Fenster auf „Übernehmen“ klicke
|
|
|
477
477
|
</message>
|
|
478
478
|
<message>
|
|
479
479
|
<location filename="../ui/tray.py" line="172"/>
|
|
480
|
-
<source
|
|
481
|
-
<translation
|
|
480
|
+
<source>Discord: connected</source>
|
|
481
|
+
<translation>Discord: verbunden</translation>
|
|
482
482
|
</message>
|
|
483
483
|
</context>
|
|
484
484
|
<context>
|
|
Binary file
|