diff --git a/Readme.md b/Readme.md index 41cd823..7c3e85e 100644 --- a/Readme.md +++ b/Readme.md @@ -15,12 +15,6 @@ - [ ] 自动查找网络歌词 -### 感觉以下第三方库 - -- [`python3-mpd2`](https://github.com/Mic92/python-mpd2), 本项目内置了修改版的`python3-mpd2`, 加入了Gtk的信号与槽机制的支持, 并更加友好的方式处理异常, 减少程序崩溃。 -- [`python3-mutagen`](https://github.com/quodlibet/mutagen), 用于获取歌曲文件内嵌的封面。 - - ### 项目依赖 以`debian 12`为例 @@ -28,7 +22,7 @@ - `python3-gi` gobject - `gir1.2-gtk-3.0` Gtk3 - `python3-mutagen` 获取歌曲标签信息的库 -- `python3-mpd2` MPD连接库(已内置修改版) +- `python3-mpd2` MPD连接库(已内置修改版,接入Gtk的信号与槽机制, 并优化了异常处理) - `python3-pil` 图像处理库 - `python3-gi-cairo` 图像处理库 diff --git a/usr/lib/sonist/mpd.py b/usr/lib/sonist/mpd.py index 0973641..d2a5b40 100644 --- a/usr/lib/sonist/mpd.py +++ b/usr/lib/sonist/mpd.py @@ -799,10 +799,9 @@ class MPDClient(MPDClientBase, GObject.Object): self.emit('state_changed', state) self.current_state = state - + if song.get('id') != self.current_song_id: - if self.current_song_id is not None: - self.emit('song_changed', status, song) + self.emit('song_changed', status, song) self.current_song_id = song.get('id') @@ -825,6 +824,7 @@ class MPDClient(MPDClientBase, GObject.Object): self._try_connect() if self.connected: self.emit('online') + self.current_song_id = self.currentsong().get('id') self.heart_beat() diff --git a/usr/lib/sonist/preferences.py b/usr/lib/sonist/preferences.py index 58df836..8a1c6f0 100644 --- a/usr/lib/sonist/preferences.py +++ b/usr/lib/sonist/preferences.py @@ -23,20 +23,21 @@ class PreferencesWindow(Gtk.Dialog): txt1 = Gtk.Label('MPD地址: ') txt2 = Gtk.Label('MPD端口: ') txt3 = Gtk.Label('音乐目录: ') - txt4 = Gtk.Label('自动扫描: ') - txt5 = Gtk.Label(' 开启时, App启动时会自动扫描音乐变化') + txt4 = Gtk.Label('更新数据库: ') + txt5 = Gtk.Label(' 重新扫描会清空播放列表并停止播放') txt6 = Gtk.Label('当前歌曲数: ') txt7 = Gtk.Label('0 首') input1 = Gtk.Entry(placeholder_text = '默认 127.0.0.1') input2 = Gtk.SpinButton.new_with_range(min = 1024, max = 65535, step = 1) input3 = Gtk.Entry(placeholder_text = '默认读取 $HOME/.mpd/mpd.conf 中定义的目录') - switch = Gtk.Switch() + btn = Gtk.Button(label = '重新扫描并重建播放列表') + btn.connect('clicked', self.scan_music) input1.set_size_request(312, -1) input1.set_text(config['host']) input2.set_value(config['port']) input3.set_text(config['music_directory']) - switch.set_active(config['auto_scan']) + grid.attach(txt1, 0, 0, 1, 1) @@ -50,8 +51,7 @@ class PreferencesWindow(Gtk.Dialog): grid.attach(txt4, 0, 3, 1, 1) box = Gtk.Box() - box.add(switch) - box.add(txt5) + box.add(btn) grid.attach(box, 2, 3, 1, 1) grid.attach(txt6, 0, 4, 1, 1) @@ -62,7 +62,7 @@ class PreferencesWindow(Gtk.Dialog): self.host_input = input1 self.port_input = input2 self.dir_input = input3 - self.switch_input = switch + self.scan_input = btn self.layout.set_border_width(32) self.layout.add(grid) @@ -78,9 +78,26 @@ class PreferencesWindow(Gtk.Dialog): mpd.connect('online', lambda o: self.get_mpd_music()) - def get_mpd_music(self): + def get_mpd_music(self, force = False): res = self.mpd.stats() - self.scan_result.set_text(f"{res.get('songs')} 首") + tips = '扫描完成... 共' if force else '' + self.scan_result.set_text(f"{tips}{res.get('songs')} 首") + + + def scan_music(self, btn): + need_resume = self.mpd.status().get('state') == 'play' + self.mpd.update() + self.mpd.stop() + self.mpd.clear() + songs = self.mpd.listall() + + for it in songs: + self.mpd.add(it['file']) + + self.get_mpd_music(True) + + if need_resume: + self.mpd.play() def show(self): @@ -100,8 +117,9 @@ class PreferencesWindow(Gtk.Dialog): data['host'] = self.host_input.get_text() data['port'] = int(self.port_input.get_value()) data['music_directory'] = self.dir_input.get_text() - data['auto_scan'] = self.switch_input.get_active() + self.app.config_data = data + with open(self.app.config_file, 'w') as f: buff = json.dumps(data) f.write(buff) diff --git a/usr/lib/sonist/sonist.py b/usr/lib/sonist/sonist.py index 59d38a5..5385801 100755 --- a/usr/lib/sonist/sonist.py +++ b/usr/lib/sonist/sonist.py @@ -48,8 +48,7 @@ class Application(Gtk.Application): self.config_data = { "host": '127.0.0.1', "port": 6600, - "music_directory": self.music_dir, - "auto_scan": True + "music_directory": self.music_dir } if os.path.isfile(self.config_file): @@ -70,9 +69,10 @@ class Application(Gtk.Application): @run_async def connect_mpd(self): - self.mpd.start() + + def do_activate(self): print('hello mpc') self.set_app_menu(None) diff --git a/usr/lib/sonist/window.py b/usr/lib/sonist/window.py index fffef44..8abf40f 100644 --- a/usr/lib/sonist/window.py +++ b/usr/lib/sonist/window.py @@ -254,32 +254,54 @@ class SonistWindow(Gtk.Window): if is_play: self.handler.reset(image_dict['handler_a']) + # song = self.mpd.currentsong() + # 更新歌曲信息 + # self.title_box.update(f"{song.get('artist')} - {song.get('title')}") else: self.handler.reset(image_dict['handler']) # 切换播放按钮状态 self.ctrl_box.toggle_play_btn(is_play) + @idle def update_playtime(self, stat = {}): self.stat = stat - times = stat['time'] or '0:0' + times = stat.get('time') or '0:0' times = times.split(':') self.timebar.update_time(int(times[0]), int(times[1])) + @idle def update_volume(self, vol = 100): self.ctrl_box.set_volume(vol) + @idle def sync_state(self, stat = None, song = None, first = False): self.ctrl_box.disabled = False self.stat = stat or self.get_mpd_stat() - state = self.stat.get('state') + # 首次启动时, 更新数据库 if first: + if self.app.config_data['auto_scan']: + self.mpd.update() + song_num = int(self.mpd.stats().get('songs')) + playlist = [it['file'] for it in self.mpd.playlistinfo()] + + # 这里只做添加, 不做删除, 重建播放列表在设置里 + if len(playlist) < song_num: + songs = self.mpd.listall() + for it in songs: + if it['file'] in playlist: + continue + self.mpd.add(it['file']) + + self.get_mpd_stat() + + self.update_play_stat(state == 'play') self.update_volume(int(self.stat.get('volume') or 100)) @@ -289,11 +311,13 @@ class SonistWindow(Gtk.Window): self.ctrl_box.toggle_mode_btn(mode = 'random') + + if state != 'stop': + song = song or self.mpd.currentsong() # 更新歌曲信息 self.title_box.update(f"{song.get('artist')} - {song.get('title')}") - self.update_playtime(self.stat) title = song['file'] title_hex = base64.b64encode(title.encode()).hex()