Skip to content

Commit

Permalink
Convert WaitWindow for plugin file saves to background task (#4189)
Browse files Browse the repository at this point in the history
* Looks nicer
 * Doesn't steal focus
 * Can avoid grabbing parent windows etc
 * Also fix some double-calling issues in auto-update tags plugin etc

 Fixes #3982
  • Loading branch information
declension committed Oct 29, 2022
1 parent 41e7aa9 commit aff89f3
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 38 deletions.
10 changes: 2 additions & 8 deletions quodlibet/ext/events/auto_update_tags_in_files.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Copyright 2019-2020 Joschua Gandert
# 2022 Nick Boultbee
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
Expand All @@ -14,8 +15,7 @@
from quodlibet.plugins.events import EventPlugin
from quodlibet.plugins.songshelpers import is_writable
from quodlibet.util import print_e
from quodlibet.util.songwrapper import SongWrapper, \
background_check_wrapper_changed
from quodlibet.util.songwrapper import SongWrapper


class UpdateStrategy(IntEnum):
Expand Down Expand Up @@ -114,7 +114,6 @@ def plugin_on_song_ended(self, song, skipped):
def _try_to_update_song(self, song_wrapper):
try:
song_wrapper._needs_write = True
self._write_tags_to_files([song_wrapper])
except Exception as e:
print_e(e)
self._error_msg(WRITE_ERROR_FMT % song_wrapper._song)
Expand Down Expand Up @@ -160,11 +159,6 @@ def _update_album(self, songs):
wrapper._needs_write = True
song_wrappers.append(wrapper)

self._write_tags_to_files(song_wrappers)

def _write_tags_to_files(self, song_wrappers):
background_check_wrapper_changed(app.library, song_wrappers)


class AutoUpdateTagsPrefs(Gtk.Box):
def __init__(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
from quodlibet.util.path import join_path_with_escaped_name_of_legal_length, \
stem_of_file_name, extension_of_file_name

from quodlibet.util.songwrapper import SongWrapper, background_check_wrapper_changed
from quodlibet.util.songwrapper import SongWrapper, check_wrapper_changed

from quodlibet import _, app, print_e, print_d, qltk

Expand Down Expand Up @@ -454,7 +454,7 @@ def import_data(self, export_album_id: AlbumId, songs: List[SongWrapper]):
export_path = self._album_id_to_export_path[export_album_id]
changed_songs = self.import_data_and_get_changed(songs, export_path)
if changed_songs:
background_check_wrapper_changed(app.library, changed_songs)
check_wrapper_changed(app.library, changed_songs)

# Remove used up export
del self._album_id_to_export_path[export_album_id]
Expand All @@ -466,7 +466,7 @@ def import_data(self, export_album_id: AlbumId, songs: List[SongWrapper]):
else:
move_export_to_used(export_path)

def import_data_and_get_changed(self, songs: List[SongWrapper], #
def import_data_and_get_changed(self, songs: List[SongWrapper],
source_path: Path) -> List[SongWrapper]:
""":return: List of changed songs"""

Expand Down
3 changes: 1 addition & 2 deletions quodlibet/plugins/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,11 @@ def overridden(obj, name):
errorhook()

if event not in ["removed", "changed"] and args:
from quodlibet import app
songs = args[0]
if not isinstance(songs, (set, list)):
songs = [songs]
songs = filter(None, songs)
check_wrapper_changed(librarian, app.window, songs)
check_wrapper_changed(librarian, songs)

def plugin_handle(self, plugin):
return issubclass(plugin.cls, EventPlugin)
Expand Down
2 changes: 1 addition & 1 deletion quodlibet/plugins/songsmenu.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,4 @@ def handles_albums(self):
self.plugin_album, self.plugin_albums]))

def plugin_finish(self):
check_wrapper_changed(self.__library, self.plugin_window, self.__songs)
check_wrapper_changed(self.__library, self.__songs)
2 changes: 1 addition & 1 deletion quodlibet/qltk/songsmenu.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ def __handle(self, item, plugin, library, songs, parent):
return

finally:
check_wrapper_changed(library, parent, filter(None, songs))
check_wrapper_changed(library, filter(None, songs))

def plugin_handle(self, plugin):
return issubclass(plugin.cls, SongsMenuPlugin)
Expand Down
55 changes: 32 additions & 23 deletions quodlibet/util/songwrapper.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
# Copyright 2005 Michael Urman
# 2016 Nick Boultbee
# 2016-22 Nick Boultbee
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

from quodlibet import _
from quodlibet import _, ngettext
from quodlibet.qltk.notif import Task
from quodlibet.util import copool
from quodlibet.util.dprint import print_w
from quodlibet.formats import AudioFileError
from quodlibet import util
from quodlibet import qltk
from quodlibet.qltk.wlw import WritingWindow
from quodlibet.util.misc import total_ordering, hashable


Expand Down Expand Up @@ -102,28 +103,36 @@ def wrap(song):
return [wrap(s) for s in songs]


def check_wrapper_changed(library, parent, songs):
def check_wrapper_changed(library, songs):
need_write = [s for s in songs if s._needs_write]

if need_write:
win = WritingWindow(parent, len(need_write))
win.show()
for song in need_write:
try:
song._song.write()
except AudioFileError as e:
qltk.ErrorMessage(
None, _("Unable to edit song"),
_("Saving <b>%s</b> failed. The file "
"may be read-only, corrupted, or you "
"do not have permission to edit it.") %
util.escape(song('~basename'))).run()
print_w("Couldn't save song %s (%s)" % (song("~filename"), e))

if win.step():
break
win.destroy()

total = len(need_write)

def generate():
msg = ngettext("Saving %d file", "Saving %d files", total) % total
with Task(_("Auto-Saving"), msg) as task:
yield
for i, song in enumerate(need_write):
try:
song._song.write()
raise AudioFileError()
except AudioFileError as e:
dialog = qltk.ErrorMessage(
None,
_("Unable to edit song"),
_("Saving <b>%s</b> failed. "
"The file may be read-only, corrupted, or you "
"do not have permission to edit it.") %
util.escape(song('~basename')), escape_desc=False)
dialog.run()
print_w("Couldn't save song %s (%s)" % (song("~filename"), e))
else:
task.update((i + 1) / total)
yield

# Small enough to see if there's only one or two, very small if lots
interval = max(250 // total, 5)
copool.add(generate, timeout=interval, funcid="update_wrapped_songs")
_inform_library_of_changed(library, songs)


Expand Down

0 comments on commit aff89f3

Please sign in to comment.