优化初次运行的逻辑

master
yutent 2023-08-26 22:28:23 +08:00
parent 546340207e
commit c734e5a79b
5 changed files with 62 additions and 26 deletions

View File

@ -15,12 +15,6 @@
- [ ] 自动查找网络歌词 - [ ] 自动查找网络歌词
### 感觉以下第三方库
- [`python3-mpd2`](https://github.com/Mic92/python-mpd2), 本项目内置了修改版的`python3-mpd2`, 加入了Gtk的信号与槽机制的支持, 并更加友好的方式处理异常, 减少程序崩溃。
- [`python3-mutagen`](https://github.com/quodlibet/mutagen), 用于获取歌曲文件内嵌的封面。
### 项目依赖 ### 项目依赖
以`debian 12`为例 以`debian 12`为例
@ -28,7 +22,7 @@
- `python3-gi` gobject - `python3-gi` gobject
- `gir1.2-gtk-3.0` Gtk3 - `gir1.2-gtk-3.0` Gtk3
- `python3-mutagen` 获取歌曲标签信息的库 - `python3-mutagen` 获取歌曲标签信息的库
- `python3-mpd2` MPD连接库(已内置修改版) - `python3-mpd2` MPD连接库(已内置修改版,接入Gtk的信号与槽机制, 并优化了异常处理)
- `python3-pil` 图像处理库 - `python3-pil` 图像处理库
- `python3-gi-cairo` 图像处理库 - `python3-gi-cairo` 图像处理库

View File

@ -801,8 +801,7 @@ class MPDClient(MPDClientBase, GObject.Object):
if song.get('id') != self.current_song_id: 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') self.current_song_id = song.get('id')
@ -825,6 +824,7 @@ class MPDClient(MPDClientBase, GObject.Object):
self._try_connect() self._try_connect()
if self.connected: if self.connected:
self.emit('online') self.emit('online')
self.current_song_id = self.currentsong().get('id')
self.heart_beat() self.heart_beat()

View File

@ -23,20 +23,21 @@ class PreferencesWindow(Gtk.Dialog):
txt1 = Gtk.Label('MPD地址: ') txt1 = Gtk.Label('MPD地址: ')
txt2 = Gtk.Label('MPD端口: ') txt2 = Gtk.Label('MPD端口: ')
txt3 = Gtk.Label('音乐目录: ') txt3 = Gtk.Label('音乐目录: ')
txt4 = Gtk.Label('自动扫描: ') txt4 = Gtk.Label('更新数据库: ')
txt5 = Gtk.Label(' 开启时, App启动时会自动扫描音乐变化') txt5 = Gtk.Label(' 重新扫描会清空播放列表并停止播放')
txt6 = Gtk.Label('当前歌曲数: ') txt6 = Gtk.Label('当前歌曲数: ')
txt7 = Gtk.Label('0 首') txt7 = Gtk.Label('0 首')
input1 = Gtk.Entry(placeholder_text = '默认 127.0.0.1') input1 = Gtk.Entry(placeholder_text = '默认 127.0.0.1')
input2 = Gtk.SpinButton.new_with_range(min = 1024, max = 65535, step = 1) input2 = Gtk.SpinButton.new_with_range(min = 1024, max = 65535, step = 1)
input3 = Gtk.Entry(placeholder_text = '默认读取 $HOME/.mpd/mpd.conf 中定义的目录') 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_size_request(312, -1)
input1.set_text(config['host']) input1.set_text(config['host'])
input2.set_value(config['port']) input2.set_value(config['port'])
input3.set_text(config['music_directory']) input3.set_text(config['music_directory'])
switch.set_active(config['auto_scan'])
grid.attach(txt1, 0, 0, 1, 1) grid.attach(txt1, 0, 0, 1, 1)
@ -50,8 +51,7 @@ class PreferencesWindow(Gtk.Dialog):
grid.attach(txt4, 0, 3, 1, 1) grid.attach(txt4, 0, 3, 1, 1)
box = Gtk.Box() box = Gtk.Box()
box.add(switch) box.add(btn)
box.add(txt5)
grid.attach(box, 2, 3, 1, 1) grid.attach(box, 2, 3, 1, 1)
grid.attach(txt6, 0, 4, 1, 1) grid.attach(txt6, 0, 4, 1, 1)
@ -62,7 +62,7 @@ class PreferencesWindow(Gtk.Dialog):
self.host_input = input1 self.host_input = input1
self.port_input = input2 self.port_input = input2
self.dir_input = input3 self.dir_input = input3
self.switch_input = switch self.scan_input = btn
self.layout.set_border_width(32) self.layout.set_border_width(32)
self.layout.add(grid) self.layout.add(grid)
@ -78,9 +78,26 @@ class PreferencesWindow(Gtk.Dialog):
mpd.connect('online', lambda o: self.get_mpd_music()) 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() 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): def show(self):
@ -100,8 +117,9 @@ class PreferencesWindow(Gtk.Dialog):
data['host'] = self.host_input.get_text() data['host'] = self.host_input.get_text()
data['port'] = int(self.port_input.get_value()) data['port'] = int(self.port_input.get_value())
data['music_directory'] = self.dir_input.get_text() data['music_directory'] = self.dir_input.get_text()
data['auto_scan'] = self.switch_input.get_active()
self.app.config_data = data self.app.config_data = data
with open(self.app.config_file, 'w') as f: with open(self.app.config_file, 'w') as f:
buff = json.dumps(data) buff = json.dumps(data)
f.write(buff) f.write(buff)

View File

@ -48,8 +48,7 @@ class Application(Gtk.Application):
self.config_data = { self.config_data = {
"host": '127.0.0.1', "host": '127.0.0.1',
"port": 6600, "port": 6600,
"music_directory": self.music_dir, "music_directory": self.music_dir
"auto_scan": True
} }
if os.path.isfile(self.config_file): if os.path.isfile(self.config_file):
@ -70,9 +69,10 @@ class Application(Gtk.Application):
@run_async @run_async
def connect_mpd(self): def connect_mpd(self):
self.mpd.start() self.mpd.start()
def do_activate(self): def do_activate(self):
print('hello mpc') print('hello mpc')
self.set_app_menu(None) self.set_app_menu(None)

View File

@ -254,32 +254,54 @@ class SonistWindow(Gtk.Window):
if is_play: if is_play:
self.handler.reset(image_dict['handler_a']) self.handler.reset(image_dict['handler_a'])
# song = self.mpd.currentsong()
# 更新歌曲信息
# self.title_box.update(f"{song.get('artist')} - {song.get('title')}")
else: else:
self.handler.reset(image_dict['handler']) self.handler.reset(image_dict['handler'])
# 切换播放按钮状态 # 切换播放按钮状态
self.ctrl_box.toggle_play_btn(is_play) self.ctrl_box.toggle_play_btn(is_play)
@idle @idle
def update_playtime(self, stat = {}): def update_playtime(self, stat = {}):
self.stat = stat self.stat = stat
times = stat['time'] or '0:0' times = stat.get('time') or '0:0'
times = times.split(':') times = times.split(':')
self.timebar.update_time(int(times[0]), int(times[1])) self.timebar.update_time(int(times[0]), int(times[1]))
@idle @idle
def update_volume(self, vol = 100): def update_volume(self, vol = 100):
self.ctrl_box.set_volume(vol) self.ctrl_box.set_volume(vol)
@idle @idle
def sync_state(self, stat = None, song = None, first = False): def sync_state(self, stat = None, song = None, first = False):
self.ctrl_box.disabled = False self.ctrl_box.disabled = False
self.stat = stat or self.get_mpd_stat() self.stat = stat or self.get_mpd_stat()
state = self.stat.get('state') state = self.stat.get('state')
# 首次启动时, 更新数据库
if first: 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_play_stat(state == 'play')
self.update_volume(int(self.stat.get('volume') or 100)) 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') self.ctrl_box.toggle_mode_btn(mode = 'random')
if state != 'stop': if state != 'stop':
song = song or self.mpd.currentsong() song = song or self.mpd.currentsong()
# 更新歌曲信息 # 更新歌曲信息
self.title_box.update(f"{song.get('artist')} - {song.get('title')}") self.title_box.update(f"{song.get('artist')} - {song.get('title')}")
self.update_playtime(self.stat)
title = song['file'] title = song['file']
title_hex = base64.b64encode(title.encode()).hex() title_hex = base64.b64encode(title.encode()).hex()