mirror of
https://github.com/DYefremov/DemonEditor.git
synced 2026-01-22 07:23:24 +01:00
improved built-in player [added windowed mode]
This commit is contained in:
@@ -10,10 +10,10 @@ from app.settings import PlayStreamsMode
|
||||
|
||||
|
||||
class Player:
|
||||
""" Simple wrapper for VLC media player. """
|
||||
__VLC_INSTANCE = None
|
||||
__PLAY_STREAMS_MODE = PlayStreamsMode.BUILT_IN
|
||||
|
||||
def __init__(self, rewind_callback, position_callback, error_callback, playing_callback):
|
||||
def __init__(self, mode, rewind_cb, position_cb, error_cb, playing_cb):
|
||||
try:
|
||||
from app.tools import vlc
|
||||
from app.tools.vlc import EventType
|
||||
@@ -21,39 +21,39 @@ class Player:
|
||||
log("{}: Load library error: {}".format(__class__.__name__, e))
|
||||
raise ImportError
|
||||
else:
|
||||
self._mode = mode
|
||||
self._is_playing = False
|
||||
args = "--quiet {}".format("" if sys.platform == "darwin" else "--no-xlib")
|
||||
self._player = vlc.Instance(args).media_player_new()
|
||||
ev_mgr = self._player.event_manager()
|
||||
|
||||
if rewind_callback:
|
||||
if rewind_cb:
|
||||
# TODO look other EventType options
|
||||
ev_mgr.event_attach(EventType.MediaPlayerBuffering,
|
||||
lambda et, p: rewind_callback(p.get_media().get_duration()),
|
||||
lambda et, p: rewind_cb(p.get_media().get_duration()),
|
||||
self._player)
|
||||
if position_callback:
|
||||
if position_cb:
|
||||
ev_mgr.event_attach(EventType.MediaPlayerTimeChanged,
|
||||
lambda et, p: position_callback(p.get_time()),
|
||||
lambda et, p: position_cb(p.get_time()),
|
||||
self._player)
|
||||
|
||||
if error_callback:
|
||||
if error_cb:
|
||||
ev_mgr.event_attach(EventType.MediaPlayerEncounteredError,
|
||||
lambda et, p: error_callback(),
|
||||
lambda et, p: error_cb(),
|
||||
self._player)
|
||||
if playing_callback:
|
||||
if playing_cb:
|
||||
ev_mgr.event_attach(EventType.MediaPlayerPlaying,
|
||||
lambda et, p: playing_callback(),
|
||||
lambda et, p: playing_cb(),
|
||||
self._player)
|
||||
|
||||
@classmethod
|
||||
def get_instance(cls, rewind_callback=None, position_callback=None, error_callback=None, playing_callback=None):
|
||||
def get_instance(cls, mode, rewind_cb=None, position_cb=None, error_cb=None, playing_cb=None):
|
||||
if not cls.__VLC_INSTANCE:
|
||||
cls.__VLC_INSTANCE = Player(rewind_callback, position_callback, error_callback, playing_callback)
|
||||
cls.__VLC_INSTANCE = Player(mode, rewind_cb, position_cb, error_cb, playing_cb)
|
||||
return cls.__VLC_INSTANCE
|
||||
|
||||
@staticmethod
|
||||
def get_play_mode():
|
||||
return Player.__PLAY_STREAMS_MODE
|
||||
def get_play_mode(self):
|
||||
return self._mode
|
||||
|
||||
@run_task
|
||||
def play(self, mrl=None):
|
||||
@@ -80,6 +80,7 @@ class Player:
|
||||
self._is_playing = False
|
||||
self._player.stop()
|
||||
self._player.release()
|
||||
self.__VLC_INSTANCE = None
|
||||
|
||||
def set_xwindow(self, xid):
|
||||
self._player.set_xwindow(xid)
|
||||
@@ -115,7 +116,10 @@ class Player:
|
||||
|
||||
|
||||
class HttpPlayer:
|
||||
""" Simple wrapper for VLC media player to interact over http. """
|
||||
""" Simple wrapper for VLC media player to interact over http.
|
||||
|
||||
NOT used anymore! May be deleted in the future!
|
||||
"""
|
||||
|
||||
__VLC_INSTANCE = None
|
||||
__PLAY_STREAMS_MODE = PlayStreamsMode.VLC
|
||||
|
||||
@@ -18,7 +18,7 @@ from app.eparser.enigma.bouquets import BqServiceType
|
||||
from app.eparser.iptv import export_to_m3u
|
||||
from app.eparser.neutrino.bouquets import BqType
|
||||
from app.settings import SettingsType, Settings, SettingsException, PlayStreamsMode, SettingsReadException
|
||||
from app.tools.media import Player, Recorder, HttpPlayer
|
||||
from app.tools.media import Player, Recorder
|
||||
from app.ui.epg_dialog import EpgDialog
|
||||
from app.ui.transmitter import LinksTransmitter
|
||||
from .backup import BackupDialog, backup_data, clear_data_path
|
||||
@@ -198,6 +198,7 @@ class Application(Gtk.Application):
|
||||
self._player = None
|
||||
self._full_screen = False
|
||||
self._current_mrl = None
|
||||
self._playback_window = None
|
||||
# Record
|
||||
self._recorder = None
|
||||
# http api
|
||||
@@ -1867,6 +1868,7 @@ class Application(Gtk.Application):
|
||||
|
||||
def on_bouquets_selection(self, model, path, column):
|
||||
self.reset_view_sort_indication(self._fav_view)
|
||||
self._alt_revealer.set_visible(False)
|
||||
self._current_bq_name = model[path][0] if len(path) > 1 else None
|
||||
self._bq_name_label.set_text(self._current_bq_name if self._current_bq_name else "")
|
||||
|
||||
@@ -2441,30 +2443,34 @@ class Application(Gtk.Application):
|
||||
self.save_stream_to_m3u(url)
|
||||
return
|
||||
|
||||
if self._player and self._player.get_play_mode() is not mode:
|
||||
self.show_error_dialog("Play mode has been changed!\nRestart the program to apply the settings.")
|
||||
self.set_playback_elms_active()
|
||||
return
|
||||
|
||||
if mode is PlayStreamsMode.VLC:
|
||||
try:
|
||||
if self._player and self._player.get_play_mode() is not mode:
|
||||
self._player.release()
|
||||
self._player = None
|
||||
if not self._player:
|
||||
self._player = HttpPlayer.get_instance(self._settings)
|
||||
except ImportError:
|
||||
self.show_error_dialog("No VLC is found. Check that it is installed!")
|
||||
else:
|
||||
self._player.play(url)
|
||||
self._current_mrl = url
|
||||
self.show_playback_window()
|
||||
elif self._playback_window:
|
||||
title = self.get_playback_title()
|
||||
GLib.idle_add(self._playback_window.set_title, title)
|
||||
GLib.idle_add(self._player.play, url, priority=GLib.PRIORITY_LOW)
|
||||
GLib.idle_add(self._playback_window.show)
|
||||
else:
|
||||
self.show_error_dialog("Init player error!")
|
||||
finally:
|
||||
self.set_playback_elms_active()
|
||||
else:
|
||||
if not self._player_box.get_visible():
|
||||
self.set_player_area_size(self._player_box)
|
||||
if not self._player:
|
||||
self._current_mrl = url
|
||||
self._player_box.set_visible(True)
|
||||
else:
|
||||
if not self._player_box.get_visible():
|
||||
self.set_player_area_size(self._player_box)
|
||||
|
||||
if self._player and self._player.get_play_mode() is PlayStreamsMode.BUILT_IN:
|
||||
GLib.idle_add(self._player.play, url, priority=GLib.PRIORITY_LOW)
|
||||
elif self._player:
|
||||
self.show_error_dialog("Play mode has been changed!\nRestart the program to apply the settings.")
|
||||
self.set_playback_elms_active()
|
||||
self._player_box.set_visible(True)
|
||||
|
||||
def on_player_stop(self, item=None):
|
||||
if self._player:
|
||||
@@ -2497,12 +2503,17 @@ class Application(Gtk.Application):
|
||||
self._player_prev_button.set_sensitive(current_index != 0)
|
||||
self._player_next_button.set_sensitive(len(self._fav_model) != current_index + 1)
|
||||
|
||||
def on_player_close(self, item=None):
|
||||
def on_player_close(self, window=None, event=None):
|
||||
if self._player:
|
||||
self._player.stop()
|
||||
|
||||
self.set_playback_elms_active()
|
||||
GLib.idle_add(self._player_box.set_visible, False, priority=GLib.PRIORITY_LOW)
|
||||
if self._playback_window:
|
||||
self._settings.add("playback_window_size", self._playback_window.get_size())
|
||||
self._playback_window.hide()
|
||||
else:
|
||||
GLib.idle_add(self._player_box.set_visible, False, priority=GLib.PRIORITY_LOW)
|
||||
return True
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def on_player_duration_changed(self, duration):
|
||||
@@ -2532,14 +2543,13 @@ class Application(Gtk.Application):
|
||||
return "{}{:02d}:{:02d}".format(str(h) + ":" if h else "", m, s)
|
||||
|
||||
def on_drawing_area_realize(self, widget):
|
||||
self.set_player_area_size(widget)
|
||||
|
||||
if not self._player:
|
||||
try:
|
||||
self._player = Player.get_instance(rewind_callback=self.on_player_duration_changed,
|
||||
position_callback=self.on_player_time_changed,
|
||||
error_callback=self.on_player_error,
|
||||
playing_callback=self.set_playback_elms_active)
|
||||
self._player = Player.get_instance(mode=self._settings.play_streams_mode,
|
||||
rewind_cb=self.on_player_duration_changed,
|
||||
position_cb=self.on_player_time_changed,
|
||||
error_cb=self.on_player_error,
|
||||
playing_cb=self.set_playback_elms_active)
|
||||
except (ImportError, NameError, AttributeError):
|
||||
self.show_error_dialog("No VLC is found. Check that it is installed!")
|
||||
return True
|
||||
@@ -2551,7 +2561,10 @@ class Application(Gtk.Application):
|
||||
self._player.play(self._current_mrl)
|
||||
finally:
|
||||
self.set_playback_elms_active()
|
||||
if self._settings.play_streams_mode is PlayStreamsMode.BUILT_IN:
|
||||
self.set_player_area_size(widget)
|
||||
|
||||
@run_idle
|
||||
def set_player_area_size(self, widget):
|
||||
w, h = self._main_window.get_size()
|
||||
widget.set_size_request(w * 0.6, -1)
|
||||
@@ -2579,8 +2592,12 @@ class Application(Gtk.Application):
|
||||
|
||||
def on_full_screen(self, item=None):
|
||||
self._full_screen = not self._full_screen
|
||||
self.update_state_on_full_screen(not self._full_screen)
|
||||
self._main_window.fullscreen() if self._full_screen else self._main_window.unfullscreen()
|
||||
if self._settings.play_streams_mode is PlayStreamsMode.BUILT_IN:
|
||||
self.update_state_on_full_screen(not self._full_screen)
|
||||
self._main_window.fullscreen() if self._full_screen else self._main_window.unfullscreen()
|
||||
elif self._playback_window:
|
||||
self._player_tool_bar.set_visible(not self._full_screen)
|
||||
self._playback_window.fullscreen() if self._full_screen else self._playback_window.unfullscreen()
|
||||
|
||||
@run_idle
|
||||
def update_state_on_full_screen(self, visible):
|
||||
@@ -2588,6 +2605,40 @@ class Application(Gtk.Application):
|
||||
self._player_tool_bar.set_visible(visible)
|
||||
self._status_bar_box.set_visible(visible and not self._app_info_box.get_visible())
|
||||
|
||||
@run_idle
|
||||
def show_playback_window(self):
|
||||
width, height = 480, 240
|
||||
size = self._settings.get("playback_window_size")
|
||||
if size:
|
||||
width, height = size
|
||||
|
||||
self._playback_window = Gtk.Window(title=self.get_playback_title(),
|
||||
window_position=Gtk.WindowPosition.CENTER,
|
||||
gravity=Gdk.Gravity.CENTER,
|
||||
icon_name="demon-editor")
|
||||
self._playback_window.resize(width, height)
|
||||
self._playback_window.connect("delete-event", self.on_player_close)
|
||||
|
||||
if self._settings.is_darwin:
|
||||
self._player_drawing_area.reparent(self._playback_window)
|
||||
else:
|
||||
self._player_prev_button.set_visible(False)
|
||||
self._player_next_button.set_visible(False)
|
||||
box = Gtk.HBox(visible=True, orientation="vertical")
|
||||
self._player_drawing_area.reparent(box)
|
||||
self._player_box.remove(self._player_tool_bar)
|
||||
box.pack_end(self._player_tool_bar, False, False, 0)
|
||||
self._playback_window.add(box)
|
||||
|
||||
self._playback_window.set_application(self)
|
||||
self._playback_window.show()
|
||||
|
||||
def get_playback_title(self):
|
||||
path, column = self._fav_view.get_cursor()
|
||||
if path:
|
||||
return "DemonEditor [{}]".format(self._fav_model[path][:][Column.FAV_SERVICE])
|
||||
return "DemonEditor [Playback]"
|
||||
|
||||
# ************************* Record ***************************** #
|
||||
|
||||
def on_record(self, button):
|
||||
@@ -2675,7 +2726,7 @@ class Application(Gtk.Application):
|
||||
|
||||
def on_watch(self, item=None):
|
||||
""" Switch to the channel and watch in the player """
|
||||
if self._app_info_box.get_visible() and self._settings.play_streams_mode is PlayStreamsMode.BUILT_IN:
|
||||
if not self._app_info_box.get_visible() and self._settings.play_streams_mode is PlayStreamsMode.BUILT_IN:
|
||||
self.set_player_area_size(self._player_box)
|
||||
self._player_box.set_visible(True)
|
||||
GLib.idle_add(self._app_info_box.set_visible, False)
|
||||
@@ -2731,6 +2782,11 @@ class Application(Gtk.Application):
|
||||
if self._player and self._player.is_playing():
|
||||
self._player.stop()
|
||||
|
||||
# IPTV type checking
|
||||
row = self._fav_model[path][:]
|
||||
if row[Column.FAV_TYPE] == BqServiceType.IPTV.name and callback:
|
||||
callback = self.play(get_iptv_url(row, self._s_type))
|
||||
|
||||
def zap(rq):
|
||||
if rq and rq.get("e2state", False):
|
||||
GLib.idle_add(scroll_to, path, self._fav_view)
|
||||
@@ -2752,8 +2808,11 @@ class Application(Gtk.Application):
|
||||
return
|
||||
|
||||
srv = self._services.get(fav_id, None)
|
||||
if srv and srv.transponder or srv_type == BqServiceType.IPTV.name:
|
||||
return srv.picon_id.rstrip(".png").replace("_", ":")
|
||||
if srv:
|
||||
if srv_type == BqServiceType.IPTV.name:
|
||||
return srv.fav_id.strip()
|
||||
elif srv.picon_id:
|
||||
return srv.picon_id.rstrip(".png").replace("_", ":")
|
||||
|
||||
def update_info(self):
|
||||
""" Updating current info over HTTP API """
|
||||
|
||||
Reference in New Issue
Block a user