spolyrics 1.2.1__tar.gz → 1.2.2__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.
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 paturrr
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 paturrr
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spolyrics
3
- Version: 1.2.1
3
+ Version: 1.2.2
4
4
  Summary: A minimalist, borderless, zero-delay synced lyrics miniplayer for Spotify on Windows.
5
5
  Author: SpoLyrics Team
6
6
  Requires-Python: >=3.8
@@ -25,7 +25,8 @@ Dynamic: summary
25
25
  <h1 align="center">SpoLyrics</h1>
26
26
 
27
27
  <p align="center">
28
- <em>A minimalist, transparent, and zero-delay Spotify lyrics miniplayer.</em>
28
+ <em>A minimalist, transparent, and zero-delay Spotify lyrics miniplayer.</em><br>
29
+ <strong>🌐 <a href="https://paturrr.github.io/SpoLyrics/">Visit the Official Website</a></strong>
29
30
  </p>
30
31
 
31
32
  <p align="center">
@@ -75,6 +76,9 @@ I built this project to solve a specific complaint from my friends: they wanted
75
76
 
76
77
  - **Advanced Customization (Settings)**
77
78
  Change lyrics color using a modern real-time custom HSV color picker, adjust window transparency (opacity), and enable "Auto-Start with Windows". All configurations are permanently saved.
79
+
80
+ - **Auto Update Checker**
81
+ Automatically checks for the newest version on PyPI when you launch the app, offering a seamless one-click update and restart experience.
78
82
 
79
83
  ## Invisible Controls
80
84
 
@@ -1,126 +1,130 @@
1
- <p align="center">
2
- <img src="https://raw.githubusercontent.com/paturrr/SpoLyrics/main/icon.ico" width="150" alt="SpoLyrics Logo">
3
- </p>
4
-
5
- <h1 align="center">SpoLyrics</h1>
6
-
7
- <p align="center">
8
- <em>A minimalist, transparent, and zero-delay Spotify lyrics miniplayer.</em>
9
- </p>
10
-
11
- <p align="center">
12
- <img src="https://img.shields.io/github/stars/paturrr/SpoLyrics.svg?style=flat-square&color=1DB954&label=stars&logo=github&logoColor=white" alt="Stars">
13
- <img src="https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20%7C%203.12-1DB954?style=flat-square&logo=python&logoColor=white" alt="Python Versions">
14
- <img src="https://img.shields.io/badge/OS-Windows%2010%2F11-1DB954?style=flat-square&logo=windows&logoColor=white" alt="Windows Only">
15
- <img src="https://img.shields.io/badge/%F0%9F%93%9C_License-MIT-1DB954?style=flat-square" alt="MIT license">
16
- </p>
17
-
18
- <p align="center">
19
- <strong>0-Delay Sync &middot; Native Windows API &middot; Glassmorphism UI &middot; Invisible Controls</strong><br>
20
- <sub>Built with Python & Windows System Media Transport Controls for 100% precision.</sub>
21
- </p>
22
-
23
- <p align="center">
24
- <img src="https://raw.githubusercontent.com/paturrr/SpoLyrics/main/assets/1.png" alt="SpoLyrics Transparent UI & Lyrics Sync">
25
- <br><br>
26
- <img src="https://raw.githubusercontent.com/paturrr/SpoLyrics/main/assets/2.png" alt="SpoLyrics Modern Settings & Shortcuts">
27
- </p>
28
-
29
- ---
30
-
31
- ## Background & Feedback
32
-
33
- I built this project to solve a specific complaint from my friends: they wanted to listen to songs on Spotify or YouTube Music while working, but the official miniplayers didn't show any lyrics.
34
-
35
- **Note:** This application is still in active development! If you encounter any bugs, have a feature request, or just want to suggest an improvement, please don't hesitate to open an issue or let me know.
36
-
37
- ---
38
-
39
- ## Key Features
40
-
41
- - **Zero-Delay Sync**
42
- 100% precise time synchronization. Pulls real-time duration data directly from the Windows OS core.
43
-
44
- - **Smart Duration Match**
45
- Automatically matches lyrics based on the duration of the currently playing song version (solving the Radio Edit vs. Album Version mismatch).
46
-
47
- - **Glassmorphism UI**
48
- Elegant, transparent, and borderless design.
49
-
50
- - **Freely Draggable**
51
- Left-click and hold anywhere to drag the lyrics window wherever you like.
52
-
53
- - **System Tray Integration**
54
- Runs quietly in the background. Right-click the system tray icon (SpoLyrics logo) to access settings, hide the lyrics, or view shortcuts.
55
-
56
- - **Advanced Customization (Settings)**
57
- Change lyrics color using a modern real-time custom HSV color picker, adjust window transparency (opacity), and enable "Auto-Start with Windows". All configurations are permanently saved.
58
-
59
- ## Invisible Controls
60
-
61
- This application uses zero conventional buttons to keep the UI perfectly clean. Use these mouse gestures:
62
-
63
- - `Right Click`: Play / Pause
64
- - `Mouse Scroll (Up/Down)`: Next / Previous track
65
- - `Middle Click (Scroll Wheel or 3-Finger Tap on Touchpad)`: Toggle Pin / Lock Window
66
- - *When locked, the resize icon changes to a padlock (🔒) and the app ignores all drags/clicks to prevent accidental touches. Middle click again to unlock.*
67
- - `Ctrl + Left Click`: Toggle song title visibility
68
- - `Ctrl + Mouse Scroll`: Increase / Decrease font size
69
- - `Drag Bottom Right Corner (⇲)`: Resize the window
70
- - `Double Left Click`: Close the application
71
-
72
- ## Installation
73
-
74
- Run this single command in your Windows Terminal or Command Prompt (Requires **Python 3.8 to 3.12**):
75
-
76
- > **Note on Python Version:** Do NOT use Python 3.13. The required `winsdk` package does not yet have pre-compiled binaries for Python 3.13 and will fail to install. Please stick to Python 3.12 or older.
77
-
78
- ```bash
79
- pip install spolyrics
80
- ```
81
- *(If you get a `pip is not recognized` error, use this alternative command instead:)*
82
- ```bash
83
- python -m pip install spolyrics
84
- ```
85
-
86
- > **IMPORTANT (OS Support):**
87
- > This app is **Exclusive to Windows**. Because it uses `winsdk` (Windows System Media Transport Controls) to achieve 0-delay performance without third-party servers, it **CANNOT** be installed on macOS or Linux.
88
-
89
- ### Alternative Installation (Manual)
90
-
91
- If you prefer to download the source code manually (e.g., as a `.zip` file) instead of using the direct `git` command above, you must install the required dependencies (the "shopping list") yourself.
92
- Open your terminal inside the `SpoLyrics` folder and run:
93
- ```bash
94
- pip install -r requirements.txt
95
- ```
96
-
97
- ## Usage
98
-
99
- Once installed, you can launch the app from any directory by typing:
100
- ```bash
101
- spolyrics
102
- ```
103
- Or, if you want it to run smoothly without spawning a black background terminal:
104
- ```bash
105
- pythonw -m main
106
- ```
107
-
108
- *(Make sure Spotify or your Windows media player is running and playing a song!)*
109
-
110
- ## Updating
111
-
112
- To update the application to the latest version, run:
113
- ```bash
114
- pip install --upgrade spolyrics
115
- ```
116
-
117
- ## Uninstallation
118
-
119
- If you wish to remove this application from your computer, simply run:
120
- ```bash
121
- pip uninstall spolyrics
122
- ```
123
-
124
- ## License
125
-
126
- This project is licensed under the [MIT License](LICENSE) - see the LICENSE file for details.
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/paturrr/SpoLyrics/main/icon.ico" width="150" alt="SpoLyrics Logo">
3
+ </p>
4
+
5
+ <h1 align="center">SpoLyrics</h1>
6
+
7
+ <p align="center">
8
+ <em>A minimalist, transparent, and zero-delay Spotify lyrics miniplayer.</em><br>
9
+ <strong>🌐 <a href="https://paturrr.github.io/SpoLyrics/">Visit the Official Website</a></strong>
10
+ </p>
11
+
12
+ <p align="center">
13
+ <img src="https://img.shields.io/github/stars/paturrr/SpoLyrics.svg?style=flat-square&color=1DB954&label=stars&logo=github&logoColor=white" alt="Stars">
14
+ <img src="https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20%7C%203.12-1DB954?style=flat-square&logo=python&logoColor=white" alt="Python Versions">
15
+ <img src="https://img.shields.io/badge/OS-Windows%2010%2F11-1DB954?style=flat-square&logo=windows&logoColor=white" alt="Windows Only">
16
+ <img src="https://img.shields.io/badge/%F0%9F%93%9C_License-MIT-1DB954?style=flat-square" alt="MIT license">
17
+ </p>
18
+
19
+ <p align="center">
20
+ <strong>0-Delay Sync &middot; Native Windows API &middot; Glassmorphism UI &middot; Invisible Controls</strong><br>
21
+ <sub>Built with Python & Windows System Media Transport Controls for 100% precision.</sub>
22
+ </p>
23
+
24
+ <p align="center">
25
+ <img src="https://raw.githubusercontent.com/paturrr/SpoLyrics/main/assets/1.png" alt="SpoLyrics Transparent UI & Lyrics Sync">
26
+ <br><br>
27
+ <img src="https://raw.githubusercontent.com/paturrr/SpoLyrics/main/assets/2.png" alt="SpoLyrics Modern Settings & Shortcuts">
28
+ </p>
29
+
30
+ ---
31
+
32
+ ## Background & Feedback
33
+
34
+ I built this project to solve a specific complaint from my friends: they wanted to listen to songs on Spotify or YouTube Music while working, but the official miniplayers didn't show any lyrics.
35
+
36
+ **Note:** This application is still in active development! If you encounter any bugs, have a feature request, or just want to suggest an improvement, please don't hesitate to open an issue or let me know.
37
+
38
+ ---
39
+
40
+ ## Key Features
41
+
42
+ - **Zero-Delay Sync**
43
+ 100% precise time synchronization. Pulls real-time duration data directly from the Windows OS core.
44
+
45
+ - **Smart Duration Match**
46
+ Automatically matches lyrics based on the duration of the currently playing song version (solving the Radio Edit vs. Album Version mismatch).
47
+
48
+ - **Glassmorphism UI**
49
+ Elegant, transparent, and borderless design.
50
+
51
+ - **Freely Draggable**
52
+ Left-click and hold anywhere to drag the lyrics window wherever you like.
53
+
54
+ - **System Tray Integration**
55
+ Runs quietly in the background. Right-click the system tray icon (SpoLyrics logo) to access settings, hide the lyrics, or view shortcuts.
56
+
57
+ - **Advanced Customization (Settings)**
58
+ Change lyrics color using a modern real-time custom HSV color picker, adjust window transparency (opacity), and enable "Auto-Start with Windows". All configurations are permanently saved.
59
+
60
+ - **Auto Update Checker**
61
+ Automatically checks for the newest version on PyPI when you launch the app, offering a seamless one-click update and restart experience.
62
+
63
+ ## Invisible Controls
64
+
65
+ This application uses zero conventional buttons to keep the UI perfectly clean. Use these mouse gestures:
66
+
67
+ - `Right Click`: Play / Pause
68
+ - `Mouse Scroll (Up/Down)`: Next / Previous track
69
+ - `Middle Click (Scroll Wheel or 3-Finger Tap on Touchpad)`: Toggle Pin / Lock Window
70
+ - *When locked, the resize icon changes to a padlock (🔒) and the app ignores all drags/clicks to prevent accidental touches. Middle click again to unlock.*
71
+ - `Ctrl + Left Click`: Toggle song title visibility
72
+ - `Ctrl + Mouse Scroll`: Increase / Decrease font size
73
+ - `Drag Bottom Right Corner (⇲)`: Resize the window
74
+ - `Double Left Click`: Close the application
75
+
76
+ ## Installation
77
+
78
+ Run this single command in your Windows Terminal or Command Prompt (Requires **Python 3.8 to 3.12**):
79
+
80
+ > **Note on Python Version:** Do NOT use Python 3.13. The required `winsdk` package does not yet have pre-compiled binaries for Python 3.13 and will fail to install. Please stick to Python 3.12 or older.
81
+
82
+ ```bash
83
+ pip install spolyrics
84
+ ```
85
+ *(If you get a `pip is not recognized` error, use this alternative command instead:)*
86
+ ```bash
87
+ python -m pip install spolyrics
88
+ ```
89
+
90
+ > **IMPORTANT (OS Support):**
91
+ > This app is **Exclusive to Windows**. Because it uses `winsdk` (Windows System Media Transport Controls) to achieve 0-delay performance without third-party servers, it **CANNOT** be installed on macOS or Linux.
92
+
93
+ ### Alternative Installation (Manual)
94
+
95
+ If you prefer to download the source code manually (e.g., as a `.zip` file) instead of using the direct `git` command above, you must install the required dependencies (the "shopping list") yourself.
96
+ Open your terminal inside the `SpoLyrics` folder and run:
97
+ ```bash
98
+ pip install -r requirements.txt
99
+ ```
100
+
101
+ ## Usage
102
+
103
+ Once installed, you can launch the app from any directory by typing:
104
+ ```bash
105
+ spolyrics
106
+ ```
107
+ Or, if you want it to run smoothly without spawning a black background terminal:
108
+ ```bash
109
+ pythonw -m main
110
+ ```
111
+
112
+ *(Make sure Spotify or your Windows media player is running and playing a song!)*
113
+
114
+ ## Updating
115
+
116
+ To update the application to the latest version, run:
117
+ ```bash
118
+ pip install --upgrade spolyrics
119
+ ```
120
+
121
+ ## Uninstallation
122
+
123
+ If you wish to remove this application from your computer, simply run:
124
+ ```bash
125
+ pip uninstall spolyrics
126
+ ```
127
+
128
+ ## License
129
+
130
+ This project is licensed under the [MIT License](LICENSE) - see the LICENSE file for details.
@@ -12,8 +12,10 @@ import logging
12
12
  import sqlite3
13
13
  from datetime import datetime, timezone
14
14
  from assets import ICON_B64
15
+ from tkinter import messagebox
15
16
  from winsdk.windows.media.control import GlobalSystemMediaTransportControlsSessionManager as MediaManager
16
17
 
18
+ CURRENT_VERSION = "1.2.2"
17
19
  CONFIG_PATH = os.path.join(os.environ.get("APPDATA", ""), "SpoLyrics", "config.json")
18
20
  APP_DIR = os.path.join(os.environ.get("APPDATA", ""), "SpoLyrics")
19
21
  os.makedirs(APP_DIR, exist_ok=True)
@@ -85,19 +87,25 @@ def save_config(config):
85
87
  with open(CONFIG_PATH, 'w') as f:
86
88
  json.dump(config, f)
87
89
 
88
- def set_auto_start(enable):
90
+ def get_exe_path():
91
+ import sys
92
+ if getattr(sys, 'frozen', False):
93
+ return sys.executable
94
+ script_exe = os.path.join(sys.prefix, 'Scripts', 'spolyrics.exe')
95
+ if os.path.exists(script_exe):
96
+ return script_exe
97
+ return sys.executable
98
+
99
+ def set_auto_start(enable, force_update=False):
89
100
  try:
90
101
  if enable:
91
102
  app_dir = os.path.join(os.environ.get("APPDATA", ""), "SpoLyrics")
92
103
  icon_path = os.path.join(app_dir, 'icon.ico')
93
- import sys
94
- if getattr(sys, 'frozen', False):
95
- exe_path = sys.executable
96
- else:
97
- exe_path = shutil.which('spolyrics') or sys.executable
104
+ exe_path = get_exe_path()
98
105
  if exe_path and os.path.exists(icon_path):
99
- ps_script = f"$s=(New-Object -COM WScript.Shell).CreateShortcut('{STARTUP_SHORTCUT}');$s.TargetPath='{exe_path}';$s.IconLocation='{icon_path}';$s.Save()"
100
- subprocess.run(["powershell", "-Command", ps_script], creationflags=0x08000000)
106
+ if force_update or not os.path.exists(STARTUP_SHORTCUT):
107
+ ps_script = f"$s=(New-Object -COM WScript.Shell).CreateShortcut('{STARTUP_SHORTCUT}');$s.TargetPath='{exe_path}';$s.IconLocation='{icon_path}';$s.Save()"
108
+ subprocess.run(["powershell", "-Command", ps_script], creationflags=0x08000000)
101
109
  else:
102
110
  if os.path.exists(STARTUP_SHORTCUT):
103
111
  os.remove(STARTUP_SHORTCUT)
@@ -138,6 +146,9 @@ class MiniLyrics:
138
146
 
139
147
  self.lbl_next = tk.Label(self.root, text="", fg='#b3b3b3', bg='#191414', font=('Arial', self.font_nxt), wraplength=330, justify="center")
140
148
  self.lbl_next.pack(expand=True, fill='both', padx=10, pady=(0, 15))
149
+
150
+ self.update_available = False
151
+ self.root.after(2000, self.check_updates)
141
152
 
142
153
  self.grip = tk.Label(self.root, text="⇲", fg='#333333', bg='#191414', cursor="size_nw_se")
143
154
  self.grip.place(relx=1.0, rely=1.0, anchor="se")
@@ -250,6 +261,16 @@ class MiniLyrics:
250
261
 
251
262
  def on_scroll(self, event):
252
263
  if self.is_pinned: return "break"
264
+
265
+ now = time.time()
266
+ if not hasattr(self, 'last_scroll_time'):
267
+ self.last_scroll_time = 0
268
+
269
+ if now - self.last_scroll_time < 0.8:
270
+ return "break"
271
+
272
+ self.last_scroll_time = now
273
+
253
274
  if event.delta > 0: self.media_control('prev')
254
275
  else: self.media_control('next')
255
276
  return "break"
@@ -730,7 +751,47 @@ class MiniLyrics:
730
751
 
731
752
  asyncio.run(main_loop())
732
753
 
754
+ def check_updates(self):
755
+ def _check():
756
+ try:
757
+ resp = requests.get('https://pypi.org/pypi/spolyrics/json', timeout=5).json()
758
+ latest = resp['info']['version']
759
+ if latest != CURRENT_VERSION:
760
+ self.root.after(0, self.show_update_prompt, latest)
761
+ except Exception as e:
762
+ logging.error("Failed to check for updates", exc_info=e)
763
+ threading.Thread(target=_check, daemon=True).start()
764
+
765
+ def prompt_update(self):
766
+ if self.update_available:
767
+ self.show_update_prompt(self.update_available)
768
+
769
+ def show_update_prompt(self, latest):
770
+ self.update_available = latest
771
+ if getattr(self, 'tray_icon', None):
772
+ self.tray_icon.update_menu()
773
+
774
+ res = messagebox.askyesno("Update Available", f"A new version of SpoLyrics (v{latest}) is available!\n\nYou are currently on v{CURRENT_VERSION}.\nWould you like to update now?")
775
+ if res:
776
+ import tempfile
777
+ bat_path = os.path.join(tempfile.gettempdir(), "update_spolyrics.bat")
778
+ exe_path = get_exe_path()
779
+ with open(bat_path, 'w') as f:
780
+ f.write('@echo off\n')
781
+ f.write('echo Updating SpoLyrics...\n')
782
+ f.write('ping 127.0.0.1 -n 3 > nul\n')
783
+ f.write('python -m pip install --upgrade spolyrics\n')
784
+ f.write(f'start "" "{exe_path}"\n')
785
+ f.write('del "%~f0"\n')
786
+ subprocess.Popen(['cmd.exe', '/c', bat_path], creationflags=16)
787
+ if getattr(self, 'tray_icon', None):
788
+ self.tray_icon.stop()
789
+ self.root.quit()
790
+ import sys
791
+ sys.exit(0)
792
+
733
793
  def create_shortcut():
794
+ path_changed = False
734
795
  try:
735
796
  shortcut_path = os.path.join(os.environ.get("APPDATA", ""), "Microsoft", "Windows", "Start Menu", "Programs", "SpoLyrics.lnk")
736
797
  app_dir = os.path.join(os.environ.get("APPDATA", ""), "SpoLyrics")
@@ -747,17 +808,26 @@ def create_shortcut():
747
808
  if not os.path.exists(shortcut_path):
748
809
  needs_update = True
749
810
 
811
+ exe_path = get_exe_path()
812
+ path_file = os.path.join(app_dir, 'current_exe_path.txt')
813
+ saved_path = ""
814
+ if os.path.exists(path_file):
815
+ with open(path_file, 'r') as f:
816
+ saved_path = f.read().strip()
817
+
818
+ if saved_path != exe_path:
819
+ needs_update = True
820
+ path_changed = True
821
+ with open(path_file, 'w') as f:
822
+ f.write(exe_path)
823
+
750
824
  if needs_update:
751
- import sys
752
- if getattr(sys, 'frozen', False):
753
- exe_path = sys.executable
754
- else:
755
- exe_path = shutil.which('spolyrics') or sys.executable
756
825
  if exe_path:
757
826
  ps_script = f"$s=(New-Object -COM WScript.Shell).CreateShortcut('{shortcut_path}');$s.TargetPath='{exe_path}';$s.IconLocation='{icon_path}';$s.Save()"
758
827
  subprocess.run(["powershell", "-Command", ps_script], creationflags=0x08000000)
759
828
  except Exception as e:
760
829
  logging.error("Failed to create shortcut", exc_info=e)
830
+ return path_changed
761
831
 
762
832
  def setup_tray(app):
763
833
  try:
@@ -786,27 +856,54 @@ def setup_tray(app):
786
856
  logging.error("Failed to open tray icon image, using fallback", exc_info=e)
787
857
  image = Image.new('RGB', (64, 64), color = (29, 185, 84))
788
858
 
789
- menu = pystray.Menu(
790
- pystray.MenuItem("Shortcuts & Info", on_info),
791
- pystray.MenuItem("Settings", on_settings),
792
- pystray.MenuItem("Toggle Visibility", on_toggle_lyrics),
793
- pystray.MenuItem("Quit", on_quit)
794
- )
795
-
796
- icon = pystray.Icon("SpoLyrics", image, "SpoLyrics", menu)
859
+ def get_menu():
860
+ items = [
861
+ pystray.MenuItem("Shortcuts & Info", on_info),
862
+ pystray.MenuItem("Settings", on_settings),
863
+ pystray.MenuItem("Toggle Visibility", on_toggle_lyrics),
864
+ pystray.MenuItem("Quit", on_quit),
865
+ pystray.MenuItem(f"v{CURRENT_VERSION}", lambda: None, enabled=False)
866
+ ]
867
+ if getattr(app, 'update_available', False):
868
+ items.insert(0, pystray.MenuItem("🔥 Update Available!", lambda: app.root.after(0, app.prompt_update)))
869
+ return pystray.Menu(*items)
870
+
871
+ icon = pystray.Icon("SpoLyrics", image, "SpoLyrics", menu=get_menu)
872
+ app.tray_icon = icon
797
873
  threading.Thread(target=icon.run, daemon=True).start()
798
874
  except Exception as e:
799
875
  logging.error("Tray icon failed to load", exc_info=e)
800
876
 
877
+ def check_single_instance():
878
+ mutex_name = "Global\\SpoLyrics_Mutex"
879
+ mutex = ctypes.windll.kernel32.CreateMutexW(None, False, mutex_name)
880
+ last_error = ctypes.windll.kernel32.GetLastError()
881
+
882
+ if last_error == 183:
883
+ from tkinter import messagebox
884
+ import sys
885
+ temp_root = tk.Tk()
886
+ temp_root.withdraw()
887
+ temp_root.attributes('-topmost', True)
888
+ res = messagebox.askyesno("Already Running", "SpoLyrics is already running in the background.\n\nAre you sure you want to open another instance?", parent=temp_root)
889
+ temp_root.destroy()
890
+ if not res:
891
+ sys.exit(0)
892
+ return mutex
893
+
801
894
  def start_app():
895
+ global _app_mutex
896
+ _app_mutex = check_single_instance()
897
+
802
898
  try:
803
899
  ctypes.windll.shcore.SetProcessDpiAwareness(1)
804
900
  except Exception as e:
805
901
  logging.error("Failed to set DPI awareness", exc_info=e)
902
+ logging.error("Failed to set DPI awareness", exc_info=e)
806
903
 
807
- create_shortcut()
904
+ path_changed = create_shortcut()
808
905
  config = load_config()
809
- set_auto_start(config['auto_start'])
906
+ set_auto_start(config['auto_start'], force_update=path_changed)
810
907
 
811
908
  app = MiniLyrics(config)
812
909
  setup_tray(app)
@@ -2,7 +2,7 @@ from setuptools import setup
2
2
 
3
3
  setup(
4
4
  name='spolyrics',
5
- version='1.2.1',
5
+ version='1.2.2',
6
6
  description='A minimalist, borderless, zero-delay synced lyrics miniplayer for Spotify on Windows.',
7
7
  long_description=open('README.md', 'r', encoding='utf-8').read(),
8
8
  long_description_content_type='text/markdown',
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spolyrics
3
- Version: 1.2.1
3
+ Version: 1.2.2
4
4
  Summary: A minimalist, borderless, zero-delay synced lyrics miniplayer for Spotify on Windows.
5
5
  Author: SpoLyrics Team
6
6
  Requires-Python: >=3.8
@@ -25,7 +25,8 @@ Dynamic: summary
25
25
  <h1 align="center">SpoLyrics</h1>
26
26
 
27
27
  <p align="center">
28
- <em>A minimalist, transparent, and zero-delay Spotify lyrics miniplayer.</em>
28
+ <em>A minimalist, transparent, and zero-delay Spotify lyrics miniplayer.</em><br>
29
+ <strong>🌐 <a href="https://paturrr.github.io/SpoLyrics/">Visit the Official Website</a></strong>
29
30
  </p>
30
31
 
31
32
  <p align="center">
@@ -75,6 +76,9 @@ I built this project to solve a specific complaint from my friends: they wanted
75
76
 
76
77
  - **Advanced Customization (Settings)**
77
78
  Change lyrics color using a modern real-time custom HSV color picker, adjust window transparency (opacity), and enable "Auto-Start with Windows". All configurations are permanently saved.
79
+
80
+ - **Auto Update Checker**
81
+ Automatically checks for the newest version on PyPI when you launch the app, offering a seamless one-click update and restart experience.
78
82
 
79
83
  ## Invisible Controls
80
84
 
File without changes
File without changes