def __init__(self): self._video = None mpv_options = OrderedDict() mpv_location = settings.mpv_ext_path # Use bundled path for MPV if not specified by user, on Mac OS, and frozen if (mpv_location is None and platform.system() == "Darwin" and getattr(sys, "frozen", False)): mpv_location = get_resource("mpv") self.timeline_trigger = None self.action_trigger = None self.external_subtitles = {} self.external_subtitles_rev = {} self.should_send_timeline = False self.start_time = None self.url = None self.evt_queue = Queue() self._lock = RLock() self._tl_lock = RLock() self._finished_lock = Lock() self.last_update = Timer() self._jf_settings = None self.get_webview = lambda: None self.pause_ignore = None # Used to ignore pause events that come from us. self.do_not_handle_pause = False self.last_seek = None self.warned_about_transcode = False self.fullscreen_disable = False self.update_check = UpdateChecker(self) if is_using_ext_mpv: mpv_options.update({ "start_mpv": settings.mpv_ext_start, "ipc_socket": settings.mpv_ext_ipc, "mpv_location": mpv_location, "player-operation-mode": "cplayer", }) if settings.menu_mouse: if is_using_ext_mpv: mpv_options["script"] = get_resource("mouse.lua") else: mpv_options["scripts"] = get_resource("mouse.lua") if not (settings.mpv_ext and settings.mpv_ext_no_ovr): mpv_options["include"] = conffile.get(APP_NAME, "mpv.conf", True) mpv_options["input_conf"] = conffile.get(APP_NAME, "input.conf", True) self._player = mpv.MPV(input_default_bindings=True, input_vo_keyboard=True, input_media_keys=settings.media_keys, log_handler=mpv_log_handler, loglevel=settings.mpv_log_level, **mpv_options) self.menu = OSDMenu(self, self._player) self.syncplay = SyncPlayManager(self) if hasattr(self._player, "osc"): self._player.osc = settings.enable_osc else: log.warning( "This mpv version doesn't support on-screen controller.") if settings.screenshot_dir is not None: if hasattr(self._player, "screenshot_directory"): self._player.screenshot_directory = settings.screenshot_dir else: log.warning( "This mpv version doesn't support setting the screenshot directory." ) # Wrapper for on_key_press that ignores None. def keypress(key): def wrapper(func): if key is not None: self._player.on_key_press(key)(func) return func return wrapper @self._player.on_key_press("CLOSE_WIN") @self._player.on_key_press("STOP") @keypress(settings.kb_stop) def handle_stop(): self.stop() @keypress(settings.kb_prev) def handle_prev(): self.put_task(self.play_prev) @keypress(settings.kb_next) def handle_next(): self.put_task(self.play_next) @self._player.on_key_press("PREV") @self._player.on_key_press("XF86_PREV") def handle_media_prev(): if settings.media_key_seek: seektime, _x = self.get_seek_times() self.seek(seektime) else: self.put_task(self.play_prev) @self._player.on_key_press("NEXT") @self._player.on_key_press("XF86_NEXT") def handle_media_next(): if settings.media_key_seek: _x, seektime = self.get_seek_times() self.seek(seektime) else: self.put_task(self.play_next) @keypress(settings.kb_watched) def handle_watched(): self.put_task(self.watched_skip) @keypress(settings.kb_unwatched) def handle_unwatched(): self.put_task(self.unwatched_quit) @keypress(settings.kb_menu) def menu_open(): if not self.menu.is_menu_shown: self.menu.show_menu() else: self.menu.hide_menu() @keypress(settings.kb_menu_esc) def menu_back(): if self.menu.is_menu_shown: self.menu.menu_action("back") else: self._player.command("set", "fullscreen", "no") self.fullscreen_disable = True @keypress(settings.kb_menu_ok) def menu_ok(): self.menu.menu_action("ok") @keypress(settings.kb_menu_left) def menu_left(): if self.menu.is_menu_shown: self.menu.menu_action("left") else: self.kb_seek("left") @keypress(settings.kb_menu_right) def menu_right(): if self.menu.is_menu_shown: self.menu.menu_action("right") else: self.kb_seek("right") @keypress(settings.kb_menu_up) def menu_up(): if self.menu.is_menu_shown: self.menu.menu_action("up") else: self.kb_seek("up") @keypress(settings.kb_menu_down) def menu_down(): if self.menu.is_menu_shown: self.menu.menu_action("down") else: self.kb_seek("down") @keypress(settings.kb_pause) def handle_pause(): if self.menu.is_menu_shown: self.menu.menu_action("ok") else: self.toggle_pause() @keypress(settings.kb_fullscreen) def handle_fullscreen(): self.toggle_fullscreen() # This gives you an interactive python debugger prompt. @keypress(settings.kb_debug) def handle_debug(): import pdb pdb.set_trace() # Kill shader packs (useful for breakage) @keypress(settings.kb_kill_shader) def kill_shaders(): if settings.shader_pack_remember: settings.shader_pack_profile = None settings.save() if self.menu.profile_manager is not None: self.menu.profile_manager.unload_profile() # Fires between episodes. @self._player.property_observer("eof-reached") def handle_end(_name, reached_end: bool): self.pause_ignore = True if self._video and reached_end: has_lock = self._finished_lock.acquire(False) self.put_task(self.finished_callback, has_lock) # Fires at the end. @self._player.property_observer("playback-abort") def handle_end_idle(_name, value: bool): self.pause_ignore = True if self._video and value: has_lock = self._finished_lock.acquire(False) self.put_task(self.finished_callback, has_lock) @self._player.property_observer("seeking") def handle_seeking(_name, value: bool): if self.do_not_handle_pause: return if self.syncplay.is_enabled(): play_time = self._player.playback_time if (play_time is not None and self.last_seek is not None and abs(self.last_seek - play_time) > 10): self.syncplay.seek_request(play_time) else: log.debug("SyncPlay Buffering: {0}".format(value)) if value: self.syncplay.on_buffer() else: self.syncplay.on_buffer_done() @self._player.property_observer("pause") def pause_handler(_name, value: bool): if self.do_not_handle_pause: return if not self._player.playback_abort: self.timeline_handle() if value != self.pause_ignore: if self.syncplay.is_enabled(): if value: self.syncplay.pause_request() else: # Don't allow unpausing locally through MPV. self.syncplay.play_request() self.set_paused(True, True) @self._player.event_callback("client-message") def handle_client_message(event): try: if "event_id" in event: args = event["event"]["args"] else: args = event["args"] if len(args) == 0: return if args[0] == "shim-menu-select": # Apparently this can happen... if args[1] == "inf": return self.menu.mouse_select(int(args[1])) elif args[0] == "shim-menu-click": self.menu.menu_action("ok") except Exception: log.warning("Error when processing client-message.", exc_info=True)
def __init__(self): mpv_config = conffile.get(APP_NAME, "mpv.conf", True) input_config = conffile.get(APP_NAME, "input.conf", True) self._video = None extra_options = {} self.timeline_trigger = None self.action_trigger = None self.external_subtitles = {} self.external_subtitles_rev = {} self.should_send_timeline = False self.start_time = None self.url = None self.evt_queue = Queue() self._lock = RLock() self._tl_lock = RLock() self.last_update = Timer() self._jf_settings = None self.get_webview = lambda: None if is_using_ext_mpv: extra_options = { "start_mpv": settings.mpv_ext_start, "ipc_socket": settings.mpv_ext_ipc, "mpv_location": settings.mpv_ext_path, "player-operation-mode": "cplayer" } self._player = mpv.MPV(input_default_bindings=True, input_vo_keyboard=True, input_media_keys=True, include=mpv_config, input_conf=input_config, log_handler=mpv_log_handler, loglevel=settings.mpv_log_level, **extra_options) self.menu = OSDMenu(self) if hasattr(self._player, 'osc'): self._player.osc = settings.enable_osc else: log.warning( "This mpv version doesn't support on-screen controller.") @self._player.on_key_press('CLOSE_WIN') @self._player.on_key_press('STOP') @self._player.on_key_press('q') def handle_stop(): self.stop() @self._player.on_key_press('<') def handle_prev(): self.put_task(self.play_prev) @self._player.on_key_press('>') def handle_next(): self.put_task(self.play_next) @self._player.on_key_press('PREV') @self._player.on_key_press('XF86_PREV') def handle_media_prev(): if settings.media_key_seek: seektime, _ = self.get_seek_times() self._player.command("seek", seektime) else: self.put_task(self.play_prev) @self._player.on_key_press('NEXT') @self._player.on_key_press('XF86_NEXT') def handle_media_next(): if settings.media_key_seek: _, seektime = self.get_seek_times() self._player.command("seek", seektime) else: self.put_task(self.play_next) @self._player.on_key_press('w') def handle_watched(): self.put_task(self.watched_skip) @self._player.on_key_press('u') def handle_unwatched(): self.put_task(self.unwatched_quit) @self._player.on_key_press('c') def menu_open(): if not self.menu.is_menu_shown: self.menu.show_menu() else: self.menu.hide_menu() @self._player.on_key_press('esc') def menu_back(): self.menu.menu_action('back') @self._player.on_key_press('enter') def menu_ok(): self.menu.menu_action('ok') @self._player.on_key_press('left') def menu_left(): if self.menu.is_menu_shown: self.menu.menu_action('left') else: seektime = -5 if settings.use_web_seek: seektime, _ = self.get_seek_times() self._player.command("seek", seektime) @self._player.on_key_press('right') def menu_right(): if self.menu.is_menu_shown: self.menu.menu_action('right') else: seektime = 5 if settings.use_web_seek: _, seektime = self.get_seek_times() self._player.command("seek", seektime) @self._player.on_key_press('up') def menu_up(): if self.menu.is_menu_shown: self.menu.menu_action('up') else: self._player.command("seek", 60) @self._player.on_key_press('down') def menu_down(): if self.menu.is_menu_shown: self.menu.menu_action('down') else: self._player.command("seek", -60) @self._player.on_key_press('space') def handle_pause(): if self.menu.is_menu_shown: self.menu.menu_action('ok') else: self.toggle_pause() # This gives you an interactive python debugger prompt. @self._player.on_key_press('~') def handle_debug(): import pdb pdb.set_trace() # Fires between episodes. @self._player.property_observer('eof-reached') def handle_end(_name, reached_end): if self._video and reached_end: self.put_task(self.finished_callback) # Fires at the end. @self._player.event_callback('idle') def handle_end_idle(event): if self._video: self.put_task(self.finished_callback)
def test_python_stream(self): handler = mock.Mock() disp = Xvfb() disp.start() m = mpv.MPV() m.register_event_callback(handler) @m.python_stream('foo') def foo_gen(): with open(TESTVID, 'rb') as f: yield f.read() @m.python_stream('bar') def bar_gen(): yield b'' m.play('python://foo') m.wait_for_playback() handler.assert_any_call({ 'reply_userdata': 0, 'error': 0, 'event_id': mpv.MpvEventID.END_FILE, 'event': { 'reason': mpv.MpvEventEndFile.EOF, 'error': mpv.ErrorCode.SUCCESS } }) handler.reset_mock() m.play('python://bar') m.wait_for_playback() handler.assert_any_call({ 'reply_userdata': 0, 'error': 0, 'event_id': mpv.MpvEventID.END_FILE, 'event': { 'reason': mpv.MpvEventEndFile.ERROR, 'error': mpv.ErrorCode.UNKNOWN_FORMAT } }) handler.reset_mock() m.play('python://baz') m.wait_for_playback() handler.assert_any_call({ 'reply_userdata': 0, 'error': 0, 'event_id': mpv.MpvEventID.END_FILE, 'event': { 'reason': mpv.MpvEventEndFile.ERROR, 'error': mpv.ErrorCode.LOADING_FAILED } }) handler.reset_mock() m.play('foo://foo') m.wait_for_playback() handler.assert_any_call({ 'reply_userdata': 0, 'error': 0, 'event_id': mpv.MpvEventID.END_FILE, 'event': { 'reason': mpv.MpvEventEndFile.ERROR, 'error': mpv.ErrorCode.LOADING_FAILED } }) handler.reset_mock() foo_gen.unregister() m.play('python://foo') m.wait_for_playback() handler.assert_any_call({ 'reply_userdata': 0, 'error': 0, 'event_id': mpv.MpvEventID.END_FILE, 'event': { 'reason': mpv.MpvEventEndFile.ERROR, 'error': mpv.ErrorCode.LOADING_FAILED } }) handler.reset_mock() m.play('python://bar') m.wait_for_playback() handler.assert_any_call({ 'reply_userdata': 0, 'error': 0, 'event_id': mpv.MpvEventID.END_FILE, 'event': { 'reason': mpv.MpvEventEndFile.ERROR, 'error': mpv.ErrorCode.UNKNOWN_FORMAT } }) handler.reset_mock() m.terminate() disp.stop()
def test_flags(self): with self.assertRaises(AttributeError): mpv.MPV('this-option-does-not-exist') m = mpv.MPV('no-video', 'cursor-autohide-fs-only', 'fs') self.assertTrue(m.fullscreen) self.assertEqual(m.cursor_autohide, '1000')
from flask import Flask, render_template import mpv from flask_socketio import SocketIO, emit app = Flask(__name__) socketio = SocketIO(app, cors_allowed_origins='*') player: mpv.MPV = mpv.MPV(ytdl=True) def on_volume_change(_, value: float): socketio.emit('volumeChanged', {'value': value}) player.observe_property("volume", on_volume_change) @socketio.on('volume', namespace='/command') def volume_change(data): global player try: player._set_property('volume', data['value']) emit('log', { 'message': f'Volume changed to {data["value"]}', 'type': 'info' }) except KeyError: emit('log', {'message': 'No volume value provided', 'type': 'error'})
def setup_video_player(self, player_id): mpv_player = mpv.MPV(border=False, ontop=False, osc="yes", loop_file="yes", aid="no") if player_id == 1: self.main_player_1 = mpv_player elif player_id == 2: self.main_player_2 = mpv_player
import tkinter as tk import os import mpv p = mpv.MPV() p.volume = 50 p.loop = 'inf' names = [] sampleFolder = 'sourceSamples' blocksize = 1024 * 10 textSource = open('transcript.txt', 'r') for fn in os.listdir(sampleFolder): if '.wav' in fn: base = os.path.join(sampleFolder, fn.replace('.wav', '')) if os.path.exists(base + '.png'): names.append(base) print(base) names = sorted(names, reverse=True, key=lambda x: int(x.replace(sampleFolder + '\\Zaud', ''))) root = tk.Tk() currentFile = None txt = tk.Text(root, height=50, width=80)
def __init__(self, parent): QW.QWidget.__init__(self, parent) self._canvas_type = ClientGUICommon.CANVAS_PREVIEW self._stop_for_slideshow = False # This is necessary since PyQT stomps over the locale settings needed by libmpv. # This needs to happen after importing PyQT before creating the first mpv.MPV instance. locale.setlocale(locale.LC_NUMERIC, 'C') self.setAttribute(QC.Qt.WA_DontCreateNativeAncestors) self.setAttribute(QC.Qt.WA_NativeWindow) # loglevels: fatal, error, debug self._player = mpv.MPV(wid=str(int(self.winId())), log_handler=print, loglevel='fatal') # hydev notes on OSC: # OSC is by default off, default input bindings are by default off # difficult to get this to intercept mouse/key events naturally, so you have to pipe them to the window with 'command', but this is not excellent # general recommendation when using libmpv is to just implement your own stuff anyway, so let's do that for prototype #self._player[ 'input-default-bindings' ] = True self.UpdateConf() #self._player.osc = True #Set to enable the mpv UI. Requires that mpv captures mouse/key events, otherwise it won't work. self._player.loop = True # this makes black screen for audio (rather than transparent) self._player.force_window = True # this actually propagates up to the OS-level sound mixer lmao, otherwise defaults to ugly hydrus filename self._player.title = 'hydrus mpv player' # this is telling ffmpeg to do audio normalization. play with it more and put it in default mpv.conf # it doesn't seem to apply at all for some files--maybe a vp9 issue or something? #self._player.af = 'lavfi=[dynaudnorm=p=0.9]' self.setMouseTracking(True) #Needed to get mouse move events #self.setFocusPolicy(QC.Qt.StrongFocus)#Needed to get key events self._player.input_cursor = False #Disable mpv mouse move/click event capture self._player.input_vo_keyboard = False #Disable mpv key event capture, might also need to set input_x11_keyboard self._media = None self._times_to_play_gif = 0 self._current_seek_to_start_count = 0 player = self._player def qt_seek_event(): if not QP.isValid(self): return if self._media is not None and self._player.time_pos <= 1.0: self._current_seek_to_start_count += 1 if self._stop_for_slideshow: self.Pause() if self._times_to_play_gif != 0 and self._current_seek_to_start_count >= self._times_to_play_gif: self.Pause() @player.event_callback(mpv.MpvEventID.SEEK) def seek_event(event): QP.CallAfter(qt_seek_event) self.destroyed.connect(self._player.terminate) HG.client_controller.sub(self, 'UpdateAudioMute', 'new_audio_mute') HG.client_controller.sub(self, 'UpdateAudioVolume', 'new_audio_volume') HG.client_controller.sub(self, 'UpdateConf', 'notify_new_options') self._my_shortcut_handler = ClientGUIShortcuts.ShortcutsHandler( self, [], catch_mouse=True)
def __init__(self): mpv_config = conffile.get(APP_NAME, "mpv.conf", True) self._player = mpv.MPV(input_default_bindings=True, input_vo_keyboard=True, include=mpv_config) self.timeline_trigger = None self.action_trigger = None self.external_subtitles = {} self.external_subtitles_rev = {} self.menu = OSDMenu(self) if hasattr(self._player, 'osc'): self._player.osc = True else: log.warning( "This mpv version doesn't support on-screen controller.") self.url = None self.evt_queue = Queue() @self._player.on_key_press('q') def handle_stop(): self.stop() self.timeline_handle() @self._player.on_key_press('<') def handle_prev(): self.put_task(self.play_prev) @self._player.on_key_press('>') def handle_next(): self.put_task(self.play_next) @self._player.on_key_press('w') def handle_watched(): self.put_task(self.watched_skip) @self._player.on_key_press('u') def handle_unwatched(): self.put_task(self.unwatched_quit) @self._player.on_key_press('c') def menu_open(): if not self.menu.is_menu_shown: self.menu.show_menu() else: self.menu.hide_menu() @self._player.on_key_press('esc') def menu_back(): self.menu.menu_action('back') @self._player.on_key_press('enter') def menu_ok(): self.menu.menu_action('ok') @self._player.on_key_press('left') def menu_left(): if self.menu.is_menu_shown: self.menu.menu_action('left') else: self._player.command("seek", -5) @self._player.on_key_press('right') def menu_right(): if self.menu.is_menu_shown: self.menu.menu_action('right') else: self._player.command("seek", 5) @self._player.on_key_press('up') def menu_up(): if self.menu.is_menu_shown: self.menu.menu_action('up') else: self._player.command("seek", 60) @self._player.on_key_press('down') def menu_down(): if self.menu.is_menu_shown: self.menu.menu_action('down') else: self._player.command("seek", -60) @self._player.on_key_press('space') def handle_pause(): if self.menu.is_menu_shown: self.menu.menu_action('ok') else: self.toggle_pause() # This gives you an interactive python debugger prompt. @self._player.on_key_press('~') def handle_debug(): import pdb pdb.set_trace() @self._player.event_callback('idle') def handle_end(event): if self._video: self.put_task(self.finished_callback) self._video = None self._lock = RLock() self.last_update = Timer() self.__part = 1
def __init__(self): mpv_config = conffile.get(APP_NAME,"mpv.conf", True) input_config = conffile.get(APP_NAME,"input.conf", True) extra_options = {} self._video = None self._lock = RLock() self._finished_lock = Lock() self.last_update = Timer() self.__part = 1 self.timeline_trigger = None self.action_trigger = None self.external_subtitles = {} self.external_subtitles_rev = {} self.url = None self.evt_queue = Queue() self.is_in_intro = False self.intro_has_triggered = False if is_using_ext_mpv: extra_options = { "start_mpv": settings.mpv_ext_start, "ipc_socket": settings.mpv_ext_ipc, "mpv_location": settings.mpv_ext_path, "player-operation-mode": "cplayer" } # todo figure out how to put these in a file extra_options = { 'script-opts': 'osc-layout=slimbox,osc-deadzonesize=.9,osc-valign=1.05', } self._player = mpv.MPV(input_default_bindings=True, input_vo_keyboard=True, input_media_keys=True, include=mpv_config, input_conf=input_config, log_handler=mpv_log_handler, loglevel=settings.mpv_log_level, **extra_options) self.menu = OSDMenu(self) self.auto_insert = False def on_new_sub(name, text): if not self.auto_insert: return if not text or not text.strip(): return pyperclip.copy(text.replace('\n', ' ')) self._player.observe_property('sub-text', on_new_sub) if hasattr(self._player, 'osc'): self._player.osc = settings.enable_osc else: log.warning("This mpv version doesn't support on-screen controller.") # Wrapper for on_key_press that ignores None. def keypress(key): def wrapper(func): if key is not None: self._player.on_key_press(key)(func) return func return wrapper @self._player.on_key_press('CLOSE_WIN') @self._player.on_key_press('STOP') @keypress(settings.kb_stop) def handle_stop(): self.stop() self.timeline_handle() @keypress(settings.kb_prev) def handle_prev(): self.put_task(self.play_prev) @keypress(settings.kb_next) def handle_next(): self.put_task(self.play_next) @self._player.on_key_press('PREV') @self._player.on_key_press('XF86_PREV') def handle_media_prev(): if settings.media_key_seek: self._player.command("seek", -15) else: self.put_task(self.play_prev) @self._player.on_key_press('NEXT') @self._player.on_key_press('XF86_NEXT') def handle_media_next(): if settings.media_key_seek: if self.is_in_intro: self.skip_intro() else: self._player.command("seek", 30) else: self.put_task(self.play_next) @keypress(settings.kb_watched) def handle_watched(): self.put_task(self.watched_skip) @keypress(settings.kb_unwatched) def handle_unwatched(): self.put_task(self.unwatched_quit) @keypress(settings.kb_menu) def menu_open(): if not self.menu.is_menu_shown: self.menu.show_menu() else: self.menu.hide_menu() @keypress(settings.kb_menu_esc) def menu_back(): if self.menu.is_menu_shown: self.menu.menu_action('back') else: self._player.command('set', 'fullscreen', 'no') @keypress(settings.kb_menu_ok) def menu_ok(): self.menu.menu_action('ok') @keypress(settings.kb_menu_left) def menu_left(): if self.menu.is_menu_shown: self.menu.menu_action('left') else: self._player.command("seek", settings.seek_left) @keypress(settings.kb_menu_right) def menu_right(): if self.menu.is_menu_shown: self.menu.menu_action('right') else: if self.is_in_intro: self.skip_intro() else: self._player.command("seek", settings.seek_right) @keypress(settings.kb_menu_up) def menu_up(): if self.menu.is_menu_shown: self.menu.menu_action('up') else: if self.is_in_intro: self.skip_intro() else: self._player.command("seek", settings.seek_up) @keypress(settings.kb_menu_down) def menu_down(): if self.menu.is_menu_shown: self.menu.menu_action('down') else: self._player.command("seek", settings.seek_down) @keypress(settings.kb_pause) def handle_pause(): if self.menu.is_menu_shown: self.menu.menu_action('ok') else: self.toggle_pause() # This gives you an interactive python debugger prompt. @keypress(settings.kb_debug) def handle_debug(): import pdb pdb.set_trace() @self._player.on_key_press('ctrl+c') def copy_current_sub(): try: sub = self._player.sub_text pyperclip.copy(sub) except AttributeError: pass # no subtitle available. def copy_screenshot(subtitles=True): includes = 'subtitles' if subtitles else 'video' from io import BytesIO import win32clipboard image = self._player.screenshot_raw(includes=includes) output = BytesIO() image.convert("RGB").save(output, "BMP") data = output.getvalue()[14:] output.close() win32clipboard.OpenClipboard() win32clipboard.EmptyClipboard() win32clipboard.SetClipboardData(win32clipboard.CF_DIB, data) win32clipboard.CloseClipboard() @self._player.on_key_press('ctrl+s') def copy_current_image(): copy_screenshot(subtitles=True) @self._player.on_key_press('ctrl+shift+s') def copy_current_image(): copy_screenshot(subtitles=False) @self._player.on_key_press('ctrl+v') def output_audio(): import subprocess import string import unicodedata sub_delay = round(self._player.sub_delay, 4) # round b/c of weird mpv precision sub_start = self._player.sub_start + sub_delay if sub_start: print("Outputting current subtitle...") valid_fn_chars = "-_.() %s%s" % (string.ascii_letters, string.digits) fn_dirty = "%s - %s" % (self._player.media_title, str(int(sub_start * 1000))) fn = unicodedata.normalize('NFKD', fn_dirty).encode('ASCII', 'ignore') fn = ''.join(chr(c) for c in fn if chr(c) in valid_fn_chars) aid = [x for x in self._player.track_list if x.get("type") == "audio" and x.get("selected")][0].get("id") subprocess.Popen([ 'mpv', self.url, '-o', '%s.mp3' % fn, '--no-video', '--start=%s' % sub_start, '--end=%s' % (self._player.sub_end + sub_delay), '--aid=%s' % aid, ]) self._player.screenshot_to_file("%s.png" % fn, includes='video') with open('%s.txt' % fn, 'w+', encoding='utf-8') as f: f.write(self._player.sub_text) @self._player.on_key_press('ctrl+a') def toggle_auto_insert(): self.auto_insert = not self.auto_insert self._player.show_text('Auto insert %s' % ("on" if self.auto_insert else "off")) # Fires between episodes. @self._player.property_observer('eof-reached') def handle_end(_name, reached_end): if self._video and reached_end: has_lock = self._finished_lock.acquire(False) self.put_task(self.finished_callback, has_lock) # Fires at the end. @self._player.event_callback('idle') def handle_end_idle(event): if self._video: has_lock = self._finished_lock.acquire(False) self.put_task(self.finished_callback, has_lock)
def setUp(self): self.disp = Xvfb() self.disp.start() self.m = mpv.MPV(vo='x11')
def startVideo(): gd.player = mpv.MPV() gd.player.pause = True gd.player.window_scale = 0.5 gd.video = True
def view_files(): player = mpv.MPV( autofit_larger= '100%x95%', # resize video if it's larger than W%xH% of the screen reset_on_next_file= 'pause', # reset pause status on next media in playlist loop_file='inf', # loop file in case of videos input_default_bindings=True, input_vo_keyboard=True) @player.on_key_press(DELETEKEY) def delete_file(): to_delete.append(current_video) try: player.playlist_next() except SystemError: print('Playlist finished!') player.quit() @player.on_key_press(NEXTFILEKEY) def next_file(): try: player.playlist_next() except SystemError: print("Playlist finished") # playlist finished player.quit() @player.on_key_press(ACCEPTKEY) def accept(): print(ACCEPTKEY) delete_files(to_delete) @player.on_key_press(FULLSCREENTOGGLE) def fullscreen_toggle(): print('fullscreen') player.fullscreen = not player.fullscreen player.fullscreen = True mediafiles = [ os.path.join(DIRNAME, file) for file in os.listdir(DIRNAME) if os.path.isfile(os.path.join(DIRNAME, file)) ] player.playlist_append( mediafiles[-1] ) # hack: last media is skipped, add it twice to make up for ite for video in mediafiles: player.playlist_append(video) player.playlist_pos = 0 playlist_len = len(player.playlist) while True: current_video = player.playlist[player.playlist_pos]['filename'] print("position: " + str(player.playlist_pos) + "/" + str(playlist_len - 1)) if player.playlist_pos >= playlist_len - 1: print("reached end of playlist") break else: player.wait_for_playback()
def setUp(self): self.disp = Xvfb() self.disp.start() self.m = mpv.MPV(vo=testvo, loglevel='debug', log_handler=timed_print())
from http.server import BaseHTTPRequestHandler, HTTPServer import time from urllib.parse import urlencode from urllib.request import Request, urlopen import codecs from subprocess import call from subprocess import Popen import mpv main = codecs.open("main.html", 'r', 'utf-8').read() hostName = "0.0.0.0" hostPort = 8888 player = mpv.MPV(ytdl=True) def ytLink(number): yt = ['https://www.youtube.com/watch?v=xxG2UWhvXJI', 'https://youtu.be/LO2RPDZkY88', 'https://youtu.be/jbt6UWc1ZKo', 'https://youtu.be/WC5FdFlUcl0'] intNum = int(number[1]) return(yt[intNum]) class MyServer(BaseHTTPRequestHandler): def do_GET(self): self.send_response(200) self.send_header("Content-type", "text/html") self.end_headers() self.wfile.write(bytes(main, "utf-8")) def do_POST(self): choice = ytLink(self.path) print(choice)
def __init__(self): mpv_config = conffile.get(APP_NAME,"mpv.conf", True) input_config = conffile.get(APP_NAME,"input.conf", True) extra_options = {} self._media_item = None self._lock = RLock() self._finished_lock = Lock() self.last_update = Timer() self.__part = 1 self.timeline_trigger = None self.action_trigger = None self.external_subtitles = {} self.external_subtitles_rev = {} self.url = None self.evt_queue = Queue() self.is_in_intro = False self.intro_has_triggered = False if is_using_ext_mpv: extra_options = { "start_mpv": settings.mpv_ext_start, "ipc_socket": settings.mpv_ext_ipc, "mpv_location": settings.mpv_ext_path, "player-operation-mode": "cplayer" } self._player = mpv.MPV(input_default_bindings=True, input_vo_keyboard=True, input_media_keys=True, include=mpv_config, input_conf=input_config, log_handler=mpv_log_handler, loglevel=settings.mpv_log_level, **extra_options) self.menu = OSDMenu(self) if hasattr(self._player, 'osc'): self._player.osc = settings.enable_osc else: log.warning("This mpv version doesn't support on-screen controller.") # Wrapper for on_key_press that ignores None. def keypress(key): def wrapper(func): if key is not None: self._player.on_key_press(key)(func) return func return wrapper @self._player.on_key_press('CLOSE_WIN') @self._player.on_key_press('STOP') @keypress(settings.kb_stop) def handle_stop(): self.stop() self.timeline_handle() @keypress(settings.kb_prev) def handle_prev(): self.put_task(self.play_prev) @keypress(settings.kb_next) def handle_next(): self.put_task(self.play_next) @self._player.on_key_press('PREV') @self._player.on_key_press('XF86_PREV') def handle_media_prev(): if settings.media_key_seek: self._player.command("seek", -15) else: self.put_task(self.play_prev) @self._player.on_key_press('NEXT') @self._player.on_key_press('XF86_NEXT') def handle_media_next(): if settings.media_key_seek: if self.is_in_intro: self.skip_intro() else: self._player.command("seek", 30) else: self.put_task(self.play_next) @keypress(settings.kb_watched) def handle_watched(): self.put_task(self.watched_skip) @keypress(settings.kb_unwatched) def handle_unwatched(): self.put_task(self.unwatched_quit) @keypress(settings.kb_menu) def menu_open(): if not self.menu.is_menu_shown: self.menu.show_menu() else: self.menu.hide_menu() @keypress(settings.kb_menu_esc) def menu_back(): if self.menu.is_menu_shown: self.menu.menu_action('back') else: self._player.command('set', 'fullscreen', 'no') @keypress(settings.kb_menu_ok) def menu_ok(): self.menu.menu_action('ok') @keypress(settings.kb_menu_left) def menu_left(): if self.menu.is_menu_shown: self.menu.menu_action('left') else: self._player.command("seek", settings.seek_left) @keypress(settings.kb_menu_right) def menu_right(): if self.menu.is_menu_shown: self.menu.menu_action('right') else: if self.is_in_intro: self.skip_intro() else: self._player.command("seek", settings.seek_right) @keypress(settings.kb_menu_up) def menu_up(): if self.menu.is_menu_shown: self.menu.menu_action('up') else: if self.is_in_intro: self.skip_intro() else: self._player.command("seek", settings.seek_up) @keypress(settings.kb_menu_down) def menu_down(): if self.menu.is_menu_shown: self.menu.menu_action('down') else: self._player.command("seek", settings.seek_down) @keypress(settings.kb_pause) def handle_pause(): if self.menu.is_menu_shown: self.menu.menu_action('ok') else: self.toggle_pause() # This gives you an interactive python debugger prompt. @keypress(settings.kb_debug) def handle_debug(): import pdb pdb.set_trace() # Fires between episodes. @self._player.property_observer('eof-reached') def handle_end(_name, reached_end): if self._media_item and reached_end: has_lock = self._finished_lock.acquire(False) self.put_task(self.finished_callback, has_lock) # Fires at the end. @self._player.event_callback('idle') def handle_end_idle(event): if self._media_item: has_lock = self._finished_lock.acquire(False) self.put_task(self.finished_callback, has_lock)
def load_stream_player(self, player): mpv_player = mpv.MPV(vf="crop=600:1080:500:0", geometry="+960+0", speed="1.1", no_correct_pts="yes", demuxer_thread="no", osc="yes", border=False, fps="60", ontop=False, profile="low-latency", cache="no", untimed="yes", rtsp_transport="tcp", aid="no", input_vo_keyboard=True, brightness="0") if player == 1: self.main_player_1 = mpv_player elif player == 2: self.main_player_2 = mpv_player
#import mpv #player = mpv.MPV(ytdl=True) #player.play('https://youtu.be/DOmdB7D-pUU') #!/usr/bin/env python3 import mpv def my_log(loglevel, component, message): print('[{}] {}: {}'.format(loglevel, component, message)) player = mpv.MPV(log_handler=my_log, ytdl=True, input_default_bindings=True, input_vo_keyboard=True) # Property access, these can be changed at runtime @player.property_observer('time-pos') def time_observer(_name, value): # Here, _value is either None if nothing is playing or a float containing # fractional seconds since the beginning of the file. print('Now playing at {:.2f}s'.format(value)) player.fullscreen = True player.loop_playlist = 'inf' # Option access, in general these require the core to reinitialize player['vo'] = 'gpu'
# os.environ['PATH']=dllspath+os.pathsep+os.environ['PATH'] # os.add_dll_directory("C:\Program Files (x86)\mpv-1.dll") import re import subprocess import time import urllib.parse import urllib.request from tkinter import * import mpv import requests import vlc # pip install python-vlc from bs4 import BeautifulSoup root = Tk() mPlayer = mpv.MPV(ytdl=True, video=False) root.title("Test MPV Program") # vlc_instance=vlc.Instance() # player = vlc_instance.media_player_new() playing = BooleanVar() res_pause = StringVar() res_pause.set("__") query_url = StringVar() query_url.set("") query_title = StringVar() query_title.set("") query_thumbnail = "" display_var = StringVar() display_var.set("Enter a song name")
# All of the tidalapi classes are inherited from Model which has a .name # Add a __str__ function so when things are converted to strings, they # return their .name. Applied to Tracks/Albums/Artists/Playlists/etc def patch__str__(self): return self.name setattr(tidalapi.models.Model, '__str__', patch__str__) # # CREATE OBJECTS # # Get the mpv player up and running player = mpv.MPV() # ! Check for errors # Establish the Tidal session using the Kodi tidalapi library session = tidalapi.Session() # Create list to keep track of playlist. Can't use mpv since the URLs given back from # Tidal have expiration dates. Usually, you can get 6 or so tracks in before the URLs # start to go bad, but this object just fetches a URL as needed internal_playlist = DoubleLinkedList() # # LOGIN TO TIDAL # # Use the tidalapi to login, give the user 3 attempts before aborting #
def __init__(self, parent, title): wx.Frame.__init__(self, parent, title=title, size=(300, 300)) panel = wx.Panel(self) box = wx.BoxSizer(wx.VERTICAL) lbl = wx.StaticText(panel, 10, style=wx.ALIGN_CENTER) # label.SetLabel("Duration") font = wx.Font(8, wx.ROMAN, wx.ITALIC, wx.NORMAL) lbl.SetFont(font) lbl.SetLabel("me") box.Add(lbl, 20, wx.ALIGN_CENTER) self.url1 = "http://funasia.streamguys1.com/live3" self.mpvAudio = mpv.MPV() # self.mpvAudio.play(self.url1) self.playing = False self.CreateStatusBar() # status bar self.elapsed = "" self.recFile = None self.recording = False self.probe = None btn = wx.Button() @self.mpvAudio.property_observer('time-pos') def time_observer(name, val): try: wholeSecs = round(val) except: wholeSecs = 0 sep = ":" hr = 0 min1 = 0 sec = 0 elapsedTemp = "" if wholeSecs < 3600: min1 = wholeSecs // 60 sec = wholeSecs % 60 elapsedTemp = str(min1) + sep + str(sec).zfill(2) #print("Debug ",elapsed) elif wholeSecs >= 3600: hr = wholeSecs // 3600 lo = wholeSecs % 3600 if lo < 60: min1 = lo // 60 sec = lo % 60 else: sec = lo elapsedTemp = str(hr) + sep + str(min1).zfill(2) + sep + str( sec).zfill(2) if elapsedTemp != self.elapsed: self.elapsed = elapsedTemp print("Now Playing at: ", self.elapsed) filemenu = wx.Menu() menuAbout = filemenu.Append(wx.ID_ABOUT, "&About", "Info about this app") filemenu.AppendSeparator() menuOpen = filemenu.Append(wx.ID_OPEN, "&Open", "Open File") menuExit = filemenu.Append(wx.ID_EXIT, "&Exit", "Terminate") # menuStop = filemenu.Append(wx.ID_STOP, "&Stop" ,"Stop") menuPlay = filemenu.Append(wx.ID_ANY, "&Play", "Play") menuRec = filemenu.Append(wx.ID_ANY, "&Rec", "Record") # menubar mb = wx.MenuBar() mb.Append(filemenu, "&File") self.SetMenuBar(mb) # add to frame #events self.Bind(wx.EVT_MENU, self.onAbout, menuAbout) self.Bind(wx.EVT_MENU, self.onOpen, menuOpen) self.Bind(wx.EVT_MENU, self.onExit, menuExit) # self.Bind(wx.EVT_MENU,self.onStop,menuStop) self.Bind(wx.EVT_MENU, self.onPlay, menuPlay) self.Bind(wx.EVT_MENU, self.onRecord, menuRec) # self.Bind(wx.EVT_MENU, self.recStop,menuRstop) self.Show(True)
#!/usr/bin/python3 import mpv player = mpv.MPV(ytdl=False) player['vid'] = 'no' @player.property_observer('time-pos') def time_observer(_name, value): # Here, _value is either None if nothing is playing or a float containing # fractional seconds since the beginning of the file. # print('Now playing at {:.2f}s'.format(value)) print('Now playing at ', str(value)) player.play('track.mp3') player.wait_for_playback()
def setUp(self): self.m = mpv.MPV()
def __init__(self, val, screenwidth, screenheight, parent=None): super().__init__(parent) self.setWindowTitle("qtube") app_exit_shortcuts = ["Ctrl+Q", "Ctrl+W"] for sc in app_exit_shortcuts: exitshortcut = QShortcut(QKeySequence(sc), self) exitshortcut.activated.connect(self.exit_seq) backshortcut = QShortcut(QKeySequence('Alt+Left'), self) backshortcut.activated.connect(self.on_back_clicked) self.setStyleSheet("background-color: " + BACKGROUND_COLOR + ";") self.mygroupbox = QGroupBox('') self.mygroupbox.setStyleSheet("color: " + FOREGROUND_COLOR + "; font-family: " + FONT + "; font-style: italic") self.myform = QFormLayout() labellist = [] combolist = [] self.mygroupbox.setLayout(self.myform) self.scroll = QScrollArea() self.scroll.setWidget(self.mygroupbox) self.scroll.setWidgetResizable(True) self.scroll.setStyleSheet("color: " + FOREGROUND_COLOR + ";") self.history = { 'urls': [], 'title_boxes': [], 'data': [], 'page_numbers': [] } self.downloaded_videos = {'paths': [], 'short_titles': []} self.search = '' self.spinner = QtWaitingSpinner(self, False) self.spinner.setRoundness(70.0) self.spinner.setMinimumTrailOpacity(15.0) self.spinner.setTrailFadePercentage(70.0) self.spinner.setNumberOfLines(10) self.spinner.setLineLength(10) self.spinner.setLineWidth(4) self.spinner.setInnerRadius(4) self.spinner.setRevolutionsPerSecond(1.5) self.spinner.setColor(QColor(FOREGROUND_COLOR)) # multi-threading QThread.currentThread().setObjectName( 'main') # threads can be named, useful for log output self.__workers_done = [] self.__threads = [] self.line = QLineEdit(self) self.line.returnPressed.connect(self.clickMethod) self.line.setStyleSheet("color: " + FOREGROUND_COLOR + "; background-color: " + BACKGROUND_COLOR + "; border: 1px solid " + FOREGROUND_COLOR + "; font-family: " + FONT + ";") active_buttons = [] self.inactive_buttons = [] self.search_button = QPushButton() self.search_button.setText('Search') self.search_button.clicked.connect(self.clickMethod) active_buttons.append(self.search_button) self.home_button = QPushButton() self.home_button.setText('Home') self.home_button.clicked.connect(self.on_home_clicked) self.inactive_buttons.append(self.home_button) self.play_playlist_button = QPushButton() self.play_playlist_button.setText('Play All') self.play_playlist_button.clicked.connect( self.on_play_playlist_clicked) active_buttons.append(self.play_playlist_button) self.back_button = QPushButton() self.back_button.setText('Back') self.back_button.clicked.connect(self.on_back_clicked) self.inactive_buttons.append(self.back_button) for b in active_buttons: b.setStyleSheet("color: " + FOREGROUND_COLOR + "; background-color: " + BACKGROUND_COLOR + "; border: 1px solid " + FOREGROUND_COLOR + "; font-family: " + FONT + ";") b.setCursor(Qt.PointingHandCursor) for b in self.inactive_buttons: b.setStyleSheet("color: " + INACTIVE_COLOR + "; background-color: " + BACKGROUND_COLOR + "; border: 1px solid " + INACTIVE_COLOR + "; font-family: " + FONT + ";") self.download_label = QLabel() self.download_label.setText('0 downloads') self.download_label.setMaximumSize(QSize(110, 20)) self.download_label.setStyleSheet("color: " + INACTIVE_COLOR + "; background-color: " + BACKGROUND_COLOR + "; font-family: " + FONT + ";") self.download_selector = QComboBox() self.download_selector.setStyleSheet("color: " + INACTIVE_COLOR + "; background-color: " + BACKGROUND_COLOR + "; font-family: " + FONT + ";") self.download_selector.currentIndexChanged.connect( self.select_download) self.download_to_play = '' self.play_downloaded_button = QPushButton() self.play_downloaded_button.setText('Play') self.play_downloaded_button.clicked.connect(self.on_play_downloaded) self.play_downloaded_button.setMaximumSize(QSize(50, 20)) self.play_downloaded_button.setStyleSheet("color: " + INACTIVE_COLOR + "; background-color: " + BACKGROUND_COLOR + "; border: 1px solid " + INACTIVE_COLOR + "; font-family: " + FONT + ";") self.container = VideoContainer(PLAYER_SIZE) self.container.setAttribute(Qt.WA_DontCreateNativeAncestors) self.container.setAttribute(Qt.WA_NativeWindow) #self.container.sig_height.connect(self.resizeWindow) self.player = mpv.MPV( wid=str(int(self.container.winId())), ytdl=True, input_default_bindings=True, input_vo_keyboard=True, keep_open=True, reset_on_next_file='pause', osd_bar=True, ) script_dir = str(Path.home()) + '/.config/mpv/scripts/' [ self.player.command('load-script', script_dir + script) for script in os.listdir(script_dir) ] player_exit_shortcuts = ['q', 'ctrl+q', 'ctrl+w'] for sc in player_exit_shortcuts: self.player.register_key_binding(sc, self.exit_seq) self.player.register_key_binding('f', self.fullscreen) self.player.register_key_binding('esc', self.fullscreen_off) self.isFullScreen = False self.player.register_key_binding('WHEEL_LEFT', 'seek 1') self.player.register_key_binding('WHEEL_RIGHT', 'seek -1') searchbarlayout = QHBoxLayout() searchbarlayout.addWidget(self.line) searchbarlayout.addWidget(self.search_button) searchbarlayout.addWidget(self.spinner) searchbar = QWidget() searchbar.setLayout(searchbarlayout) buttonrowlayout = QHBoxLayout() buttonrowlayout.addWidget(self.back_button) buttonrowlayout.addWidget(self.home_button) buttonrowlayout.addWidget(self.play_playlist_button) buttonrow = QWidget() buttonrow.setLayout(buttonrowlayout) downloadrowlayout = QHBoxLayout() downloadrowlayout.addWidget(self.download_label) downloadrowlayout.addWidget(self.download_selector) downloadrowlayout.addWidget(self.play_downloaded_button) downloadrow = QWidget() downloadrow.setLayout(downloadrowlayout) sublayout = QVBoxLayout() sublayout.addWidget(searchbar) sublayout.addWidget(buttonrow) sublayout.addWidget(self.scroll) sublayout.addWidget(downloadrow) self.left = QWidget() self.left.setLayout(sublayout) self.left.setFixedWidth(LIST_WIDTH) biglayout = QHBoxLayout(self) biglayout.addWidget(self.left) biglayout.addWidget(self.container) biglayout.setContentsMargins(0, 0, 0, 0) self.move(int((screenwidth - PLAYER_SIZE.width() - LIST_WIDTH) / 2), int((screenheight - PLAYER_SIZE.height()) / 2)) # load home page data self.spinner.start() idx = 'Home' worker = Worker(idx, HOME_URL, search=False) thread = QThread() thread.setObjectName('thread_' + idx) worker.moveToThread(thread) worker.sig_data.connect(self.on_click_data_received) self.sig_abort_workers.connect(worker.abort) thread.started.connect(worker.grabData) thread.start() self.__threads.append((thread, worker))
def start_playing(self): if not self.player: self.player = mpv.MPV(video=False) thread = threading.Thread(target=self.continous_player, args={}) thread.daemon = True thread.start()
def start_server(cls, visibility=False, ao="alsa:device=[plughw:1,0]"): if os.path.isfile(PLAYLIST_FILE): f = open(PLAYLIST_FILE, "r") try: cls.playlist = json.loads(f.read()) except: pass finally: f.close() else: cls.playlist = [] cls.currently_playing = None cls.user_selected_flag = False cls.shutdown_flag = False cls.lock = threading.Lock() cls.play_lock = threading.Lock() cls.mpv = mpv.MPV(None, no_video="", ao=ao) cls.volume = 100.0 cls.play_queue = queue.Queue(maxsize=50) # threaded debug if DEBUG: cls._thread_debug = threading.Thread(target=cls._debug) cls._thread_debug.start() # threaded broadcast of position cls._thread_broadcast_pos = threading.Thread(target=cls._broadcast_position) cls._thread_broadcast_pos.start() # threaded play cls._thread_play = threading.Thread(target=cls._play) cls._thread_play.start() # start mpv listeners cls.mpv.register_event_callback(mpv.MpvEventID.END_FILE, cls._mpv_eof) # set mpv to paused initially cls.mpv.pause = True cherrypy_config = { "/rq": { "tools.websocket.on": True, "tools.websocket.handler_cls": JukeboxWebWorker, "tools.secureheaders.on": True, } } cherrypy.config.update({ "log.access_file": "access_log", "log.error_file": "error_log" }) cherrypy.config.update({"server.socket_port": WS_PORT}) if visibility: cherrypy.config.update({"server.socket_host": "0.0.0.0"}) # set the priority according to your needs if you are hooking something # else on the 'before_finalize' hook point. cherrypy.tools.secureheaders = cherrypy.Tool('before_finalize', secureheaders, priority=60) cls._wsp = WebSocketPlugin(cherrypy.engine) cls._wsp.subscribe() cherrypy.tools.websocket = WebSocketTool() cherrypy.engine.subscribe("stop", cls.stop_server) cherrypy.quickstart(JukeboxWebService(), "/", config=cherrypy_config)
def __init__(self): mpv_config = conffile.get(APP_NAME, "mpv.conf", True) input_config = conffile.get(APP_NAME, "input.conf", True) self._video = None extra_options = {} self.timeline_trigger = None self.action_trigger = None self.external_subtitles = {} self.external_subtitles_rev = {} self.should_send_timeline = False self.start_time = None self.url = None self.evt_queue = Queue() self._lock = RLock() self._tl_lock = RLock() self._finished_lock = Lock() self.last_update = Timer() self._jf_settings = None self.get_webview = lambda: None self.pause_ignore = None # Used to ignore pause events that come from us. self.last_seek = None self.update_check = UpdateChecker(self) if is_using_ext_mpv: extra_options = { "start_mpv": settings.mpv_ext_start, "ipc_socket": settings.mpv_ext_ipc, "mpv_location": settings.mpv_ext_path, "player-operation-mode": "cplayer" } self._player = mpv.MPV(input_default_bindings=True, input_vo_keyboard=True, input_media_keys=True, include=mpv_config, input_conf=input_config, log_handler=mpv_log_handler, loglevel=settings.mpv_log_level, **extra_options) self.menu = OSDMenu(self) self.syncplay = SyncPlayManager(self) self._player['demuxer-max-bytes'] = '800000000' if hasattr(self._player, 'osc'): self._player.osc = settings.enable_osc else: log.warning( "This mpv version doesn't support on-screen controller.") # Wrapper for on_key_press that ignores None. def keypress(key): def wrapper(func): if key is not None: self._player.on_key_press(key)(func) return func return wrapper @self._player.on_key_press('CLOSE_WIN') @self._player.on_key_press('STOP') @keypress(settings.kb_stop) def handle_stop(): self.stop() @keypress(settings.kb_prev) def handle_prev(): self.put_task(self.play_prev) @keypress(settings.kb_next) def handle_next(): self.put_task(self.play_next) @self._player.on_key_press('PREV') @self._player.on_key_press('XF86_PREV') def handle_media_prev(): if settings.media_key_seek: seektime, _x = self.get_seek_times() self.seek(seektime) else: self.put_task(self.play_prev) @self._player.on_key_press('NEXT') @self._player.on_key_press('XF86_NEXT') def handle_media_next(): if settings.media_key_seek: _x, seektime = self.get_seek_times() self.seek(seektime) else: self.put_task(self.play_next) @keypress(settings.kb_watched) def handle_watched(): self.put_task(self.watched_skip) @keypress(settings.kb_unwatched) def handle_unwatched(): self.put_task(self.unwatched_quit) @keypress(settings.kb_menu) def menu_open(): if not self.menu.is_menu_shown: self.menu.show_menu() else: self.menu.hide_menu() @keypress(settings.kb_menu_esc) def menu_back(): if self.menu.is_menu_shown: self.menu.menu_action('back') else: self._player.command('set', 'fullscreen', 'no') @keypress(settings.kb_menu_ok) def menu_ok(): self.menu.menu_action('ok') @keypress(settings.kb_menu_left) def menu_left(): if self.menu.is_menu_shown: self.menu.menu_action('left') else: seektime = settings.seek_left if settings.use_web_seek: seektime, _x = self.get_seek_times() self.seek(seektime) @keypress(settings.kb_menu_right) def menu_right(): if self.menu.is_menu_shown: self.menu.menu_action('right') else: seektime = settings.seek_right if settings.use_web_seek: _x, seektime = self.get_seek_times() self.seek(seektime) @keypress(settings.kb_menu_up) def menu_up(): if self.menu.is_menu_shown: self.menu.menu_action('up') else: self.seek(settings.seek_up) @keypress(settings.kb_menu_down) def menu_down(): if self.menu.is_menu_shown: self.menu.menu_action('down') else: self.seek(settings.seek_down) @keypress(settings.kb_pause) def handle_pause(): if self.menu.is_menu_shown: self.menu.menu_action('ok') else: self.toggle_pause() # This gives you an interactive python debugger prompt. @keypress(settings.kb_debug) def handle_debug(): import pdb pdb.set_trace() # Fires between episodes. @self._player.property_observer('eof-reached') def handle_end(_name, reached_end): if self._video and reached_end: has_lock = self._finished_lock.acquire(False) self.put_task(self.finished_callback, has_lock) # Fires at the end. @self._player.property_observer('playback-abort') def handle_end_idle(name, value): if self._video and value: has_lock = self._finished_lock.acquire(False) self.put_task(self.finished_callback, has_lock) @self._player.property_observer("seeking") def handle_seeking(name, value): if self.syncplay.is_enabled(): play_time = self._player.playback_time if (play_time is not None and self.last_seek is not None and abs(self.last_seek - play_time) > 10): log.info("Reverting sync for syncplay.") self._player.command("revert-seek") self.syncplay.seek_request(play_time) else: log.debug("SyncPlay Buffering: {0}".format(value)) if value: self.syncplay.on_buffer() else: self.syncplay.on_buffer_done() @self._player.property_observer("pause") def pause_handler(_name, value): if not self._player.playback_abort: self.timeline_handle() if value != self.pause_ignore: if self.syncplay.is_enabled(): if value: self.syncplay.pause_request() else: # Don't allow unpausing locally through MPV. self.syncplay.play_request() self.set_paused(True, True)
def __init__( self, parent ): CAC.ApplicationCommandProcessorMixin.__init__( self ) QW.QWidget.__init__( self, parent ) self._canvas_type = CC.CANVAS_PREVIEW self._stop_for_slideshow = False # This is necessary since PyQT stomps over the locale settings needed by libmpv. # This needs to happen after importing PyQT before creating the first mpv.MPV instance. locale.setlocale( locale.LC_NUMERIC, 'C' ) self.setAttribute( QC.Qt.WA_DontCreateNativeAncestors ) self.setAttribute( QC.Qt.WA_NativeWindow ) loglevel = 'debug' if HG.mpv_report_mode else 'fatal' # loglevels: fatal, error, debug self._player = mpv.MPV( wid = str( int( self.winId() ) ), log_handler = log_handler, loglevel = loglevel ) # hydev notes on OSC: # OSC is by default off, default input bindings are by default off # difficult to get this to intercept mouse/key events naturally, so you have to pipe them to the window with 'command', but this is not excellent # general recommendation when using libmpv is to just implement your own stuff anyway, so let's do that for prototype #self._player[ 'input-default-bindings' ] = True self.UpdateConf() self._player.loop = True # this makes black screen for audio (rather than transparent) self._player.force_window = True # this actually propagates up to the OS-level sound mixer lmao, otherwise defaults to ugly hydrus filename self._player.title = 'hydrus mpv player' # pass up un-button-pressed mouse moves to parent, which wants to do cursor show/hide self.setMouseTracking( True ) #self.setFocusPolicy(QC.Qt.StrongFocus)#Needed to get key events self._player.input_cursor = False#Disable mpv mouse move/click event capture self._player.input_vo_keyboard = False#Disable mpv key event capture, might also need to set input_x11_keyboard self._media = None self._file_is_loaded = False self._disallow_seek_on_this_file = False self._times_to_play_gif = 0 self._current_seek_to_start_count = 0 self._InitialiseMPVCallbacks() self.destroyed.connect( self._player.terminate ) HG.client_controller.sub( self, 'UpdateAudioMute', 'new_audio_mute' ) HG.client_controller.sub( self, 'UpdateAudioVolume', 'new_audio_volume' ) HG.client_controller.sub( self, 'UpdateConf', 'notify_new_options' ) HG.client_controller.sub( self, 'SetLogLevel', 'set_mpv_log_level' ) self._my_shortcut_handler = ClientGUIShortcuts.ShortcutsHandler( self, [], catch_mouse = True )
def test_custom_stream(self): handler = mock.Mock() fail_mock = mock.Mock(side_effect=ValueError) stream_mock = mock.Mock() stream_mock.seek = mock.Mock(return_value=0) stream_mock.read = mock.Mock(return_value=b'') disp = Xvfb() disp.start() m = mpv.MPV(video=False) m.register_event_callback(handler) m.register_stream_protocol('pythonfail', fail_mock) @m.register_stream_protocol('pythonsuccess') def open_fn(uri): self.assertEqual(uri, 'pythonsuccess://foo') return stream_mock m.play('pythondoesnotexist://foo') m.wait_for_playback() handler.assert_any_call({ 'reply_userdata': 0, 'error': 0, 'event_id': mpv.MpvEventID.END_FILE, 'event': { 'reason': mpv.MpvEventEndFile.ERROR, 'error': mpv.ErrorCode.LOADING_FAILED } }) handler.reset_mock() m.play('pythonfail://foo') m.wait_for_playback() handler.assert_any_call({ 'reply_userdata': 0, 'error': 0, 'event_id': mpv.MpvEventID.END_FILE, 'event': { 'reason': mpv.MpvEventEndFile.ERROR, 'error': mpv.ErrorCode.LOADING_FAILED } }) handler.reset_mock() m.play('pythonsuccess://foo') m.wait_for_playback() stream_mock.seek.assert_any_call(0) stream_mock.read.assert_called() handler.assert_any_call({ 'reply_userdata': 0, 'error': 0, 'event_id': mpv.MpvEventID.END_FILE, 'event': { 'reason': mpv.MpvEventEndFile.ERROR, 'error': mpv.ErrorCode.UNKNOWN_FORMAT } }) m.terminate() disp.stop()
def main(): global player parser = argparse.ArgumentParser(description='simple queue player for mpv') parser.add_argument('files', metavar="URL/PATH", default=None, nargs='*') parser.add_argument( '-p', '--property', metavar=("KEY", "VALUE"), nargs=2, default=[], action='append', help= "set mpv property KEY to VALUE. See all available properties with 'mpv --list-properties'" ) parser.add_argument('-v', '--video', action='store_true', help="Enable video. Shorthand for '-p video auto'") args = parser.parse_args() props = default_properties # assemble dict from properties from command line custom_props = {p[0]: p[1] for p in args.property} # override/add properties from arguments props.update(custom_props) if args.video: props['video'] = "auto" player = mpv.MPV(**props) @player.on_key_press('a') def ask_url(): """Ask for filename/URL to append to the playlist""" def cb(url): if url != "": player.playlist_append(url) prompt("Enter URL or file name", cb) @player.on_key_press('c') def ask_command(): """Open playlist editing command prompt. Available commands listed in HELP_COMMANDS""" prompt("Enter command (or 'h' for help)", handle_command) @player.property_observer('playlist') def playlist_observer(_name, value): """Make sure playlist_pos is set, display playlist. Gets called if items in playlist or position in playlist changes.""" if len(player.playlist) > 0: if player.playlist_pos is None: # when adding a title to an empty playlist, mpv doesn't automatically start playback, # this does the job. player.playlist_pos = 0 print_playlist() greet() if len(args.files) > 0: for f in args.files: player.playlist_append(f) else: ask_url() # slightly ugly; but makes sure this thread terminates when mpv terminates # there probably is a better way to do this. player._event_thread.join()