mirror of
https://github.com/SoongNoonien/mpdevil.git
synced 2023-08-10 21:12:44 +03:00
Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3f42f62be6 | ||
![]() |
eff74509da | ||
![]() |
f8a9aa0fc0 | ||
![]() |
03b34d1c29 | ||
![]() |
86f439c891 | ||
![]() |
d36c4beca4 | ||
![]() |
6e88ce3e57 | ||
![]() |
0acadd7103 | ||
![]() |
ed143dab55 |
@@ -17,6 +17,8 @@ Features
|
||||
- fetches lyrics from the web (based on PyLyrics)
|
||||
- MPRIS interface (based on mpDris2)
|
||||
|
||||
See: https://github.com/SoongNoonien/mpdevil/wiki/Usage
|
||||
|
||||
Building and installation
|
||||
-------------------------
|
||||
|
||||
|
412
bin/mpdevil.py
412
bin/mpdevil.py
@@ -33,13 +33,13 @@ import gettext
|
||||
import datetime
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
|
||||
#MPRIS modules
|
||||
import dbus
|
||||
import dbus.service
|
||||
from dbus.mainloop.glib import DBusGMainLoop
|
||||
import base64
|
||||
import re
|
||||
|
||||
DATADIR = '@datadir@'
|
||||
NAME = 'mpdevil'
|
||||
@@ -58,139 +58,6 @@ except locale.Error:
|
||||
gettext.textdomain(PACKAGE)
|
||||
gettext.install(PACKAGE, localedir='@datadir@/locale')
|
||||
|
||||
# MPRIS allowed metadata tags
|
||||
allowed_tags = {
|
||||
'mpris:trackid': dbus.ObjectPath,
|
||||
'mpris:length': dbus.Int64,
|
||||
'mpris:artUrl': str,
|
||||
'xesam:album': str,
|
||||
'xesam:albumArtist': list,
|
||||
'xesam:artist': list,
|
||||
'xesam:asText': str,
|
||||
'xesam:audioBPM': int,
|
||||
'xesam:comment': list,
|
||||
'xesam:composer': list,
|
||||
'xesam:contentCreated': str,
|
||||
'xesam:discNumber': int,
|
||||
'xesam:firstUsed': str,
|
||||
'xesam:genre': list,
|
||||
'xesam:lastUsed': str,
|
||||
'xesam:lyricist': str,
|
||||
'xesam:title': str,
|
||||
'xesam:trackNumber': int,
|
||||
'xesam:url': str,
|
||||
'xesam:useCount': int,
|
||||
'xesam:userRating': float,
|
||||
}
|
||||
|
||||
# python dbus bindings don't include annotations and properties
|
||||
MPRIS2_INTROSPECTION = """<node name="/org/mpris/MediaPlayer2">
|
||||
<interface name="org.freedesktop.DBus.Introspectable">
|
||||
<method name="Introspect">
|
||||
<arg direction="out" name="xml_data" type="s"/>
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="org.freedesktop.DBus.Properties">
|
||||
<method name="Get">
|
||||
<arg direction="in" name="interface_name" type="s"/>
|
||||
<arg direction="in" name="property_name" type="s"/>
|
||||
<arg direction="out" name="value" type="v"/>
|
||||
</method>
|
||||
<method name="GetAll">
|
||||
<arg direction="in" name="interface_name" type="s"/>
|
||||
<arg direction="out" name="properties" type="a{sv}"/>
|
||||
</method>
|
||||
<method name="Set">
|
||||
<arg direction="in" name="interface_name" type="s"/>
|
||||
<arg direction="in" name="property_name" type="s"/>
|
||||
<arg direction="in" name="value" type="v"/>
|
||||
</method>
|
||||
<signal name="PropertiesChanged">
|
||||
<arg name="interface_name" type="s"/>
|
||||
<arg name="changed_properties" type="a{sv}"/>
|
||||
<arg name="invalidated_properties" type="as"/>
|
||||
</signal>
|
||||
</interface>
|
||||
<interface name="org.mpris.MediaPlayer2">
|
||||
<method name="Raise"/>
|
||||
<method name="Quit"/>
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
|
||||
<property name="CanQuit" type="b" access="read"/>
|
||||
<property name="CanRaise" type="b" access="read"/>
|
||||
<property name="HasTrackList" type="b" access="read"/>
|
||||
<property name="Identity" type="s" access="read"/>
|
||||
<property name="DesktopEntry" type="s" access="read"/>
|
||||
<property name="SupportedUriSchemes" type="as" access="read"/>
|
||||
<property name="SupportedMimeTypes" type="as" access="read"/>
|
||||
</interface>
|
||||
<interface name="org.mpris.MediaPlayer2.Player">
|
||||
<method name="Next"/>
|
||||
<method name="Previous"/>
|
||||
<method name="Pause"/>
|
||||
<method name="PlayPause"/>
|
||||
<method name="Stop"/>
|
||||
<method name="Play"/>
|
||||
<method name="Seek">
|
||||
<arg direction="in" name="Offset" type="x"/>
|
||||
</method>
|
||||
<method name="SetPosition">
|
||||
<arg direction="in" name="TrackId" type="o"/>
|
||||
<arg direction="in" name="Position" type="x"/>
|
||||
</method>
|
||||
<method name="OpenUri">
|
||||
<arg direction="in" name="Uri" type="s"/>
|
||||
</method>
|
||||
<signal name="Seeked">
|
||||
<arg name="Position" type="x"/>
|
||||
</signal>
|
||||
<property name="PlaybackStatus" type="s" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="LoopStatus" type="s" access="readwrite">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="Rate" type="d" access="readwrite">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="Shuffle" type="b" access="readwrite">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="Metadata" type="a{sv}" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="Volume" type="d" access="readwrite">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
|
||||
</property>
|
||||
<property name="Position" type="x" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
|
||||
</property>
|
||||
<property name="MinimumRate" type="d" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="MaximumRate" type="d" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="CanGoNext" type="b" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="CanGoPrevious" type="b" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="CanPlay" type="b" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="CanPause" type="b" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="CanSeek" type="b" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="CanControl" type="b" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
|
||||
</property>
|
||||
</interface>
|
||||
</node>"""
|
||||
|
||||
class IntEntry(Gtk.SpinButton):
|
||||
def __init__(self, default, lower, upper, step):
|
||||
Gtk.SpinButton.__init__(self)
|
||||
@@ -230,19 +97,18 @@ class FocusFrame(Gtk.Frame):
|
||||
self.style_context.remove_provider(self.provider)
|
||||
|
||||
class Cover(object):
|
||||
regex=re.compile(r'^\.?(album|cover|folder|front).*\.(gif|jpeg|jpg|png)$', flags=re.IGNORECASE)
|
||||
def __init__(self, lib_path, song_file):
|
||||
self.lib_path=lib_path or "/"
|
||||
self.lib_path=lib_path or ""
|
||||
self.path=None
|
||||
if not song_file == None:
|
||||
head_tail=os.path.split(song_file)
|
||||
if self.lib_path[-1] == "/":
|
||||
path=(self.lib_path+head_tail[0]+"/")
|
||||
else:
|
||||
path=(self.lib_path+"/"+head_tail[0]+"/")
|
||||
if os.path.exists(path):
|
||||
filelist=[file for file in os.listdir(path) if file.endswith('.jpg') or file.endswith('.png') or file.endswith('.gif')]
|
||||
if not filelist == []:
|
||||
self.path=(path+filelist[0])
|
||||
head, tail=os.path.split(song_file)
|
||||
song_dir=os.path.join(self.lib_path, head)
|
||||
if os.path.exists(song_dir):
|
||||
for f in os.listdir(song_dir):
|
||||
if self.regex.match(f):
|
||||
self.path=os.path.join(song_dir, f)
|
||||
break
|
||||
|
||||
def get_pixbuf(self, size):
|
||||
if self.path == None:
|
||||
@@ -411,6 +277,25 @@ class Client(AutoSettingsClient):
|
||||
songs=self.find("album", album, "date", year, self.settings.get_artist_type(), artist)
|
||||
self.files_to_playlist([song['file'] for song in songs], append, force)
|
||||
|
||||
def song_to_str_dict(self, song): #converts tags with multiple values to comma separated strings
|
||||
return_song=song
|
||||
for tag, value in return_song.items():
|
||||
if type(value) == list:
|
||||
return_song[tag]=(', '.join(value))
|
||||
return return_song
|
||||
|
||||
def song_to_first_str_dict(self, song): #extracts the first value of multiple value tags
|
||||
return_song=song
|
||||
for tag, value in return_song.items():
|
||||
if type(value) == list:
|
||||
return_song[tag]=value[0]
|
||||
return return_song
|
||||
|
||||
def extend_song_for_display(self, song):
|
||||
base_song={"title": _("Unknown Title"), "track": "0", "disc": "", "artist": _("Unknown Artist"), "album": _("Unknown Album"), "duration": "0.0", "date": "", "genre": ""}
|
||||
base_song.update(song)
|
||||
return base_song
|
||||
|
||||
def on_reconnected(self, *args):
|
||||
self.try_connect_default()
|
||||
self.emitter.emit("playlist")
|
||||
@@ -423,6 +308,139 @@ class MPRISInterface(dbus.service.Object): #TODO emit Seeked if needed
|
||||
__introspect_interface = "org.freedesktop.DBus.Introspectable"
|
||||
__prop_interface = dbus.PROPERTIES_IFACE
|
||||
|
||||
# python dbus bindings don't include annotations and properties
|
||||
MPRIS2_INTROSPECTION = """<node name="/org/mpris/MediaPlayer2">
|
||||
<interface name="org.freedesktop.DBus.Introspectable">
|
||||
<method name="Introspect">
|
||||
<arg direction="out" name="xml_data" type="s"/>
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="org.freedesktop.DBus.Properties">
|
||||
<method name="Get">
|
||||
<arg direction="in" name="interface_name" type="s"/>
|
||||
<arg direction="in" name="property_name" type="s"/>
|
||||
<arg direction="out" name="value" type="v"/>
|
||||
</method>
|
||||
<method name="GetAll">
|
||||
<arg direction="in" name="interface_name" type="s"/>
|
||||
<arg direction="out" name="properties" type="a{sv}"/>
|
||||
</method>
|
||||
<method name="Set">
|
||||
<arg direction="in" name="interface_name" type="s"/>
|
||||
<arg direction="in" name="property_name" type="s"/>
|
||||
<arg direction="in" name="value" type="v"/>
|
||||
</method>
|
||||
<signal name="PropertiesChanged">
|
||||
<arg name="interface_name" type="s"/>
|
||||
<arg name="changed_properties" type="a{sv}"/>
|
||||
<arg name="invalidated_properties" type="as"/>
|
||||
</signal>
|
||||
</interface>
|
||||
<interface name="org.mpris.MediaPlayer2">
|
||||
<method name="Raise"/>
|
||||
<method name="Quit"/>
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
|
||||
<property name="CanQuit" type="b" access="read"/>
|
||||
<property name="CanRaise" type="b" access="read"/>
|
||||
<property name="HasTrackList" type="b" access="read"/>
|
||||
<property name="Identity" type="s" access="read"/>
|
||||
<property name="DesktopEntry" type="s" access="read"/>
|
||||
<property name="SupportedUriSchemes" type="as" access="read"/>
|
||||
<property name="SupportedMimeTypes" type="as" access="read"/>
|
||||
</interface>
|
||||
<interface name="org.mpris.MediaPlayer2.Player">
|
||||
<method name="Next"/>
|
||||
<method name="Previous"/>
|
||||
<method name="Pause"/>
|
||||
<method name="PlayPause"/>
|
||||
<method name="Stop"/>
|
||||
<method name="Play"/>
|
||||
<method name="Seek">
|
||||
<arg direction="in" name="Offset" type="x"/>
|
||||
</method>
|
||||
<method name="SetPosition">
|
||||
<arg direction="in" name="TrackId" type="o"/>
|
||||
<arg direction="in" name="Position" type="x"/>
|
||||
</method>
|
||||
<method name="OpenUri">
|
||||
<arg direction="in" name="Uri" type="s"/>
|
||||
</method>
|
||||
<signal name="Seeked">
|
||||
<arg name="Position" type="x"/>
|
||||
</signal>
|
||||
<property name="PlaybackStatus" type="s" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="LoopStatus" type="s" access="readwrite">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="Rate" type="d" access="readwrite">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="Shuffle" type="b" access="readwrite">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="Metadata" type="a{sv}" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="Volume" type="d" access="readwrite">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
|
||||
</property>
|
||||
<property name="Position" type="x" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
|
||||
</property>
|
||||
<property name="MinimumRate" type="d" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="MaximumRate" type="d" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="CanGoNext" type="b" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="CanGoPrevious" type="b" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="CanPlay" type="b" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="CanPause" type="b" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="CanSeek" type="b" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
|
||||
</property>
|
||||
<property name="CanControl" type="b" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
|
||||
</property>
|
||||
</interface>
|
||||
</node>"""
|
||||
|
||||
# MPRIS allowed metadata tags
|
||||
allowed_tags = {
|
||||
'mpris:trackid': dbus.ObjectPath,
|
||||
'mpris:length': dbus.Int64,
|
||||
'mpris:artUrl': str,
|
||||
'xesam:album': str,
|
||||
'xesam:albumArtist': list,
|
||||
'xesam:artist': list,
|
||||
'xesam:asText': str,
|
||||
'xesam:audioBPM': int,
|
||||
'xesam:comment': list,
|
||||
'xesam:composer': list,
|
||||
'xesam:contentCreated': str,
|
||||
'xesam:discNumber': int,
|
||||
'xesam:firstUsed': str,
|
||||
'xesam:genre': list,
|
||||
'xesam:lastUsed': str,
|
||||
'xesam:lyricist': str,
|
||||
'xesam:title': str,
|
||||
'xesam:trackNumber': int,
|
||||
'xesam:url': str,
|
||||
'xesam:useCount': int,
|
||||
'xesam:userRating': float,
|
||||
}
|
||||
|
||||
def __init__(self, window, client, settings):
|
||||
dbus.service.Object.__init__(self, dbus.SessionBus(), "/org/mpris/MediaPlayer2")
|
||||
self._name = "org.mpris.MediaPlayer2.mpdevil"
|
||||
@@ -539,7 +557,7 @@ class MPRISInterface(dbus.service.Object): #TODO emit Seeked if needed
|
||||
# Cast self.metadata to the correct type, or discard it
|
||||
for key, value in self.metadata.items():
|
||||
try:
|
||||
self.metadata[key] = allowed_tags[key](value)
|
||||
self.metadata[key] = self.allowed_tags[key](value)
|
||||
except ValueError:
|
||||
del self.metadata[key]
|
||||
|
||||
@@ -663,7 +681,7 @@ class MPRISInterface(dbus.service.Object): #TODO emit Seeked if needed
|
||||
|
||||
@dbus.service.method(__introspect_interface)
|
||||
def Introspect(self):
|
||||
return MPRIS2_INTROSPECTION
|
||||
return self.MPRIS2_INTROSPECTION
|
||||
|
||||
@dbus.service.signal(__prop_interface, signature="sa{sv}as")
|
||||
def PropertiesChanged(self, interface, changed_properties, invalidated_properties):
|
||||
@@ -920,29 +938,11 @@ class SongsView(Gtk.ScrolledWindow):
|
||||
self.treeview.handler_unblock(self.key_press_event)
|
||||
|
||||
def populate(self, songs):
|
||||
for song in songs:
|
||||
try:
|
||||
title=song["title"]
|
||||
except:
|
||||
title=_("Unknown Title")
|
||||
try:
|
||||
track=song["track"]
|
||||
except:
|
||||
track="0"
|
||||
try:
|
||||
artist=song["artist"]
|
||||
except:
|
||||
artist=_("Unknown Artist")
|
||||
try:
|
||||
album=song["album"]
|
||||
except:
|
||||
album=_("Unknown Album")
|
||||
try:
|
||||
dura=float(song["duration"])
|
||||
except:
|
||||
dura=0.0
|
||||
for s in songs:
|
||||
song=self.client.extend_song_for_display(self.client.song_to_str_dict(s))
|
||||
dura=float(song["duration"])
|
||||
duration=str(datetime.timedelta(seconds=int(dura)))
|
||||
self.store.append([track, title, artist, album, duration, song["file"]])
|
||||
self.store.append([song["track"], song["title"], song["artist"], song["album"], duration, song["file"]])
|
||||
|
||||
def clear(self):
|
||||
self.store.clear()
|
||||
@@ -1253,8 +1253,7 @@ class AlbumIconView(Gtk.IconView):
|
||||
GLib.idle_add(self.emit, "done")
|
||||
|
||||
def scroll_to_selected_album(self):
|
||||
songid=self.client.status()["songid"]
|
||||
song=self.client.playlistid(songid)[0]
|
||||
song=self.client.song_to_first_str_dict(self.client.currentsong())
|
||||
self.unselect_all()
|
||||
row_num=len(self.store)
|
||||
for i in range(0, row_num):
|
||||
@@ -1429,7 +1428,7 @@ class MainCover(Gtk.Frame):
|
||||
|
||||
def on_button_press_event(self, widget, event):
|
||||
if self.client.connected():
|
||||
song=self.client.currentsong()
|
||||
song=self.client.song_to_first_str_dict(self.client.currentsong())
|
||||
if not song == {}:
|
||||
try:
|
||||
artist=song[self.settings.get_artist_type()]
|
||||
@@ -1467,7 +1466,6 @@ class PlaylistView(Gtk.Box):
|
||||
self.client=client
|
||||
self.settings=settings
|
||||
self.playlist_version=None
|
||||
self.last_song_path=None
|
||||
|
||||
#Store
|
||||
#(track, disc, title, artist, album, duration, date, genre, file, weight)
|
||||
@@ -1598,22 +1596,15 @@ class PlaylistView(Gtk.Box):
|
||||
|
||||
def refresh_selection(self): #Gtk.TreePath(len(self.store) is used to generate an invalid TreePath (needed to unset cursor)
|
||||
self.treeview.set_cursor(Gtk.TreePath(len(self.store)), None, False)
|
||||
for row in self.store: #reset bold text
|
||||
row[9]=Pango.Weight.BOOK
|
||||
try:
|
||||
song=self.client.status()["song"]
|
||||
path = Gtk.TreePath(int(song))
|
||||
self.selection.select_path(path)
|
||||
if self.last_song_path != None:
|
||||
try:
|
||||
self.store[self.last_song_path][9]=Pango.Weight.BOOK
|
||||
except:
|
||||
pass
|
||||
self.store[path][9]=Pango.Weight.BOLD
|
||||
self.last_song_path=path
|
||||
self.scroll_to_selected_title()
|
||||
except:
|
||||
if self.last_song_path != None:
|
||||
self.store[self.last_song_path][9]=Pango.Weight.BOOK
|
||||
self.last_song_path=None
|
||||
self.selection.unselect_all()
|
||||
|
||||
def clear(self, *args):
|
||||
@@ -1657,45 +1648,15 @@ class PlaylistView(Gtk.Box):
|
||||
songs=self.client.playlistinfo()
|
||||
if not songs == []:
|
||||
self.playlist_info.set_text("")
|
||||
for song in songs:
|
||||
try:
|
||||
title=song["title"]
|
||||
except:
|
||||
title=_("Unknown Title")
|
||||
try:
|
||||
track=song["track"]
|
||||
except:
|
||||
track="0"
|
||||
try:
|
||||
disc=song["disc"]
|
||||
except:
|
||||
disc=""
|
||||
try:
|
||||
artist=song["artist"]
|
||||
except:
|
||||
artist=_("Unknown Artist")
|
||||
try:
|
||||
album=song["album"]
|
||||
except:
|
||||
album=_("Unknown Album")
|
||||
try:
|
||||
dura=float(song["duration"])
|
||||
except:
|
||||
dura=0.0
|
||||
try:
|
||||
year=song["date"]
|
||||
except:
|
||||
year=""
|
||||
try:
|
||||
genre=song["genre"]
|
||||
except:
|
||||
genre=""
|
||||
for s in songs:
|
||||
song=self.client.extend_song_for_display(self.client.song_to_str_dict(s))
|
||||
dura=float(song["duration"])
|
||||
duration=str(datetime.timedelta(seconds=int(dura )))
|
||||
try:
|
||||
treeiter=self.store.get_iter(song["pos"])
|
||||
self.store.set(treeiter, 0, track, 1, disc, 2, title, 3, artist, 4, album, 5, duration, 6, year, 7, genre, 8, song["file"], 9, Pango.Weight.BOOK)
|
||||
self.store.set(treeiter, 0, song["track"], 1, song["disc"], 2, song["title"], 3, song["artist"], 4, song["album"], 5, duration, 6, song["date"], 7, song["genre"], 8, song["file"], 9, Pango.Weight.BOOK)
|
||||
except:
|
||||
self.store.append([track, disc, title, artist, album, duration, year, genre, song["file"], Pango.Weight.BOOK])
|
||||
self.store.append([song["track"], song["disc"], song["title"], song["artist"], song["album"], duration, song["date"], song["genre"], song["file"], Pango.Weight.BOOK])
|
||||
for i in reversed(range(int(self.client.status()["playlistlength"]), len(self.store))):
|
||||
treeiter=self.store.get_iter(i)
|
||||
self.store.remove(treeiter)
|
||||
@@ -1791,7 +1752,7 @@ class Browser(Gtk.Box):
|
||||
|
||||
def back_to_album(self, *args):
|
||||
try: #since this can still be running when the connection is lost, various exceptions can occur
|
||||
song=self.client.currentsong()
|
||||
song=self.client.song_to_first_str_dict(self.client.currentsong())
|
||||
try:
|
||||
artist=song[self.settings.get_artist_type()]
|
||||
except:
|
||||
@@ -1803,7 +1764,7 @@ class Browser(Gtk.Box):
|
||||
if not song['genre'] == self.genre_select.get_value():
|
||||
self.genre_select.deactivate() #deactivate genre filter to show all artists
|
||||
except:
|
||||
pass
|
||||
self.genre_select.deactivate() #deactivate genre filter to show all artists
|
||||
if len(self.artist_view.get_selected_artists()) <= 1:
|
||||
row_num=len(self.artist_view.store)
|
||||
for i in range(0, row_num):
|
||||
@@ -2708,13 +2669,12 @@ class AudioType(Gtk.Button):
|
||||
def on_clicked(self, *args):
|
||||
try:
|
||||
self.store.clear()
|
||||
song=self.client.status()["song"]
|
||||
tags=self.client.playlistinfo(song)[0]
|
||||
for key in tags:
|
||||
if key == "time":
|
||||
self.store.append([key, str(datetime.timedelta(seconds=int(tags[key])))])
|
||||
song=self.client.song_to_str_dict(self.client.currentsong())
|
||||
for tag, value in song.items():
|
||||
if tag == "time":
|
||||
self.store.append([tag, str(datetime.timedelta(seconds=int(value)))])
|
||||
else:
|
||||
self.store.append([key, tags[key]])
|
||||
self.store.append([tag, value])
|
||||
self.popover.show_all()
|
||||
self.treeview.queue_resize()
|
||||
except:
|
||||
@@ -2872,7 +2832,7 @@ class LyricsWindow(Gtk.Window):
|
||||
GLib.idle_add(self.label.set_text, text)
|
||||
|
||||
def refresh(self, *args):
|
||||
update_thread=threading.Thread(target=self.display_lyrics, kwargs={"current_song": self.client.currentsong()}, daemon=True)
|
||||
update_thread=threading.Thread(target=self.display_lyrics, kwargs={"current_song": self.client.song_to_first_str_dict(self.client.currentsong())}, daemon=True)
|
||||
update_thread.start()
|
||||
|
||||
def getLyrics(self, singer, song): #partially copied from PyLyrics 1.1.0
|
||||
@@ -2995,7 +2955,7 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
|
||||
def on_file_changed(self, *args):
|
||||
try:
|
||||
song=self.client.currentsong()
|
||||
song=self.client.song_to_str_dict(self.client.currentsong())
|
||||
self.set_title(song["artist"]+" - "+song["title"]+" - "+song["album"])
|
||||
if self.settings.get_boolean("send-notify"):
|
||||
if not self.is_active() and self.client.status()["state"] == "play":
|
||||
|
@@ -1,7 +1,7 @@
|
||||
dnl -*- Mode: autoconf -*-
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
AC_PREREQ([2.68])
|
||||
AC_INIT([mpdevil], [0.8.0])
|
||||
AC_INIT([mpdevil], [0.8.1])
|
||||
AC_CONFIG_SRCDIR([bin/mpdevil.py])
|
||||
AM_INIT_AUTOMAKE
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
Reference in New Issue
Block a user