~comcloudway/melon

7cdf6ca765ab32a84c319f4c40cf132521dd0d3b — Jakob Meier 6 months ago 015cc73
fetch video data on separate thread when creating/picking playlists
4 files changed, 91 insertions(+), 39 deletions(-)

M melon/playlist/create.py
M melon/playlist/pick.py
M melon/widgets/feeditem.py
M melon/window.py
M melon/playlist/create.py => melon/playlist/create.py +34 -4
@@ 4,17 4,16 @@ gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
from gi.repository import Gtk, Adw, Gio, GLib
from gettext import gettext as _
import threading

from melon.widgets.iconbutton import IconButton
from melon.widgets.simpledialog import SimpleDialog
from melon.widgets.feeditem import AdaptiveFeedItem
from melon.models import new_local_playlist
from melon.models import new_local_playlist, Video
from melon.servers.utils import get_app_settings

class PlaylistCreatorDialog(SimpleDialog):
    def __init__(self, video=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.set_title(_("New Playlist"))
    def display(self, video=None):
        page = Adw.PreferencesPage()
        self.content = []
        if not video is None:


@@ 73,6 72,37 @@ class PlaylistCreatorDialog(SimpleDialog):
        self.toolbar_view.add_bottom_bar(bottom_bar)

        self.set_widget(page)
    def background(self, target=None):
        video = None
        if isinstance(target, Video):
            # target is already a video object
            video = target
        elif not target is None:
            # we have to fetch the video ourselves
            server_id = target[0]
            video_id = target[1]
            servers = get_servers_list()
            if server_id in servers:
                instance = get_server_instance(servers[server_id])
                video = instance.get_video_info(video_id)
        GLib.idle_add(self.display, video)
    def __init__(self, video=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.set_title(_("New Playlist"))

        # show spinner
        # will be cleared by display
        spinner = Gtk.Spinner()
        spinner.set_size_request(50, 50)
        spinner.start()
        cb = Gtk.CenterBox()
        cb.set_center_widget(spinner)
        self.set_widget(cb)

        # start background thread
        self.thread = threading.Thread(target=self.background, args=[video])
        self.thread.daemon = True
        self.thread.start()

    def create_playlist(self, x):
        new_local_playlist(

M melon/playlist/pick.py => melon/playlist/pick.py +45 -24
@@ 5,12 5,13 @@ gi.require_version('Adw', '1')
from gi.repository import Gtk, Adw, Gio, GLib, Gdk
from unidecode import unidecode
from gettext import gettext as _
import threading

from melon.widgets.feeditem import AdaptiveFeedItem
from melon.widgets.feeditem import AdaptiveFeedItem, AdaptivePlaylistFeedItem
from melon.widgets.iconbutton import IconButton
from melon.widgets.simpledialog import SimpleDialog
from melon.models import get_playlists, PlaylistWrapperType, add_to_local_playlist
from melon.servers.utils import get_app_settings, pixbuf_from_url
from melon.servers.utils import get_app_settings, pixbuf_from_url, get_servers_list, get_server_instance
from melon.playlist.create import PlaylistCreatorDialog

class PlaylistPickerDialog(SimpleDialog):


@@ 18,9 19,8 @@ class PlaylistPickerDialog(SimpleDialog):
        diag = PlaylistCreatorDialog(video)
        self.hide()
        diag.show()
    def __init__(self, video, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.set_title(_("Add to Playlist"))

    def display(self, video):
        page = Adw.PreferencesPage()

        # use preference group as preview for video element


@@ 58,25 58,9 @@ class PlaylistPickerDialog(SimpleDialog):
        for playlist in get_playlists():
            if playlist.type == PlaylistWrapperType.EXTERNAL:
                continue
            row = Adw.ActionRow()
            row.set_title(unidecode(playlist.inner.title).replace("&","&"))
            row.set_subtitle(unidecode(playlist.inner.description).replace("&","&"))
            pixbuf = None
            if app_conf["show_images_in_feed"]:
                pixbuf = pixbuf_from_url(playlist.inner.thumbnail)
            avatar = Adw.Avatar()
            avatar.set_size(48)
            if not pixbuf is None:
                texture = Gdk.Texture.new_for_pixbuf(pixbuf)
                avatar.set_custom_image(texture)
            else:
                avatar.set_show_initials(True)
                avatar.set_text(playlist.inner.title)
            row.add_prefix(avatar)
            row.set_activatable(True)
            row.connect(
                "activated",
                pass_me(
            row = AdaptivePlaylistFeedItem(
                playlist,
                onClick=pass_me(
                    lambda _, playlist, video: add_to_local_playlist(playlist.inner.id, video) or self.hide(),
                    playlist, video)
            )


@@ 98,5 82,42 @@ class PlaylistPickerDialog(SimpleDialog):
        self.toolbar_view.add_bottom_bar(bottom_bar)

        self.set_widget(page)

    def background(self, target=None):
        video = None

        if not target is None:
            server_id = target[0]
            video_id = target[1]
            servers = get_servers_list()
            if server_id in servers:
                instance = get_server_instance(servers[server_id])
                video = instance.get_video_info(video_id)

        if not video is None:
            GLib.idle_add(self.display, video)

    def __init__(self, video, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.set_title(_("Add to Playlist"))

        # should never happen but still
        if video is None:
            self.hide()

        # show spinner
        # will be cleared by display
        spinner = Gtk.Spinner()
        spinner.set_size_request(50, 50)
        spinner.start()
        cb = Gtk.CenterBox()
        cb.set_center_widget(spinner)
        self.set_widget(cb)

        # start background thread
        self.thread = threading.Thread(target=self.background, args=[video])
        self.thread.daemon = True
        self.thread.start()

def pass_me(func, *args):
    return lambda x: func(x, *args)

M melon/widgets/feeditem.py => melon/widgets/feeditem.py +8 -2
@@ 81,11 81,17 @@ class AdaptiveFeedItem(Adw.ActionRow):


class AdaptivePlaylistFeedItem(Adw.ActionRow):
    def __init__(self, playlist:PlaylistWrapper, show_preview=True, *args, **kwargs):
    def __init__(self, playlist:PlaylistWrapper, show_preview=True, onClick=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.set_title(unidecode(playlist.inner.title).replace("&","&"))
        self.set_subtitle(unidecode(playlist.inner.description).replace("&","&"))
        if playlist.type == PlaylistWrapperType.EXTERNAL:
        if not onClick is None:
            # use custom click callback
            self.connect(
                "activated",
                onClick
            )
        elif playlist.type == PlaylistWrapperType.EXTERNAL:
            self.set_action_name("win.browse_playlist")
            self.set_action_target_value(
                GLib.Variant("as", [playlist.inner.server, playlist.inner.id]))

M melon/window.py => melon/window.py +4 -9
@@ 48,11 48,9 @@ class MainWindow(Adw.ApplicationWindow):
        server_id = prefs[0]
        video_id = prefs[1]
        servers = get_servers_list()
        if server_id in servers:
            instance = get_server_instance(servers[server_id])
            video = instance.get_video_info(video_id)
            diag = PlaylistPickerDialog(video)
            diag.show()
        video = (server_id, video_id)
        diag = PlaylistPickerDialog(video)
        diag.show()
    def open_playlist_creator(self, action, prefs):
        act = action.get_name()
        # video to be automatically added (if available)


@@ 61,10 59,7 @@ class MainWindow(Adw.ApplicationWindow):
            # open new playlist dialog & add video to said playlist
            server_id = prefs[0]
            video_id = prefs[1]
            servers = get_servers_list()
            if server_id in servers:
                instance = get_server_instance(servers[server_id])
                video = instance.get_video_info(video_id)
            video = (server_id, video_id)
        # create basic dialog
        diag = PlaylistCreatorDialog(video)
        diag.show()