优化初次运行的逻辑
parent
546340207e
commit
c734e5a79b
|
@ -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` 图像处理库
|
||||||
|
|
||||||
|
|
|
@ -799,10 +799,9 @@ class MPDClient(MPDClientBase, GObject.Object):
|
||||||
self.emit('state_changed', state)
|
self.emit('state_changed', state)
|
||||||
self.current_state = state
|
self.current_state = state
|
||||||
|
|
||||||
|
|
||||||
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()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue