Skip to content

Instantly share code, notes, and snippets.

@Tamriel
Last active December 2, 2016 13:00
Show Gist options
  • Save Tamriel/204ee6e3fe84e7450d2a71d6127f34eb to your computer and use it in GitHub Desktop.
Save Tamriel/204ee6e3fe84e7450d2a71d6127f34eb to your computer and use it in GitHub Desktop.
Quod Libet Plugin to sync saved searches to a device
import os
import cPickle
from gi.repository import Gtk
from quodlibet import get_user_dir
from quodlibet import qltk
from quodlibet.plugins.events import EventPlugin
from quodlibet.qltk.ccb import ConfigCheckButton
from quodlibet.query import Query
from quodlibet.plugins import PluginConfigMixin
from quodlibet import config
from pydub import AudioSegment
class SyncToDevice(EventPlugin, PluginConfigMixin):
PLUGIN_ID = "sync_to_device"
PLUGIN_NAME = ("Sync to device")
PLUGIN_DESC = (
'Converts all songs from the selected saved searches to 192 kbs and synchronizes them to the specified path '
"(all songs at that path which are not in the saved searches will be deleted). "
"Needs the python package 'pydub'.")
c_path = __name__ + '_path'
@classmethod
def PluginPreferences(self, parent):
vbox = Gtk.VBox(spacing=6)
queries = {}
query_path = os.path.join(get_user_dir(), 'lists', 'queries.saved')
with open(query_path, 'rU') as query_file:
for query_string in query_file:
name = next(query_file).strip()
queries[name] = Query(query_string.strip())
for query_name, query in queries.iteritems():
check_button = ConfigCheckButton((query_name), "plugins", self._config_key(query_name))
check_button.set_active(self.config_get_bool(query_name))
vbox.pack_start(check_button, False, True, 0)
def start(button):
enabled_queries = []
for query_name, query in queries.iteritems():
if self.config_get_bool(query_name):
enabled_queries.append(query)
selected_songs = []
songs_path = os.path.join(get_user_dir(), 'songs')
with open(songs_path, 'rb') as songs_file:
songs = cPickle.load(songs_file)
for song in songs:
if any(query.search(song) for query in enabled_queries):
selected_songs.append(song)
filename_list = []
destination_path = config.get('plugins', self.c_path)
for song in selected_songs:
song_path = song['~filename']
song_file_name = song("artist") + song("album") + song("title")
song_file_name = "".join(c for c in song_file_name if c.isalnum()) + ".mp3" # colons don't work on FAT
filename_list.append(song_file_name)
destination_file = destination_path + song_file_name
# skip existing files
if not os.path.exists(destination_file):
sound = AudioSegment.from_file(song_path)
sound.export(destination_file, format="mp3", bitrate="192k", tags=song)
# delete files which are not in the saved searches anymore
for existing_file_name in os.listdir(destination_path):
if existing_file_name not in filename_list:
os.remove(destination_path + existing_file_name)
message = qltk.Message(Gtk.MessageType.WARNING, None, "", "Synchronization finished.")
message.run()
def path_changed(entry):
self.path = entry.get_text()
config.set('plugins', self.c_path, self.path)
try:
self.pattern = config.get('plugins', self.c_path)
except:
self.pattern = ''
config.set('plugins', self.c_path, self.pattern)
destination_path_box = Gtk.HBox(spacing=3)
destination_path = Gtk.Entry()
destination_path.set_text(self.pattern)
destination_path.connect('changed', path_changed)
destination_path_box.pack_start(Gtk.Label(label="Destination path:"), True, True, 0)
destination_path_box.pack_start(destination_path, True, True, 0)
start_button = Gtk.Button(label=("Start synchronization"))
start_button.connect('clicked', start)
vbox.pack_start(destination_path_box, True, True, 0)
vbox.pack_start(start_button, True, True, 0)
label = Gtk.Label(label="Quod Libet will become unresponsive. You will get a message when finished.")
vbox.pack_start(label, True, True, 0)
return qltk.Frame(("Select the saved searches to copy:"), child=vbox)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment