Compare commits
13 Commits
Author | SHA1 | Date |
---|---|---|
|
c2f7976ddc | |
|
28f2ae5033 | |
|
c8ee7d4aad | |
|
27f1ff704e | |
|
563fa8c733 | |
|
2d7fe9966a | |
|
afa39b5026 | |
|
712d321bf3 | |
|
ef701c2c43 | |
|
6b1fa4daae | |
|
4ae5a975be | |
|
6b72640e73 | |
|
272ce69d50 |
8
build.sh
8
build.sh
|
@ -4,7 +4,7 @@ if [ -d unpack ]; then
|
|||
sudo rm -rf unpack
|
||||
fi
|
||||
|
||||
version="1.0.2"
|
||||
version="1.0.5"
|
||||
|
||||
mkdir -p unpack/DEBIAN
|
||||
|
||||
|
@ -12,7 +12,11 @@ cp debian/control unpack/DEBIAN/
|
|||
cp -r usr unpack/
|
||||
|
||||
cd unpack
|
||||
find . -type f | xargs md5sum > DEBIAN/md5sums
|
||||
find usr -type f | xargs md5sum > DEBIAN/md5sums
|
||||
|
||||
_size=$(du -d 0 usr | cut -f1)
|
||||
sed -i "s/{{size}}/${_size}/" DEBIAN/control
|
||||
sed -i "s/{{version}}/${version}/" DEBIAN/control
|
||||
|
||||
cd ..
|
||||
dpkg-deb -b unpack/ "sonist-${version}.deb"
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
Package: sonist
|
||||
Version: 1.0.2
|
||||
Version: {{version}}
|
||||
Section: X11
|
||||
Architecture: all
|
||||
Author: Yutent
|
||||
Maintainer: Yutent <yutent.io@gmail.com>
|
||||
Depends: python3-gi, gir1.2-gtk-3.0, python3-pil, python3-cairo, python3-mutagen, mpd
|
||||
Depends: python3-gi, gir1.2-gtk-3.0, python3-pil, python3-gi-cairo, python3-mutagen, mpd
|
||||
Priority: optional
|
||||
Installed-Size: 5644
|
||||
Homepage: https://github.com/app-cat/sonist-gtk
|
||||
Installed-Size: {{size}}
|
||||
Homepage: https://git.wkit.fun/appcat/sonist-gtk
|
||||
Description: Sonist - 基于mpd后端的音乐播放器.
|
||||
高颜值且轻量的 MPD GUI客户端.
|
||||
|
|
|
@ -21,13 +21,12 @@ class AboutWindow(Gtk.AboutDialog):
|
|||
self.set_logo(GdkPixbuf.Pixbuf.new_from_file(image_dict['sonist']))
|
||||
|
||||
self.set_license_type(Gtk.License.MIT_X11)
|
||||
self.set_version('1.0.2')
|
||||
self.set_website('https://github.com/app-cat/sonist-gtk')
|
||||
self.set_version('1.0.5')
|
||||
self.set_website('https://git.wkit.fun/appcat/sonist-gtk')
|
||||
self.set_website_label('官网')
|
||||
self.set_authors([
|
||||
'Yutent <yutent.io@gmail.com> (Sonist)',
|
||||
'Mic92 <https://github.com/Mic92/python-mpd2> (python-mpd2)',
|
||||
'quodlibet <https://github.com/quodlibet/mutagen> (python-mutagen)'
|
||||
])
|
||||
self.set_copyright('© 2023 Yutent <yutent.io@gmail.com>')
|
||||
self.set_comments('Sonist-Gtk 是一个界面美观, 基于MPD后端的音乐播放器, 使用python + gtk3开发。')
|
||||
|
|
|
@ -103,7 +103,9 @@ class Application(Gtk.Application):
|
|||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = Application()
|
||||
app.run(sys.argv)
|
||||
|
||||
try:
|
||||
app = Application()
|
||||
app.run(sys.argv)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
from .image import ScaleImage
|
||||
|
||||
from assets import image_dict
|
||||
|
||||
class DiskBox(Gtk.Fixed):
|
||||
|
||||
def __init__(self):
|
||||
Gtk.Fixed.__init__(self)
|
||||
|
||||
|
||||
disk = ScaleImage(image_dict['disk'])
|
||||
handler = ScaleImage(image_dict['handler'])
|
||||
album = ScaleImage()
|
||||
|
||||
disk.resize(192, 192)
|
||||
album.clip_resize(128).set_radius(64)
|
||||
|
||||
handler.resize(48, 96)
|
||||
self.handler = handler
|
||||
self.album = album
|
||||
|
||||
self.put(disk, 16, 16)
|
||||
self.put(album, 48, 48)
|
||||
self.put(handler, 0, 16)
|
||||
|
||||
|
||||
def update_state(self, played = False):
|
||||
if played:
|
||||
self.handler.reset(image_dict['handler_a'])
|
||||
else:
|
||||
self.handler.reset(image_dict['handler'])
|
||||
|
||||
return self
|
||||
|
||||
|
||||
def update_album(self, filepath = None):
|
||||
self.album.reset(filepath, True).set_radius(64)
|
||||
return self
|
|
@ -0,0 +1,38 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk, Gdk
|
||||
|
||||
from .image_button import ImageButton
|
||||
from .option_menu import OptionMenu
|
||||
|
||||
from assets import image_dict
|
||||
|
||||
class Topbar(Gtk.EventBox):
|
||||
|
||||
def __init__(self, app, win):
|
||||
Gtk.EventBox.__init__(self)
|
||||
|
||||
self.window = win
|
||||
|
||||
self.set_size_request(320, 26)
|
||||
|
||||
box = Gtk.Fixed()
|
||||
|
||||
menu_btn = ImageButton(image_dict['menu'])
|
||||
popup_menu = OptionMenu(app)
|
||||
menu_btn.connect('clicked', lambda btn: popup_menu.show(btn))
|
||||
box.put(menu_btn, 276, 6)
|
||||
|
||||
self.connect("button-press-event", self.on_drag)
|
||||
self.add(box)
|
||||
|
||||
|
||||
def on_drag(self, widget, event):
|
||||
if event.button == Gdk.BUTTON_PRIMARY:
|
||||
self.window.begin_move_drag(
|
||||
event.button,
|
||||
int(event.x_root),
|
||||
int(event.y_root),
|
||||
event.time)
|
|
@ -9,12 +9,13 @@ from utils import blur_image, pic_to_pixbuf, base64_to_pixbuf, idle
|
|||
|
||||
from assets import image_dict
|
||||
|
||||
from ui.topbar import Topbar
|
||||
from ui.image import ScaleImage
|
||||
from ui.image_button import ImageButton
|
||||
from ui.title_text import TitleText
|
||||
from ui.ctrl_box import CtrlBox
|
||||
from ui.timebar import Timebar
|
||||
from ui.option_menu import OptionMenu
|
||||
from ui.disk_box import DiskBox
|
||||
|
||||
|
||||
|
||||
|
@ -36,6 +37,18 @@ class SonistWindow(Gtk.Window):
|
|||
self.css_provider = None
|
||||
self.set_default_style()
|
||||
|
||||
self.set_position(Gtk.WindowPosition.CENTER)
|
||||
self.set_decorated(False) # 隐藏系统标题栏
|
||||
self.set_name('SonistWindow')
|
||||
self.set_title('Sonist')
|
||||
self.set_default_size(320, 384)
|
||||
self.set_resizable(False)
|
||||
self.set_wmclass('Sonist', 'Sonist')
|
||||
|
||||
self.set_background_image(image_dict['disk'])
|
||||
|
||||
|
||||
|
||||
self.connect("destroy", lambda win: app.remove_window(win))
|
||||
|
||||
self.mpd.connect('offline', lambda o: self.reset_player())
|
||||
|
@ -45,47 +58,20 @@ class SonistWindow(Gtk.Window):
|
|||
self.mpd.connect('volume_changed', lambda o, vol: self.update_volume(vol))
|
||||
self.mpd.connect('playing', lambda o, stat, song: self.update_playtime(stat))
|
||||
|
||||
self.set_name('SonistWindow')
|
||||
self.set_title('Sonist')
|
||||
self.set_default_size(320, 384)
|
||||
self.set_resizable(False)
|
||||
self.set_wmclass('Sonist', 'Sonist')
|
||||
|
||||
self.set_opacity(0.9)
|
||||
|
||||
self.set_background_image(image_dict['disk'])
|
||||
|
||||
layout = Gtk.Layout()
|
||||
|
||||
# 菜单按钮
|
||||
menu_btn = ImageButton(image_dict['menu'])
|
||||
popup_menu = OptionMenu(app)
|
||||
menu_btn.connect('clicked', lambda btn: popup_menu.show(btn))
|
||||
layout.put(menu_btn, 276, 6)
|
||||
# 内嵌的标题栏
|
||||
bar = Topbar(app, self)
|
||||
layout.put(bar, 0, 0)
|
||||
|
||||
# 唱片
|
||||
disk = ScaleImage(image_dict['disk'])
|
||||
handler = ScaleImage(image_dict['handler'])
|
||||
album = ScaleImage()
|
||||
|
||||
disk.resize(192, 192)
|
||||
album.clip_resize(128).set_radius(64)
|
||||
|
||||
handler.resize(48, 96)
|
||||
self.handler = handler
|
||||
self.album = album
|
||||
|
||||
box = Gtk.Fixed()
|
||||
box.put(disk, 16, 16)
|
||||
box.put(album, 48, 48)
|
||||
box.put(handler, 0, 16)
|
||||
|
||||
layout.put(box, 48, 16)
|
||||
disk = DiskBox()
|
||||
self.disk = disk
|
||||
layout.put(disk, 48, 16)
|
||||
|
||||
|
||||
# title
|
||||
self.title_box = TitleText()
|
||||
|
||||
layout.put(self.title_box, 27, 244)
|
||||
|
||||
|
||||
|
@ -151,8 +137,6 @@ class SonistWindow(Gtk.Window):
|
|||
self.style_context.add_provider_for_screen(self.screen, provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
|
||||
|
||||
|
||||
|
||||
|
||||
def get_mpd_stat(self):
|
||||
try:
|
||||
self.stat = self.mpd.status()
|
||||
|
@ -193,17 +177,14 @@ class SonistWindow(Gtk.Window):
|
|||
elif btn == 'mode_btn':
|
||||
# repeat all
|
||||
if self.ctrl_box.curr_mode == 0:
|
||||
self.mpd.repeat(1)
|
||||
self.mpd.random(0)
|
||||
self.mpd.single(0)
|
||||
# random
|
||||
elif self.ctrl_box.curr_mode == 1:
|
||||
self.mpd.repeat(0)
|
||||
self.mpd.random(1)
|
||||
self.mpd.single(0)
|
||||
# single
|
||||
else:
|
||||
self.mpd.repeat(0)
|
||||
self.mpd.random(0)
|
||||
self.mpd.single(1)
|
||||
|
||||
|
@ -250,11 +231,7 @@ class SonistWindow(Gtk.Window):
|
|||
@idle
|
||||
def update_play_stat(self, is_play = True):
|
||||
|
||||
if is_play:
|
||||
self.handler.reset(image_dict['handler_a'])
|
||||
else:
|
||||
self.handler.reset(image_dict['handler'])
|
||||
|
||||
self.disk.update_state(is_play)
|
||||
# 切换播放按钮状态
|
||||
self.ctrl_box.toggle_play_btn(is_play)
|
||||
|
||||
|
@ -282,10 +259,14 @@ class SonistWindow(Gtk.Window):
|
|||
# 首次启动时, 更新数据库
|
||||
if first:
|
||||
self.mpd.update()
|
||||
self.mpd.repeat(1)
|
||||
song_num = int(self.mpd.stats().get('songs') or 0)
|
||||
playlist = [it['file'] for it in self.mpd.playlistinfo()]
|
||||
|
||||
self.ctrl_box.disabled = song_num == 0
|
||||
|
||||
if song_num == 0:
|
||||
self.ctrl_box.disabled = True
|
||||
return
|
||||
|
||||
# 这里只做添加, 不做删除, 重建播放列表在设置里
|
||||
if song_num > 0 and len(playlist) < song_num:
|
||||
|
@ -307,43 +288,38 @@ class SonistWindow(Gtk.Window):
|
|||
self.ctrl_box.toggle_mode_btn(mode = 'random')
|
||||
|
||||
|
||||
song = song or self.mpd.currentsong()
|
||||
|
||||
if song.get('id'):
|
||||
# 更新歌曲信息
|
||||
self.title_box.update(f"{song.get('artist')} - {song.get('title')}")
|
||||
|
||||
if state != 'stop':
|
||||
title_hex = base64.b64encode(song.get('title').encode()).hex()
|
||||
|
||||
song = song or self.mpd.currentsong()
|
||||
filepath = f"{self.app.album_cache_dir}/{title_hex}.png"
|
||||
songpath = f"{self.app.music_dir}/{song.get('file')}"
|
||||
|
||||
if song.get('id'):
|
||||
# 更新歌曲信息
|
||||
self.title_box.update(f"{song.get('artist')} - {song.get('title')}")
|
||||
|
||||
title = song.get('title')
|
||||
title_hex = base64.b64encode(title.encode()).hex()
|
||||
|
||||
filepath = f"{self.app.album_cache_dir}/{title_hex}.png"
|
||||
songpath = f"{self.app.music_dir}/{title}"
|
||||
|
||||
if os.path.isfile(filepath):
|
||||
self.update_album(filepath)
|
||||
else:
|
||||
|
||||
id3 = mutagen.File(songpath)
|
||||
pic = None
|
||||
try:
|
||||
if id3.tags.get('APIC:'):
|
||||
pic = id3.tags['APIC:']
|
||||
elif len(id3.pictures) > 0:
|
||||
pic = id3.pictures[0]
|
||||
|
||||
if pic is None:
|
||||
self.update_album()
|
||||
else:
|
||||
album = pic_to_pixbuf(pic)
|
||||
self.update_album(album)
|
||||
|
||||
except Exception as err:
|
||||
pass
|
||||
if os.path.isfile(filepath):
|
||||
self.update_album(filepath)
|
||||
else:
|
||||
|
||||
id3 = mutagen.File(songpath)
|
||||
pic = None
|
||||
try:
|
||||
if id3.tags.get('APIC:'):
|
||||
pic = id3.tags['APIC:']
|
||||
elif len(id3.pictures) > 0:
|
||||
pic = id3.pictures[0]
|
||||
|
||||
if pic is None:
|
||||
self.update_album()
|
||||
else:
|
||||
album = pic_to_pixbuf(pic)
|
||||
self.update_album(album)
|
||||
|
||||
except Exception as err:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@idle
|
||||
|
@ -353,9 +329,9 @@ class SonistWindow(Gtk.Window):
|
|||
self.timebar.update_time()
|
||||
self.update_album()
|
||||
|
||||
@idle
|
||||
|
||||
def update_album(self, filepath = None):
|
||||
self.set_background_image(filepath or image_dict['disk'])
|
||||
self.album.reset(filepath, True).set_radius(64)
|
||||
self.disk.update_album(filepath)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue