M melon/browse/playlist.py => melon/browse/playlist.py +9 -3
@@ 31,6 31,15 @@ class BrowsePlaylistScreen(Adw.NavigationPage):
self.thread.start()
def display_info(self, texture):
+ self.external_btn = IconButton("","modem-symbolic")
+ self.external_btn.connect("clicked", self.on_open_in_browser)
+ self.header_bar.pack_end(self.external_btn)
+ self.startplay_btn = IconButton("","media-playback-start-symbolic", tooltip=_("Start playing"))
+ self.startplay_btn.set_action_name("win.playlistplayer-external")
+ self.startplay_btn.set_action_target_value(
+ GLib.Variant("as", [self.playlist.server, self.playlist.id]))
+ self.header_bar.pack_end(self.startplay_btn)
+
# base layout
self.box = Adw.PreferencesPage()
self.about = Adw.PreferencesGroup()
@@ 102,9 111,6 @@ class BrowsePlaylistScreen(Adw.NavigationPage):
self.set_title(_("Playlist"))
self.header_bar = Adw.HeaderBar()
- self.external_btn = IconButton("","modem-symbolic")
- self.external_btn.connect("clicked", self.on_open_in_browser)
- self.header_bar.pack_end(self.external_btn)
self.toolbar_view = Adw.ToolbarView()
self.toolbar_view.add_top_bar(self.header_bar)
M melon/models/__init__.py => melon/models/__init__.py +10 -0
@@ 747,6 747,16 @@ def set_video_playback_position(vid: Video, position: float, duration: float):
conn.close()
notify("playback_changed")
+def set_video_playback_position_force(server_id: str, video_id:str, position: float, duration: float):
+ uts = datetime.now().timestamp()
+ conn = connect_to_db()
+ execute_sql(conn, """
+ INSERT OR REPLACE INTO playback
+ VALUES (?,?,?,?,?)
+ """, (uts, server_id, video_id, duration, position))
+ conn.close()
+ notify("playback_changed")
+
def get_last_playback() -> (tuple[Video, float, float] | None):
conn = connect_to_db()
results = conn.execute("""
M melon/player/__init__.py => melon/player/__init__.py +90 -27
@@ 15,22 15,19 @@ from melon.widgets.feeditem import AdaptiveFeedItem
from melon.widgets.preferencerow import PreferenceRow, PreferenceType, Preference
from melon.widgets.iconbutton import IconButton
from melon.models import get_app_settings, add_to_history, register_callback
-from melon.models import get_video_playback_position, set_video_playback_position
+from melon.models import get_video_playback_position, set_video_playback_position, set_video_playback_position_force
from melon.utils import pass_me
class PlayerScreen(Adw.NavigationPage):
def on_open_in_browser(self, arg):
Gtk.UriLauncher.new(uri=self.video.url).launch()
- quality_select = None
def display_info(self):
self.set_title(self.video.title)
self.scrollview.set_child(self.box)
# video details
self.about = Adw.PreferencesGroup()
self.about.set_title(unidecode(self.video.title).replace("&","&"))
- if not self.quality_select is None:
- self.about.add(self.quality_select)
# expandable description field
desc_field = Adw.ExpanderRow()
@@ 54,34 51,60 @@ class PlayerScreen(Adw.NavigationPage):
self.about.add(btn_bookmark)
def display_player(self):
- player = VideoPlayer(self.streams)
+ self.position = 0
+ self.duration = 0
+ self.player = VideoPlayer(self.streams)
pos = get_video_playback_position(self.video.server, self.video.id)
if not pos is None:
- player.goto(pos)
- player.connect_update(self.on_player_data)
+ self.position = pos
+ self.player.goto(pos)
+ self.player.connect_update(self.on_player_data)
+ self.player.connect_ended(self.on_player_end)
# do not autoplay
- player.pause()
- self.box.append(player)
+ self.player.pause()
+ self.box.append(self.player)
# TODO: stop + kill player on hide
+ # TODO: connect this to navpage close
+ def on_close(self):
+ self.disconnect_player()
+
+ def disconnect_player(self):
+ if not self.player is None:
+ self.player.connect_ended(None)
+ self.player.connect_update(None)
+
+ def on_player_end(self):
+ if self.position is None or self.duration is None:
+ # we only want to save valid datasets
+ return
+ set_video_playback_position(self.video, self.position, self.duration)
+ self.disconnect_player()
def on_player_data(self, position, duration):
if position is None or duration is None:
# we only want to save valid datasets
return
- set_video_playback_position(self.video, position, duration)
+ if self.position is None or self.duration is None:
+ # comparisons wouldn't be possible
+ return
+ if int(self.position) != int(position) or int(self.duration) != int(duration):
+ # only commit data if the second changed
+ set_video_playback_position(self.video, position, duration)
+ self.position = position
+ self.duration = duration
- channel = None
def display_channel(self):
if not self.channel is None:
self.about.add(AdaptiveFeedItem(self.channel))
return False
def display_error(self):
- text = Gtk.Label()
- text.set_label(_("Video could not be loaded"))
- cb = Gtk.CenterBox()
- cb.set_center_widget(text)
- self.scrollview.set_child(cb)
+ status = Adw.StatusPage()
+ status.set_title(_("*crickets chirping*"))
+ subs = get_subscribed_channels()
+ status.set_description(_("Video could not be loaded"))
+ status.set_icon_name("weather-few-clouds-night-symbolic")
+ self.scrollview.set_child(status)
return False
def background(self, video_id):
@@ 106,19 129,18 @@ class PlayerScreen(Adw.NavigationPage):
def __init__(self, server_id, video_id, *args, **kwargs):
super().__init__(*args, **kwargs)
- self.video_id = video_id
- # get instance handle
- server = get_servers_list()[server_id]
- self.instance = get_server_instance(server)
+ self.external_btn = None
+ self.channel = None
+ self.player = None
+
+ # skip init
+ if server_id is None or video_id is None:
+ return
# show fallback title
- self.set_title(_("Player"))
+ self.set_title(_("Loading..."))
self.header_bar = Adw.HeaderBar()
- self.external_btn = IconButton("","modem-symbolic")
- self.external_btn.connect("clicked", self.on_open_in_browser)
- self.header_bar.pack_end(self.external_btn)
-
self.toolbar_view = Adw.ToolbarView()
self.toolbar_view.add_top_bar(self.header_bar)
self.set_child(self.toolbar_view)
@@ 127,6 149,49 @@ class PlayerScreen(Adw.NavigationPage):
self.toolbar_view.set_content(self.wrapper)
self.scrollview = Gtk.ScrolledWindow()
+ self.wrapper.set_child(self.scrollview)
+
+ self.init_video(server_id, video_id)
+
+ def init_video(self, server_id, video_id):
+ # reset these for now
+ self.position = None
+ self.duration = None
+
+ self.video_id = video_id
+ # get instance handle
+ server = get_servers_list()[server_id]
+ self.instance = get_server_instance(server)
+
+ # show fallback title
+ # in case init_video is called twice,
+ # this resets the title
+ self.set_title(_("Loading..."))
+
+ # reset playback position if video was nearly completely watched
+ pos = get_video_playback_position(server_id, video_id)
+ dur = get_video_playback_position(server_id, video_id)
+ if not pos is None and not dur is None:
+ # TODO consider moving this to the settings panel
+ consider_done = 0.99*dur
+ # video was probably watched till end
+ # reset playback position
+ if pos >= consider_done:
+ # we can use force here, because if pos and dur aren't None
+ # set_video_playback_position was called before so the video exists
+ set_video_playback_position_force(server_id, video_id, 0, dur)
+
+ self.video_id = video_id
+ # get instance handle
+ server = get_servers_list()[server_id]
+ self.instance = get_server_instance(server)
+
+ if not self.external_btn is None:
+ self.header_bar.remove(self.external_btn)
+ self.external_btn = IconButton("","modem-symbolic")
+ self.external_btn.connect("clicked", self.on_open_in_browser)
+ self.header_bar.pack_end(self.external_btn)
+
# show spinner
# will be cleared by display_info
spinner = Gtk.Spinner()
@@ 136,8 201,6 @@ class PlayerScreen(Adw.NavigationPage):
cb.set_center_widget(spinner)
self.scrollview.set_child(cb)
- self.wrapper.set_child(self.scrollview)
-
self.box = Gtk.Box(orientation = Gtk.Orientation.VERTICAL)
# add a padding to the box
# so the preference groups do not touch the edge on mobile
A melon/player/playlist.py => melon/player/playlist.py +144 -0
@@ 0,0 1,144 @@
+import gi
+gi.require_version("WebKit", "6.0")
+gi.require_version('Gtk', '4.0')
+gi.require_version('Adw', '1')
+from gi.repository import Gtk, Adw, WebKit, GLib
+from unidecode import unidecode
+from gettext import gettext as _
+import threading
+
+from melon.servers.utils import get_server_instance, get_servers_list
+from melon.servers import SearchMode
+from melon.widgets.feeditem import AdaptiveFeedItem
+from melon.widgets.preferencerow import PreferenceRow, PreferenceType, Preference
+from melon.widgets.iconbutton import IconButton
+from melon.models import get_app_settings, add_to_history, register_callback
+from melon.models import get_video_playback_position, set_video_playback_position, set_video_playback_position_force
+from melon.utils import pass_me
+
+from melon.models import get_local_playlist, PlaylistWrapper, PlaylistWrapperType
+
+from melon.player import PlayerScreen
+
+class PlaylistPlayerScreen(PlayerScreen):
+ playlist = None
+ playlist_index = 0
+ playlist_instance = None
+ playlist_content = []
+
+ def __init__(self, ref: (tuple[str, str] | int), index=0, *args, **kwargs):
+ # make sure to initalize widget
+ # PlayerScreen.__init__ will break after initializing parents
+ # because neither server or video are supplied
+ super().__init__(None, None)
+
+ self.playlist_index = index
+ self.playlist = None
+ self.video_duration = None
+ self.video_position = None
+ self.playlist_instance = None
+
+ # prepare base layout
+ self.header_bar = Adw.HeaderBar()
+ self.set_title(_("Loading..."))
+ # show spinner
+ self.toolbar_view = Adw.ToolbarView()
+ self.toolbar_view.add_top_bar(self.header_bar)
+ self.set_child(self.toolbar_view)
+
+ self.wrapper = Adw.Clamp()
+ self.toolbar_view.set_content(self.wrapper)
+
+ self.scrollview = Gtk.ScrolledWindow()
+ # show spinner
+ # will be overwritten by init_load_video
+ spinner = Gtk.Spinner()
+ spinner.set_size_request(50, 50)
+ spinner.start()
+ cb = Gtk.CenterBox()
+ cb.set_center_widget(spinner)
+ self.scrollview.set_child(cb)
+ self.wrapper.set_child(self.scrollview)
+
+ # start prepare_playlist thread
+ self.visible = True
+ self.thread = threading.Thread(target=self.prepare_playlist_task, args=[ref])
+ self.thread.daemon = True
+ self.thread.start()
+
+ # fetch playlist data & store it interally
+ def prepare_playlist_task(self, ref: (tuple[str, str] | int)):
+ if isinstance(ref, int):
+ playlist_id = ref
+ # local playlist
+ pl = get_local_playlist(playlist_id)
+ self.playlist = PlaylistWrapper.from_local(pl)
+ self.playlist_content = pl.content
+ elif isinstance(ref, tuple):
+ server_id = ref[0]
+ playlist_id = ref[1]
+ # external playlist
+ server = get_servers_list()[server_id]
+ self.playlist_instance = get_server_instance(server)
+ pl = self.playlist_instance.get_playlist_info(playlist_id)
+ self.playlist = PlaylistWrapper.from_external(pl)
+ cont = self.playlist_instance.get_playlist_content(playlist_id)
+ self.playlist_content = cont
+ else:
+ # shouldn't be reachable
+ # if properly used
+ # (see argument type bounds)
+ GLib.idle_add(self.playlist_error)
+ return
+
+ # show empty playlist screen if there are no videos
+ if not self.playlist_content:
+ GLib.idle_add(self.empty_playlist)
+ return
+
+ # show playlist error screen if something didn't quite work out
+ if self.playlist_index > len(self.playlist_content):
+ GLib.idle_add(self.playlist_error)
+ return
+ self.prepare(0)
+
+ def prepare(self, index):
+ dt = self.playlist_content[index]
+ server_id = dt.server
+ video_id = dt.id
+
+ GLib.idle_add(self.init_video, server_id, video_id)
+
+ def on_player_end(self):
+ super().on_player_end()
+ # if there are more videos in the playlist
+ # load the next one
+ # do nothing if there are no more videos
+ if self.playlist_index+1 < len(self.playlist_content):
+ self.playlist_index += 1
+ self.prepare(self.playlist_index)
+
+ def empty_playlist(self):
+ # display playlist is empty banner
+ # acts as a drop in replacement for the player screen
+ status = Adw.StatusPage()
+ status.set_title(_("*crickets chirping*"))
+ subs = get_subscribed_channels()
+ status.set_description(_("This playlist is empty"))
+ status.set_icon_name("weather-few-clouds-night-symbolic")
+ self.scrollview.set_child(status)
+
+ def playlist_error(self):
+ status = Adw.StatusPage()
+ status.set_title(_("*crickets chirping*"))
+ subs = get_subscribed_channels()
+ status.set_description(_("There was an error loading the playlist"))
+ status.set_icon_name("weather-few-clouds-night-symbolic")
+ self.scrollview.set_child(status)
+
+ def display_player(self):
+ super().display_player()
+ # the super method pauses video by default
+ # however in playlist mode it makes sense to always autoplay
+ # TODO: consider not autoplaying the first title?
+ self.player.play()
M melon/playlist/__init__.py => melon/playlist/__init__.py +7 -1
@@ 2,7 2,7 @@ import sys
import gi
gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
-from gi.repository import Gtk, Adw
+from gi.repository import Gtk, Adw, GLib
from unidecode import unidecode
from gettext import gettext as _
@@ 39,6 39,12 @@ class LocalPlaylistScreen(Adw.NavigationPage):
edit_button = IconButton(_("Edit"), "document-edit-symbolic")
edit_button.connect("clicked", lambda _: self.open_edit())
+ self.startplay_btn = IconButton("","media-playback-start-symbolic", tooltip=_("Start playing"))
+ self.startplay_btn.set_action_name("win.playlistplayer-local")
+ self.startplay_btn.set_action_target_value(
+ GLib.Variant("u", self.playlist.id))
+ self.header_bar.pack_end(self.startplay_btn)
+
if len(playlist.content) == 0:
status = Adw.StatusPage()
status.set_title(_("*crickets chirping*"))
M melon/widgets/player.py => melon/widgets/player.py +7 -0
@@ 24,6 24,7 @@ class VideoPlayer(Gtk.Overlay):
self.duration = None
self.paused = True
self.update_callback=None
+ self.ended_callback=None
overlay = Gtk.Overlay()
self.set_child(overlay)
@@ 129,6 130,8 @@ class VideoPlayer(Gtk.Overlay):
def connect_update(self, callback=None):
self.update_callback = callback
+ def connect_ended(self, callback=None):
+ self.ended_callback = callback
def _show_controls(self):
self.controls.set_opacity(1)
@@ 184,6 187,10 @@ class VideoPlayer(Gtk.Overlay):
def _loop(self):
dur = self.source.query_duration(Gst.Format.TIME)
pos = self.source.query_position(Gst.Format.TIME)
+ # compare the nanoseconds values before converting them to seconds
+ # so we don't have to deal with float arithmetics
+ if pos[0] and dur[0] and pos[1] == dur[1] and not self.ended_callback is None:
+ self.ended_callback()
if dur[0]:
# convert nanoseconds to senconds
dur = dur[1]/(10**9)
M melon/window.py => melon/window.py +11 -0
@@ 15,6 15,7 @@ from melon.servers.utils import get_servers_list, get_server_instance
from melon.settings import SettingsScreen
from melon.importer import ImporterScreen
from melon.player import PlayerScreen
+from melon.player.playlist import PlaylistPlayerScreen
from melon.widgets.simpledialog import SimpleDialog
from melon.playlist import LocalPlaylistScreen
from melon.playlist.pick import PlaylistPickerDialog
@@ 66,6 67,13 @@ class MainWindow(Adw.ApplicationWindow):
def open_local_playlist_viewer(self, action, prefs):
self.view.push(LocalPlaylistScreen(prefs.unpack()))
+ def open_playlistplayer_local(self, action, prefs):
+ self.view.push(PlaylistPlayerScreen(prefs.unpack()))
+ def open_playlistplayer_external(self, action, prefs):
+ server_id = prefs[0]
+ playlist_id = prefs[1]
+ self.view.push(PlaylistPlayerScreen((server_id, playlist_id)))
+
# Opens the about app screen
def open_about(self,action,prefs):
dialog = Adw.AboutWindow()
@@ 128,6 136,9 @@ class MainWindow(Adw.ApplicationWindow):
self.reg_action("add_to_playlist", self.open_playlist_picker, "as")
# same as new_playlist but with [server_id, video_id] to identify a video
self.reg_action("add_to_new_playlist", self.open_playlist_creator, "as")
+ # playlist player
+ self.reg_action("playlistplayer-local", self.open_playlistplayer_local, "u")
+ self.reg_action("playlistplayer-external", self.open_playlistplayer_external, "as")
def reg_action(self, name, func, variant=None, target=None):
vtype = None
M po/POTFILES.in => po/POTFILES.in +2 -0
@@ 5,6 5,7 @@ melon/browse/channel.py
melon/browse/playlist.py
melon/browse/search.py
melon/browse/server.py
+melon/home/__init__.py
melon/home/history.py
melon/home/new.py
melon/home/playlists.py
@@ 12,6 13,7 @@ melon/home/subs.py
melon/import_providers/newpipe.py
melon/importer.py
melon/player/__init__.py
+melon/player/playlist.py
melon/playlist/__init__.py
melon/playlist/create.py
melon/playlist/pick.py
M po/de.po => po/de.po +106 -66
@@ 7,7 7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Melon 0.1.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-03-14 20:08+0100\n"
+"POT-Creation-Date: 2024-03-15 08:56+0100\n"
"PO-Revision-Date: 2024-03-01 11:23+0000\n"
"Last-Translator: Anonymous <noreply@weblate.org>\n"
"Language-Team: German <https://translate.codeberg.org/projects/melon/melon-"
@@ 80,9 80,11 @@ msgstr ""
#: ../melon/browse/__init__.py:18 ../melon/browse/search.py:58
#: ../melon/browse/server.py:101 ../melon/browse/server.py:127
-#: ../melon/home/history.py:23 ../melon/home/new.py:28
+#: ../melon/home/history.py:23 ../melon/home/new.py:29
#: ../melon/home/playlists.py:21 ../melon/home/subs.py:20
-#: ../melon/importer.py:61 ../melon/playlist/__init__.py:44
+#: ../melon/importer.py:61 ../melon/player/__init__.py:101
+#: ../melon/player/playlist.py:125 ../melon/player/playlist.py:133
+#: ../melon/playlist/__init__.py:50
msgid "*crickets chirping*"
msgstr "*Grillen zirpen*"
@@ 132,15 134,19 @@ msgstr ""
msgid "Channel"
msgstr ""
-#: ../melon/browse/playlist.py:47 ../melon/player/__init__.py:45
+#: ../melon/browse/playlist.py:37 ../melon/playlist/__init__.py:42
+msgid "Start playing"
+msgstr ""
+
+#: ../melon/browse/playlist.py:56 ../melon/player/__init__.py:44
msgid "Bookmark"
msgstr "Merken"
-#: ../melon/browse/playlist.py:48
+#: ../melon/browse/playlist.py:57
msgid "Add Playlist to your local playlist collection"
msgstr "Wiedergabeliste zur lokalen Sammlung hinzufügen"
-#: ../melon/browse/playlist.py:102
+#: ../melon/browse/playlist.py:111
msgid "Playlist"
msgstr ""
@@ 198,14 204,31 @@ msgstr "Versuche nach einem anderen Begriff zu suchen"
msgid "This feed is empty"
msgstr ""
-#: ../melon/home/history.py:24
-msgid "You haven't watched any videos yet"
-msgstr "Du hast noch keine Videos geschaut"
+#: ../melon/home/__init__.py:18
+msgid "Home"
+msgstr ""
-#: ../melon/home/history.py:26 ../melon/home/new.py:35 ../melon/home/subs.py:23
+#: ../melon/home/__init__.py:39 ../melon/home/history.py:26
+#: ../melon/home/new.py:36 ../melon/home/subs.py:23
msgid "Browse Servers"
msgstr "Dienste durchsuchen"
+#: ../melon/home/__init__.py:46
+msgid "Preferences"
+msgstr ""
+
+#: ../melon/home/__init__.py:47
+msgid "Import Data"
+msgstr ""
+
+#: ../melon/home/__init__.py:48
+msgid "About Melon"
+msgstr ""
+
+#: ../melon/home/history.py:24
+msgid "You haven't watched any videos yet"
+msgstr "Du hast noch keine Videos geschaut"
+
#: ../melon/home/history.py:36 ../melon/home/history.py:117
msgid "History"
msgstr "Verlauf"
@@ 222,31 245,39 @@ msgstr ""
msgid "Load older videos"
msgstr ""
-#: ../melon/home/new.py:22
+#: ../melon/home/new.py:23
msgid "Refresh"
msgstr "Aktualisieren"
-#: ../melon/home/new.py:31
+#: ../melon/home/new.py:32
msgid "Subscribe to a channel first, to view new uploads"
msgstr "Du musst einem Kanal folgen, um neue Videos zu sehen."
-#: ../melon/home/new.py:33
+#: ../melon/home/new.py:34
msgid "The channels you are subscribed to haven't uploaded anything yet"
msgstr "Die Kanäle, die du abonniert hast, haben noch nichts hochgeladen"
-#: ../melon/home/new.py:54
+#: ../melon/home/new.py:55
#, python-brace-format
msgid "(Last refresh: {last_refresh})"
msgstr "(Zuletzt aktualisiert: {last_refresh})"
-#: ../melon/home/new.py:56 ../melon/home/new.py:113
+#: ../melon/home/new.py:57 ../melon/home/new.py:146
msgid "What's new"
msgstr "Neues"
-#: ../melon/home/new.py:57
+#: ../melon/home/new.py:58
msgid "These are the latest videos of channels you follow"
msgstr "Hier sind die neusten Videos von Kanälen, denen du folgst"
+#: ../melon/home/new.py:137
+msgid "Pick up where you left off"
+msgstr ""
+
+#: ../melon/home/new.py:138
+msgid "Watch"
+msgstr ""
+
#: ../melon/home/playlists.py:22
msgid "You don't have any playlists yet"
msgstr "Du hast noch keine Wiedergabelisten"
@@ 310,105 341,114 @@ msgstr "Die folgenden Import-Methoden wurden gefunden"
msgid "There are no available importer methods"
msgstr "Es gibt keine verfügbaren Import-Methoden"
-#: ../melon/player/__init__.py:35
+#: ../melon/player/__init__.py:34
msgid "Description"
msgstr "Beschreibung"
-#: ../melon/player/__init__.py:46
+#: ../melon/player/__init__.py:45
msgid "Add this video to a playlist"
msgstr "Füge dieses Video einer Wiedergabeliste hinzu"
-#: ../melon/player/__init__.py:65
+#: ../melon/player/__init__.py:103
msgid "Video could not be loaded"
msgstr ""
-#: ../melon/player/__init__.py:97
-msgid "Player"
+#: ../melon/player/__init__.py:139 ../melon/player/__init__.py:173
+#: ../melon/player/playlist.py:43
+msgid "Loading..."
+msgstr ""
+
+#: ../melon/player/playlist.py:127
+msgid "This playlist is empty"
+msgstr ""
+
+#: ../melon/player/playlist.py:135
+msgid "There was an error loading the playlist"
msgstr ""
#: ../melon/playlist/__init__.py:39
msgid "Edit"
msgstr "Bearbeiten"
-#: ../melon/playlist/__init__.py:45
+#: ../melon/playlist/__init__.py:51
msgid "You haven't added any videos to this playlist yet"
msgstr "Du hast noch keine Videos zu dieser Wiedergabeliste hinzugefügt"
-#: ../melon/playlist/__init__.py:47
+#: ../melon/playlist/__init__.py:53
msgid "Start watching"
msgstr "Videos anschauen"
-#: ../melon/playlist/__init__.py:77
+#: ../melon/playlist/__init__.py:83
msgid "Edit Playlist"
msgstr "Wiedergabeliste bearbeiten"
-#: ../melon/playlist/__init__.py:83
+#: ../melon/playlist/__init__.py:89
msgid "Playlist details"
msgstr "Wiedergabelistendetails"
-#: ../melon/playlist/__init__.py:84
+#: ../melon/playlist/__init__.py:90
msgid "Change playlist information"
msgstr "Wiedergabelistendetails ändern"
-#: ../melon/playlist/__init__.py:86 ../melon/playlist/create.py:37
+#: ../melon/playlist/__init__.py:92 ../melon/playlist/create.py:37
msgid "Playlist name"
msgstr "Name der Wiedergabeliste"
-#: ../melon/playlist/__init__.py:89 ../melon/playlist/create.py:40
+#: ../melon/playlist/__init__.py:95 ../melon/playlist/create.py:40
msgid "Playlist description"
msgstr "Beschreibung der Wiedergabeliste"
-#: ../melon/playlist/__init__.py:94
+#: ../melon/playlist/__init__.py:100
msgid "Save details"
msgstr "Details speichern"
-#: ../melon/playlist/__init__.py:95
+#: ../melon/playlist/__init__.py:101
msgid "Change playlist title and description. (Closes the dialog)"
msgstr ""
"Titel und Beschreibung der Wiedergabeliste ändern. (Schließt den Dialog)"
-#: ../melon/playlist/__init__.py:105 ../melon/playlist/__init__.py:147
+#: ../melon/playlist/__init__.py:111 ../melon/playlist/__init__.py:153
msgid "Delete Playlist"
msgstr "Wiedergabeliste löschen"
-#: ../melon/playlist/__init__.py:106
+#: ../melon/playlist/__init__.py:112
msgid "Delete this playlist and it's content. This can NOT be undone."
msgstr ""
"Diese Wiedergabeliste und ihren Inhalt löschen. Diese Aktion kann nicht "
"rückgängig gemacht werden."
-#: ../melon/playlist/__init__.py:117
+#: ../melon/playlist/__init__.py:123
msgid "Close"
msgstr "Schließen"
-#: ../melon/playlist/__init__.py:117
+#: ../melon/playlist/__init__.py:123
msgid "Close without changing anything"
msgstr ""
-#: ../melon/playlist/__init__.py:150
+#: ../melon/playlist/__init__.py:156
msgid "Do you really want to delete this playlist?"
msgstr ""
-#: ../melon/playlist/__init__.py:151
+#: ../melon/playlist/__init__.py:157
msgid "This cannot be undone"
msgstr "Dies kann nicht rückgängig gemacht werden"
-#: ../melon/playlist/__init__.py:155 ../melon/playlist/create.py:47
-#: ../melon/playlist/pick.py:70 ../melon/widgets/preferencerow.py:174
-#: ../melon/widgets/preferencerow.py:217
+#: ../melon/playlist/__init__.py:161 ../melon/playlist/create.py:47
+#: ../melon/playlist/pick.py:70 ../melon/widgets/preferencerow.py:175
+#: ../melon/widgets/preferencerow.py:218
msgid "Cancel"
msgstr "Abbruch"
-#: ../melon/playlist/__init__.py:155
+#: ../melon/playlist/__init__.py:161
msgid "Do not delete the playlist"
msgstr "Wiedergabeliste nicht löschen"
-#: ../melon/playlist/__init__.py:156 ../melon/widgets/preferencerow.py:206
-#: ../melon/widgets/preferencerow.py:218
+#: ../melon/playlist/__init__.py:162 ../melon/widgets/preferencerow.py:207
+#: ../melon/widgets/preferencerow.py:219
msgid "Delete"
msgstr "Löschen"
-#: ../melon/playlist/__init__.py:156
+#: ../melon/playlist/__init__.py:162
msgid "Delete this playlist"
msgstr "Diese Wiedergabeliste löschen"
@@ 436,7 476,7 @@ msgstr "Unbenannte Wiedergabeliste"
msgid "Do not create playlist"
msgstr "Wiedergabeliste nicht erstellen"
-#: ../melon/playlist/create.py:48 ../melon/widgets/preferencerow.py:175
+#: ../melon/playlist/create.py:48 ../melon/widgets/preferencerow.py:176
msgid "Create"
msgstr "Erstellen"
@@ 472,26 512,26 @@ msgstr "Neue Wiedergabeliste erstellen und Video hinzufügen"
msgid "Add to Playlist"
msgstr "Zur Wiedergabeliste hinzufügen"
-#: ../melon/servers/invidious/__init__.py:27
+#: ../melon/servers/invidious/__init__.py:32
msgid "Open source alternative front-end to YouTube"
msgstr "Quelloffenes alternatives Frontend für YouTube"
-#: ../melon/servers/invidious/__init__.py:32
+#: ../melon/servers/invidious/__init__.py:37
msgid "Instance"
msgstr "Instanz"
-#: ../melon/servers/invidious/__init__.py:33
+#: ../melon/servers/invidious/__init__.py:38
msgid ""
"See https://docs.invidious.io/instances/ for a list of available instances"
msgstr ""
"Auf https://docs.invidious.io/instances/ kannst du eine liste verfügbarer "
"Instanzen finden"
-#: ../melon/servers/invidious/__init__.py:44
+#: ../melon/servers/invidious/__init__.py:49
msgid "Trending"
msgstr "Trends"
-#: ../melon/servers/invidious/__init__.py:45
+#: ../melon/servers/invidious/__init__.py:50
msgid "Popular"
msgstr "Beliebt"
@@ 651,71 691,71 @@ msgstr ""
"Deaktivierte Dienste werden beim Durchsuchen und auf dem Startbildschirm "
"nicht angezeigt"
-#: ../melon/widgets/player.py:32
+#: ../melon/widgets/player.py:34
msgid "No streams available"
msgstr ""
-#: ../melon/widgets/player.py:78 ../melon/widgets/player.py:244
+#: ../melon/widgets/player.py:80 ../melon/widgets/player.py:279
msgid "Play"
msgstr ""
-#: ../melon/widgets/player.py:99
+#: ../melon/widgets/player.py:101
msgid "Video quality"
msgstr "Auflösung"
-#: ../melon/widgets/player.py:238
+#: ../melon/widgets/player.py:273
msgid "Pause"
msgstr ""
-#: ../melon/widgets/preferencerow.py:115
+#: ../melon/widgets/preferencerow.py:116
msgid "Add"
msgstr "Hinzufügen"
-#: ../melon/widgets/preferencerow.py:129
+#: ../melon/widgets/preferencerow.py:130
msgid "Move up"
msgstr "Nach oben verschieben"
-#: ../melon/widgets/preferencerow.py:140
+#: ../melon/widgets/preferencerow.py:141
msgid "Move down"
msgstr "Nach unten verschieben"
-#: ../melon/widgets/preferencerow.py:149
+#: ../melon/widgets/preferencerow.py:150
msgid "Remove from list"
msgstr "Von der Liste entfernen"
-#: ../melon/widgets/preferencerow.py:162
+#: ../melon/widgets/preferencerow.py:163
msgid "Add Item"
msgstr "Eintrag hinzufügen"
-#: ../melon/widgets/preferencerow.py:165
+#: ../melon/widgets/preferencerow.py:166
msgid "Create a new list entry"
msgstr "Neuen Listeneintrag erstellen"
-#: ../melon/widgets/preferencerow.py:166
+#: ../melon/widgets/preferencerow.py:167
msgid "Enter the new value here"
msgstr "Gibt den neuen Wert hier ein"
-#: ../melon/widgets/preferencerow.py:169
+#: ../melon/widgets/preferencerow.py:170
msgid "Value"
msgstr "Wert"
-#: ../melon/widgets/preferencerow.py:209
+#: ../melon/widgets/preferencerow.py:210
msgid "Do you really want to delete this item?"
msgstr "Möchtest du den Eintrag wirklich löschen?"
-#: ../melon/widgets/preferencerow.py:210
+#: ../melon/widgets/preferencerow.py:211
msgid "You won't be able to restore it afterwards"
msgstr "Eine Wiederherstellung ist nicht möglich"
-#: ../melon/widgets/preferencerow.py:217
+#: ../melon/widgets/preferencerow.py:218
msgid "Do not remove item"
msgstr "Eintrag nicht entfernen"
-#: ../melon/widgets/preferencerow.py:218
+#: ../melon/widgets/preferencerow.py:219
msgid "Remove item from list"
msgstr "Eintrag von der Liste entfernen"
-#: ../melon/window.py:76
+#: ../melon/window.py:84
msgid "Stream videos on the go"
msgstr "Videos unterwegs streamen"
M po/fa.po => po/fa.po +105 -65
@@ 7,7 7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Melon 0.1.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-03-14 20:08+0100\n"
+"POT-Creation-Date: 2024-03-15 08:56+0100\n"
"PO-Revision-Date: 2024-03-05 05:13+0000\n"
"Last-Translator: sohrabbehdani <behdanisohrab@gmail.com>\n"
"Language-Team: Persian <https://translate.codeberg.org/projects/melon/melon-"
@@ 75,9 75,11 @@ msgstr ""
#: ../melon/browse/__init__.py:18 ../melon/browse/search.py:58
#: ../melon/browse/server.py:101 ../melon/browse/server.py:127
-#: ../melon/home/history.py:23 ../melon/home/new.py:28
+#: ../melon/home/history.py:23 ../melon/home/new.py:29
#: ../melon/home/playlists.py:21 ../melon/home/subs.py:20
-#: ../melon/importer.py:61 ../melon/playlist/__init__.py:44
+#: ../melon/importer.py:61 ../melon/player/__init__.py:101
+#: ../melon/player/playlist.py:125 ../melon/player/playlist.py:133
+#: ../melon/playlist/__init__.py:50
msgid "*crickets chirping*"
msgstr ""
@@ 126,15 128,19 @@ msgstr ""
msgid "Channel"
msgstr ""
-#: ../melon/browse/playlist.py:47 ../melon/player/__init__.py:45
+#: ../melon/browse/playlist.py:37 ../melon/playlist/__init__.py:42
+msgid "Start playing"
+msgstr ""
+
+#: ../melon/browse/playlist.py:56 ../melon/player/__init__.py:44
msgid "Bookmark"
msgstr "نشانک گذاری"
-#: ../melon/browse/playlist.py:48
+#: ../melon/browse/playlist.py:57
msgid "Add Playlist to your local playlist collection"
msgstr "افزودن این لیستپخش به مجموعه لیستپخش های محلی"
-#: ../melon/browse/playlist.py:102
+#: ../melon/browse/playlist.py:111
msgid "Playlist"
msgstr ""
@@ 191,14 197,31 @@ msgstr ""
msgid "This feed is empty"
msgstr ""
-#: ../melon/home/history.py:24
-msgid "You haven't watched any videos yet"
+#: ../melon/home/__init__.py:18
+msgid "Home"
msgstr ""
-#: ../melon/home/history.py:26 ../melon/home/new.py:35 ../melon/home/subs.py:23
+#: ../melon/home/__init__.py:39 ../melon/home/history.py:26
+#: ../melon/home/new.py:36 ../melon/home/subs.py:23
msgid "Browse Servers"
msgstr "جستجو در کارساز ها"
+#: ../melon/home/__init__.py:46
+msgid "Preferences"
+msgstr ""
+
+#: ../melon/home/__init__.py:47
+msgid "Import Data"
+msgstr ""
+
+#: ../melon/home/__init__.py:48
+msgid "About Melon"
+msgstr ""
+
+#: ../melon/home/history.py:24
+msgid "You haven't watched any videos yet"
+msgstr ""
+
#: ../melon/home/history.py:36 ../melon/home/history.py:117
msgid "History"
msgstr ""
@@ 215,31 238,39 @@ msgstr ""
msgid "Load older videos"
msgstr ""
-#: ../melon/home/new.py:22
+#: ../melon/home/new.py:23
msgid "Refresh"
msgstr ""
-#: ../melon/home/new.py:31
+#: ../melon/home/new.py:32
msgid "Subscribe to a channel first, to view new uploads"
msgstr ""
-#: ../melon/home/new.py:33
+#: ../melon/home/new.py:34
msgid "The channels you are subscribed to haven't uploaded anything yet"
msgstr ""
-#: ../melon/home/new.py:54
+#: ../melon/home/new.py:55
#, python-brace-format
msgid "(Last refresh: {last_refresh})"
msgstr ""
-#: ../melon/home/new.py:56 ../melon/home/new.py:113
+#: ../melon/home/new.py:57 ../melon/home/new.py:146
msgid "What's new"
msgstr ""
-#: ../melon/home/new.py:57
+#: ../melon/home/new.py:58
msgid "These are the latest videos of channels you follow"
msgstr ""
+#: ../melon/home/new.py:137
+msgid "Pick up where you left off"
+msgstr ""
+
+#: ../melon/home/new.py:138
+msgid "Watch"
+msgstr ""
+
#: ../melon/home/playlists.py:22
msgid "You don't have any playlists yet"
msgstr ""
@@ 298,102 329,111 @@ msgstr ""
msgid "There are no available importer methods"
msgstr ""
-#: ../melon/player/__init__.py:35
+#: ../melon/player/__init__.py:34
msgid "Description"
msgstr ""
-#: ../melon/player/__init__.py:46
+#: ../melon/player/__init__.py:45
msgid "Add this video to a playlist"
msgstr "افزودن این ویدئو به لیستپخش"
-#: ../melon/player/__init__.py:65
+#: ../melon/player/__init__.py:103
msgid "Video could not be loaded"
msgstr ""
-#: ../melon/player/__init__.py:97
-msgid "Player"
+#: ../melon/player/__init__.py:139 ../melon/player/__init__.py:173
+#: ../melon/player/playlist.py:43
+msgid "Loading..."
+msgstr ""
+
+#: ../melon/player/playlist.py:127
+msgid "This playlist is empty"
+msgstr ""
+
+#: ../melon/player/playlist.py:135
+msgid "There was an error loading the playlist"
msgstr ""
#: ../melon/playlist/__init__.py:39
msgid "Edit"
msgstr ""
-#: ../melon/playlist/__init__.py:45
+#: ../melon/playlist/__init__.py:51
msgid "You haven't added any videos to this playlist yet"
msgstr ""
-#: ../melon/playlist/__init__.py:47
+#: ../melon/playlist/__init__.py:53
msgid "Start watching"
msgstr ""
-#: ../melon/playlist/__init__.py:77
+#: ../melon/playlist/__init__.py:83
msgid "Edit Playlist"
msgstr ""
-#: ../melon/playlist/__init__.py:83
+#: ../melon/playlist/__init__.py:89
msgid "Playlist details"
msgstr ""
-#: ../melon/playlist/__init__.py:84
+#: ../melon/playlist/__init__.py:90
msgid "Change playlist information"
msgstr "تغییر اطلاعات لیست پخش"
-#: ../melon/playlist/__init__.py:86 ../melon/playlist/create.py:37
+#: ../melon/playlist/__init__.py:92 ../melon/playlist/create.py:37
msgid "Playlist name"
msgstr ""
-#: ../melon/playlist/__init__.py:89 ../melon/playlist/create.py:40
+#: ../melon/playlist/__init__.py:95 ../melon/playlist/create.py:40
msgid "Playlist description"
msgstr ""
-#: ../melon/playlist/__init__.py:94
+#: ../melon/playlist/__init__.py:100
msgid "Save details"
msgstr ""
-#: ../melon/playlist/__init__.py:95
+#: ../melon/playlist/__init__.py:101
msgid "Change playlist title and description. (Closes the dialog)"
msgstr "تغییر عنوان و توضیحات لیست پخش (این پنجره بسته می شود)"
-#: ../melon/playlist/__init__.py:105 ../melon/playlist/__init__.py:147
+#: ../melon/playlist/__init__.py:111 ../melon/playlist/__init__.py:153
msgid "Delete Playlist"
msgstr ""
-#: ../melon/playlist/__init__.py:106
+#: ../melon/playlist/__init__.py:112
msgid "Delete this playlist and it's content. This can NOT be undone."
msgstr ""
-#: ../melon/playlist/__init__.py:117
+#: ../melon/playlist/__init__.py:123
msgid "Close"
msgstr "بستن"
-#: ../melon/playlist/__init__.py:117
+#: ../melon/playlist/__init__.py:123
msgid "Close without changing anything"
msgstr "بستن بدون تغییر دادن چیزی"
-#: ../melon/playlist/__init__.py:150
+#: ../melon/playlist/__init__.py:156
msgid "Do you really want to delete this playlist?"
msgstr ""
-#: ../melon/playlist/__init__.py:151
+#: ../melon/playlist/__init__.py:157
msgid "This cannot be undone"
msgstr ""
-#: ../melon/playlist/__init__.py:155 ../melon/playlist/create.py:47
-#: ../melon/playlist/pick.py:70 ../melon/widgets/preferencerow.py:174
-#: ../melon/widgets/preferencerow.py:217
+#: ../melon/playlist/__init__.py:161 ../melon/playlist/create.py:47
+#: ../melon/playlist/pick.py:70 ../melon/widgets/preferencerow.py:175
+#: ../melon/widgets/preferencerow.py:218
msgid "Cancel"
msgstr "لغو"
-#: ../melon/playlist/__init__.py:155
+#: ../melon/playlist/__init__.py:161
msgid "Do not delete the playlist"
msgstr ""
-#: ../melon/playlist/__init__.py:156 ../melon/widgets/preferencerow.py:206
-#: ../melon/widgets/preferencerow.py:218
+#: ../melon/playlist/__init__.py:162 ../melon/widgets/preferencerow.py:207
+#: ../melon/widgets/preferencerow.py:219
msgid "Delete"
msgstr ""
-#: ../melon/playlist/__init__.py:156
+#: ../melon/playlist/__init__.py:162
msgid "Delete this playlist"
msgstr ""
@@ 421,7 461,7 @@ msgstr ""
msgid "Do not create playlist"
msgstr ""
-#: ../melon/playlist/create.py:48 ../melon/widgets/preferencerow.py:175
+#: ../melon/playlist/create.py:48 ../melon/widgets/preferencerow.py:176
msgid "Create"
msgstr "ایجاد"
@@ 458,24 498,24 @@ msgstr "ایجاد یک لیستپخش جدید و افزودن ویدئو ب
msgid "Add to Playlist"
msgstr "افزودن به لیستپخش"
-#: ../melon/servers/invidious/__init__.py:27
+#: ../melon/servers/invidious/__init__.py:32
msgid "Open source alternative front-end to YouTube"
msgstr ""
-#: ../melon/servers/invidious/__init__.py:32
+#: ../melon/servers/invidious/__init__.py:37
msgid "Instance"
msgstr ""
-#: ../melon/servers/invidious/__init__.py:33
+#: ../melon/servers/invidious/__init__.py:38
msgid ""
"See https://docs.invidious.io/instances/ for a list of available instances"
msgstr ""
-#: ../melon/servers/invidious/__init__.py:44
+#: ../melon/servers/invidious/__init__.py:49
msgid "Trending"
msgstr ""
-#: ../melon/servers/invidious/__init__.py:45
+#: ../melon/servers/invidious/__init__.py:50
msgid "Popular"
msgstr ""
@@ 615,70 655,70 @@ msgid ""
"Disabled servers won't show up in the browser or on the local/home screen"
msgstr ""
-#: ../melon/widgets/player.py:32
+#: ../melon/widgets/player.py:34
msgid "No streams available"
msgstr ""
-#: ../melon/widgets/player.py:78 ../melon/widgets/player.py:244
+#: ../melon/widgets/player.py:80 ../melon/widgets/player.py:279
msgid "Play"
msgstr ""
-#: ../melon/widgets/player.py:99
+#: ../melon/widgets/player.py:101
msgid "Video quality"
msgstr ""
-#: ../melon/widgets/player.py:238
+#: ../melon/widgets/player.py:273
msgid "Pause"
msgstr ""
-#: ../melon/widgets/preferencerow.py:115
+#: ../melon/widgets/preferencerow.py:116
msgid "Add"
msgstr "افزودن"
-#: ../melon/widgets/preferencerow.py:129
+#: ../melon/widgets/preferencerow.py:130
msgid "Move up"
msgstr ""
-#: ../melon/widgets/preferencerow.py:140
+#: ../melon/widgets/preferencerow.py:141
msgid "Move down"
msgstr ""
-#: ../melon/widgets/preferencerow.py:149
+#: ../melon/widgets/preferencerow.py:150
msgid "Remove from list"
msgstr ""
-#: ../melon/widgets/preferencerow.py:162
+#: ../melon/widgets/preferencerow.py:163
msgid "Add Item"
msgstr "افزودن مورد"
-#: ../melon/widgets/preferencerow.py:165
+#: ../melon/widgets/preferencerow.py:166
msgid "Create a new list entry"
msgstr "ایجاد یک ورودی لیست جدید"
-#: ../melon/widgets/preferencerow.py:166
+#: ../melon/widgets/preferencerow.py:167
msgid "Enter the new value here"
msgstr ""
-#: ../melon/widgets/preferencerow.py:169
+#: ../melon/widgets/preferencerow.py:170
msgid "Value"
msgstr ""
-#: ../melon/widgets/preferencerow.py:209
+#: ../melon/widgets/preferencerow.py:210
msgid "Do you really want to delete this item?"
msgstr ""
-#: ../melon/widgets/preferencerow.py:210
+#: ../melon/widgets/preferencerow.py:211
msgid "You won't be able to restore it afterwards"
msgstr ""
-#: ../melon/widgets/preferencerow.py:217
+#: ../melon/widgets/preferencerow.py:218
msgid "Do not remove item"
msgstr ""
-#: ../melon/widgets/preferencerow.py:218
+#: ../melon/widgets/preferencerow.py:219
msgid "Remove item from list"
msgstr ""
-#: ../melon/window.py:76
+#: ../melon/window.py:84
msgid "Stream videos on the go"
msgstr ""
M po/melon.pot => po/melon.pot +105 -65
@@ 8,7 8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Melon 0.1.3\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-03-14 20:08+0100\n"
+"POT-Creation-Date: 2024-03-15 08:56+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ 74,9 74,11 @@ msgstr ""
#: ../melon/browse/__init__.py:18 ../melon/browse/search.py:58
#: ../melon/browse/server.py:101 ../melon/browse/server.py:127
-#: ../melon/home/history.py:23 ../melon/home/new.py:28
+#: ../melon/home/history.py:23 ../melon/home/new.py:29
#: ../melon/home/playlists.py:21 ../melon/home/subs.py:20
-#: ../melon/importer.py:61 ../melon/playlist/__init__.py:44
+#: ../melon/importer.py:61 ../melon/player/__init__.py:101
+#: ../melon/player/playlist.py:125 ../melon/player/playlist.py:133
+#: ../melon/playlist/__init__.py:50
msgid "*crickets chirping*"
msgstr ""
@@ 125,15 127,19 @@ msgstr ""
msgid "Channel"
msgstr ""
-#: ../melon/browse/playlist.py:47 ../melon/player/__init__.py:45
+#: ../melon/browse/playlist.py:37 ../melon/playlist/__init__.py:42
+msgid "Start playing"
+msgstr ""
+
+#: ../melon/browse/playlist.py:56 ../melon/player/__init__.py:44
msgid "Bookmark"
msgstr ""
-#: ../melon/browse/playlist.py:48
+#: ../melon/browse/playlist.py:57
msgid "Add Playlist to your local playlist collection"
msgstr ""
-#: ../melon/browse/playlist.py:102
+#: ../melon/browse/playlist.py:111
msgid "Playlist"
msgstr ""
@@ 190,14 196,31 @@ msgstr ""
msgid "This feed is empty"
msgstr ""
-#: ../melon/home/history.py:24
-msgid "You haven't watched any videos yet"
+#: ../melon/home/__init__.py:18
+msgid "Home"
msgstr ""
-#: ../melon/home/history.py:26 ../melon/home/new.py:35 ../melon/home/subs.py:23
+#: ../melon/home/__init__.py:39 ../melon/home/history.py:26
+#: ../melon/home/new.py:36 ../melon/home/subs.py:23
msgid "Browse Servers"
msgstr ""
+#: ../melon/home/__init__.py:46
+msgid "Preferences"
+msgstr ""
+
+#: ../melon/home/__init__.py:47
+msgid "Import Data"
+msgstr ""
+
+#: ../melon/home/__init__.py:48
+msgid "About Melon"
+msgstr ""
+
+#: ../melon/home/history.py:24
+msgid "You haven't watched any videos yet"
+msgstr ""
+
#: ../melon/home/history.py:36 ../melon/home/history.py:117
msgid "History"
msgstr ""
@@ 214,31 237,39 @@ msgstr ""
msgid "Load older videos"
msgstr ""
-#: ../melon/home/new.py:22
+#: ../melon/home/new.py:23
msgid "Refresh"
msgstr ""
-#: ../melon/home/new.py:31
+#: ../melon/home/new.py:32
msgid "Subscribe to a channel first, to view new uploads"
msgstr ""
-#: ../melon/home/new.py:33
+#: ../melon/home/new.py:34
msgid "The channels you are subscribed to haven't uploaded anything yet"
msgstr ""
-#: ../melon/home/new.py:54
+#: ../melon/home/new.py:55
#, python-brace-format
msgid "(Last refresh: {last_refresh})"
msgstr ""
-#: ../melon/home/new.py:56 ../melon/home/new.py:113
+#: ../melon/home/new.py:57 ../melon/home/new.py:146
msgid "What's new"
msgstr ""
-#: ../melon/home/new.py:57
+#: ../melon/home/new.py:58
msgid "These are the latest videos of channels you follow"
msgstr ""
+#: ../melon/home/new.py:137
+msgid "Pick up where you left off"
+msgstr ""
+
+#: ../melon/home/new.py:138
+msgid "Watch"
+msgstr ""
+
#: ../melon/home/playlists.py:22
msgid "You don't have any playlists yet"
msgstr ""
@@ 297,102 328,111 @@ msgstr ""
msgid "There are no available importer methods"
msgstr ""
-#: ../melon/player/__init__.py:35
+#: ../melon/player/__init__.py:34
msgid "Description"
msgstr ""
-#: ../melon/player/__init__.py:46
+#: ../melon/player/__init__.py:45
msgid "Add this video to a playlist"
msgstr ""
-#: ../melon/player/__init__.py:65
+#: ../melon/player/__init__.py:103
msgid "Video could not be loaded"
msgstr ""
-#: ../melon/player/__init__.py:97
-msgid "Player"
+#: ../melon/player/__init__.py:139 ../melon/player/__init__.py:173
+#: ../melon/player/playlist.py:43
+msgid "Loading..."
+msgstr ""
+
+#: ../melon/player/playlist.py:127
+msgid "This playlist is empty"
+msgstr ""
+
+#: ../melon/player/playlist.py:135
+msgid "There was an error loading the playlist"
msgstr ""
#: ../melon/playlist/__init__.py:39
msgid "Edit"
msgstr ""
-#: ../melon/playlist/__init__.py:45
+#: ../melon/playlist/__init__.py:51
msgid "You haven't added any videos to this playlist yet"
msgstr ""
-#: ../melon/playlist/__init__.py:47
+#: ../melon/playlist/__init__.py:53
msgid "Start watching"
msgstr ""
-#: ../melon/playlist/__init__.py:77
+#: ../melon/playlist/__init__.py:83
msgid "Edit Playlist"
msgstr ""
-#: ../melon/playlist/__init__.py:83
+#: ../melon/playlist/__init__.py:89
msgid "Playlist details"
msgstr ""
-#: ../melon/playlist/__init__.py:84
+#: ../melon/playlist/__init__.py:90
msgid "Change playlist information"
msgstr ""
-#: ../melon/playlist/__init__.py:86 ../melon/playlist/create.py:37
+#: ../melon/playlist/__init__.py:92 ../melon/playlist/create.py:37
msgid "Playlist name"
msgstr ""
-#: ../melon/playlist/__init__.py:89 ../melon/playlist/create.py:40
+#: ../melon/playlist/__init__.py:95 ../melon/playlist/create.py:40
msgid "Playlist description"
msgstr ""
-#: ../melon/playlist/__init__.py:94
+#: ../melon/playlist/__init__.py:100
msgid "Save details"
msgstr ""
-#: ../melon/playlist/__init__.py:95
+#: ../melon/playlist/__init__.py:101
msgid "Change playlist title and description. (Closes the dialog)"
msgstr ""
-#: ../melon/playlist/__init__.py:105 ../melon/playlist/__init__.py:147
+#: ../melon/playlist/__init__.py:111 ../melon/playlist/__init__.py:153
msgid "Delete Playlist"
msgstr ""
-#: ../melon/playlist/__init__.py:106
+#: ../melon/playlist/__init__.py:112
msgid "Delete this playlist and it's content. This can NOT be undone."
msgstr ""
-#: ../melon/playlist/__init__.py:117
+#: ../melon/playlist/__init__.py:123
msgid "Close"
msgstr ""
-#: ../melon/playlist/__init__.py:117
+#: ../melon/playlist/__init__.py:123
msgid "Close without changing anything"
msgstr ""
-#: ../melon/playlist/__init__.py:150
+#: ../melon/playlist/__init__.py:156
msgid "Do you really want to delete this playlist?"
msgstr ""
-#: ../melon/playlist/__init__.py:151
+#: ../melon/playlist/__init__.py:157
msgid "This cannot be undone"
msgstr ""
-#: ../melon/playlist/__init__.py:155 ../melon/playlist/create.py:47
-#: ../melon/playlist/pick.py:70 ../melon/widgets/preferencerow.py:174
-#: ../melon/widgets/preferencerow.py:217
+#: ../melon/playlist/__init__.py:161 ../melon/playlist/create.py:47
+#: ../melon/playlist/pick.py:70 ../melon/widgets/preferencerow.py:175
+#: ../melon/widgets/preferencerow.py:218
msgid "Cancel"
msgstr ""
-#: ../melon/playlist/__init__.py:155
+#: ../melon/playlist/__init__.py:161
msgid "Do not delete the playlist"
msgstr ""
-#: ../melon/playlist/__init__.py:156 ../melon/widgets/preferencerow.py:206
-#: ../melon/widgets/preferencerow.py:218
+#: ../melon/playlist/__init__.py:162 ../melon/widgets/preferencerow.py:207
+#: ../melon/widgets/preferencerow.py:219
msgid "Delete"
msgstr ""
-#: ../melon/playlist/__init__.py:156
+#: ../melon/playlist/__init__.py:162
msgid "Delete this playlist"
msgstr ""
@@ 420,7 460,7 @@ msgstr ""
msgid "Do not create playlist"
msgstr ""
-#: ../melon/playlist/create.py:48 ../melon/widgets/preferencerow.py:175
+#: ../melon/playlist/create.py:48 ../melon/widgets/preferencerow.py:176
msgid "Create"
msgstr ""
@@ 454,24 494,24 @@ msgstr ""
msgid "Add to Playlist"
msgstr ""
-#: ../melon/servers/invidious/__init__.py:27
+#: ../melon/servers/invidious/__init__.py:32
msgid "Open source alternative front-end to YouTube"
msgstr ""
-#: ../melon/servers/invidious/__init__.py:32
+#: ../melon/servers/invidious/__init__.py:37
msgid "Instance"
msgstr ""
-#: ../melon/servers/invidious/__init__.py:33
+#: ../melon/servers/invidious/__init__.py:38
msgid ""
"See https://docs.invidious.io/instances/ for a list of available instances"
msgstr ""
-#: ../melon/servers/invidious/__init__.py:44
+#: ../melon/servers/invidious/__init__.py:49
msgid "Trending"
msgstr ""
-#: ../melon/servers/invidious/__init__.py:45
+#: ../melon/servers/invidious/__init__.py:50
msgid "Popular"
msgstr ""
@@ 611,70 651,70 @@ msgid ""
"Disabled servers won't show up in the browser or on the local/home screen"
msgstr ""
-#: ../melon/widgets/player.py:32
+#: ../melon/widgets/player.py:34
msgid "No streams available"
msgstr ""
-#: ../melon/widgets/player.py:78 ../melon/widgets/player.py:244
+#: ../melon/widgets/player.py:80 ../melon/widgets/player.py:279
msgid "Play"
msgstr ""
-#: ../melon/widgets/player.py:99
+#: ../melon/widgets/player.py:101
msgid "Video quality"
msgstr ""
-#: ../melon/widgets/player.py:238
+#: ../melon/widgets/player.py:273
msgid "Pause"
msgstr ""
-#: ../melon/widgets/preferencerow.py:115
+#: ../melon/widgets/preferencerow.py:116
msgid "Add"
msgstr ""
-#: ../melon/widgets/preferencerow.py:129
+#: ../melon/widgets/preferencerow.py:130
msgid "Move up"
msgstr ""
-#: ../melon/widgets/preferencerow.py:140
+#: ../melon/widgets/preferencerow.py:141
msgid "Move down"
msgstr ""
-#: ../melon/widgets/preferencerow.py:149
+#: ../melon/widgets/preferencerow.py:150
msgid "Remove from list"
msgstr ""
-#: ../melon/widgets/preferencerow.py:162
+#: ../melon/widgets/preferencerow.py:163
msgid "Add Item"
msgstr ""
-#: ../melon/widgets/preferencerow.py:165
+#: ../melon/widgets/preferencerow.py:166
msgid "Create a new list entry"
msgstr ""
-#: ../melon/widgets/preferencerow.py:166
+#: ../melon/widgets/preferencerow.py:167
msgid "Enter the new value here"
msgstr ""
-#: ../melon/widgets/preferencerow.py:169
+#: ../melon/widgets/preferencerow.py:170
msgid "Value"
msgstr ""
-#: ../melon/widgets/preferencerow.py:209
+#: ../melon/widgets/preferencerow.py:210
msgid "Do you really want to delete this item?"
msgstr ""
-#: ../melon/widgets/preferencerow.py:210
+#: ../melon/widgets/preferencerow.py:211
msgid "You won't be able to restore it afterwards"
msgstr ""
-#: ../melon/widgets/preferencerow.py:217
+#: ../melon/widgets/preferencerow.py:218
msgid "Do not remove item"
msgstr ""
-#: ../melon/widgets/preferencerow.py:218
+#: ../melon/widgets/preferencerow.py:219
msgid "Remove item from list"
msgstr ""
-#: ../melon/window.py:76
+#: ../melon/window.py:84
msgid "Stream videos on the go"
msgstr ""