11 changed files with 489 additions and 0 deletions
@ -0,0 +1,244 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!-- Generated with glade 3.22.1 --> |
||||
<interface> |
||||
<requires lib="gtk+" version="3.20"/> |
||||
<object class="GtkImage" id="fullscreenBtn"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">False</property> |
||||
<property name="icon_name">view-restore</property> |
||||
</object> |
||||
<object class="GtkImage" id="nextImg"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">False</property> |
||||
<property name="icon_name">media-skip-forward</property> |
||||
</object> |
||||
<object class="GtkImage" id="pauseImg"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">False</property> |
||||
<property name="icon_name">media-playback-pause</property> |
||||
</object> |
||||
<object class="GtkImage" id="playImg"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">False</property> |
||||
<property name="icon_name">media-playback-start</property> |
||||
</object> |
||||
<object class="GtkImage" id="playlistImg"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">False</property> |
||||
<property name="icon_name">format-justify-fill</property> |
||||
</object> |
||||
<object class="GtkImage" id="prevImg"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">False</property> |
||||
<property name="icon_name">media-skip-backward</property> |
||||
</object> |
||||
<object class="GtkImage" id="volumeDownImg"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">False</property> |
||||
<property name="icon_name">audio-volume-low</property> |
||||
</object> |
||||
<object class="GtkImage" id="volumeUpImg"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">False</property> |
||||
<property name="icon_name">audio-volume-high</property> |
||||
</object> |
||||
<object class="GtkWindow" id="gtplayer"> |
||||
<property name="can_focus">False</property> |
||||
<child> |
||||
<placeholder/> |
||||
</child> |
||||
<child> |
||||
<object class="GtkBox"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">False</property> |
||||
<property name="orientation">vertical</property> |
||||
<child> |
||||
<object class="GtkBox"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">False</property> |
||||
<child> |
||||
<object class="GtkBox"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">False</property> |
||||
<property name="orientation">vertical</property> |
||||
<child> |
||||
<object class="GtkDrawingArea" id="videoArea"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">False</property> |
||||
<signal name="realize" handler="realize" swapped="no"/> |
||||
</object> |
||||
<packing> |
||||
<property name="expand">True</property> |
||||
<property name="fill">True</property> |
||||
<property name="position">0</property> |
||||
</packing> |
||||
</child> |
||||
</object> |
||||
<packing> |
||||
<property name="expand">True</property> |
||||
<property name="fill">True</property> |
||||
<property name="position">0</property> |
||||
</packing> |
||||
</child> |
||||
</object> |
||||
<packing> |
||||
<property name="expand">True</property> |
||||
<property name="fill">True</property> |
||||
<property name="position">0</property> |
||||
</packing> |
||||
</child> |
||||
<child> |
||||
<object class="GtkBox"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">False</property> |
||||
<child> |
||||
<object class="GtkButtonBox"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">False</property> |
||||
<property name="layout_style">expand</property> |
||||
<child> |
||||
<object class="GtkButton" id="prevBtn"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">True</property> |
||||
<property name="receives_default">True</property> |
||||
<property name="image">prevImg</property> |
||||
</object> |
||||
<packing> |
||||
<property name="expand">True</property> |
||||
<property name="fill">True</property> |
||||
<property name="position">0</property> |
||||
</packing> |
||||
</child> |
||||
<child> |
||||
<object class="GtkButton" id="playBtn"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">True</property> |
||||
<property name="receives_default">True</property> |
||||
<property name="image">pauseImg</property> |
||||
</object> |
||||
<packing> |
||||
<property name="expand">True</property> |
||||
<property name="fill">True</property> |
||||
<property name="position">1</property> |
||||
</packing> |
||||
</child> |
||||
<child> |
||||
<object class="GtkButton" id="playBt"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">True</property> |
||||
<property name="receives_default">True</property> |
||||
<property name="image">playImg</property> |
||||
</object> |
||||
<packing> |
||||
<property name="expand">True</property> |
||||
<property name="fill">True</property> |
||||
<property name="position">2</property> |
||||
</packing> |
||||
</child> |
||||
<child> |
||||
<object class="GtkButton" id="nextBtn"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">True</property> |
||||
<property name="receives_default">True</property> |
||||
<property name="image">nextImg</property> |
||||
</object> |
||||
<packing> |
||||
<property name="expand">True</property> |
||||
<property name="fill">True</property> |
||||
<property name="position">3</property> |
||||
</packing> |
||||
</child> |
||||
</object> |
||||
<packing> |
||||
<property name="expand">False</property> |
||||
<property name="fill">True</property> |
||||
<property name="position">0</property> |
||||
</packing> |
||||
</child> |
||||
<child> |
||||
<object class="GtkProgressBar"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">False</property> |
||||
<property name="pulse_step">0</property> |
||||
</object> |
||||
<packing> |
||||
<property name="expand">True</property> |
||||
<property name="fill">True</property> |
||||
<property name="position">1</property> |
||||
</packing> |
||||
</child> |
||||
<child> |
||||
<object class="GtkButtonBox"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">False</property> |
||||
<property name="layout_style">end</property> |
||||
<child> |
||||
<object class="GtkButton" id="volumeUpBtn"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">True</property> |
||||
<property name="receives_default">True</property> |
||||
<property name="image">volumeUpImg</property> |
||||
</object> |
||||
<packing> |
||||
<property name="expand">True</property> |
||||
<property name="fill">True</property> |
||||
<property name="position">0</property> |
||||
</packing> |
||||
</child> |
||||
<child> |
||||
<object class="GtkButton" id="volumeDownBtn"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">True</property> |
||||
<property name="receives_default">True</property> |
||||
<property name="image">volumeDownImg</property> |
||||
</object> |
||||
<packing> |
||||
<property name="expand">True</property> |
||||
<property name="fill">True</property> |
||||
<property name="position">1</property> |
||||
</packing> |
||||
</child> |
||||
<child> |
||||
<object class="GtkButton" id="fullscreenBt"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">True</property> |
||||
<property name="receives_default">True</property> |
||||
<property name="image">fullscreenBtn</property> |
||||
</object> |
||||
<packing> |
||||
<property name="expand">True</property> |
||||
<property name="fill">True</property> |
||||
<property name="position">2</property> |
||||
</packing> |
||||
</child> |
||||
<child> |
||||
<object class="GtkButton" id="playlistBtn"> |
||||
<property name="visible">True</property> |
||||
<property name="can_focus">True</property> |
||||
<property name="receives_default">True</property> |
||||
<property name="image">playlistImg</property> |
||||
</object> |
||||
<packing> |
||||
<property name="expand">True</property> |
||||
<property name="fill">True</property> |
||||
<property name="position">3</property> |
||||
</packing> |
||||
</child> |
||||
</object> |
||||
<packing> |
||||
<property name="expand">False</property> |
||||
<property name="fill">True</property> |
||||
<property name="position">2</property> |
||||
</packing> |
||||
</child> |
||||
</object> |
||||
<packing> |
||||
<property name="expand">False</property> |
||||
<property name="fill">True</property> |
||||
<property name="position">1</property> |
||||
</packing> |
||||
</child> |
||||
</object> |
||||
</child> |
||||
</object> |
||||
</interface> |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,16 @@
|
||||
import gi |
||||
import mpv |
||||
|
||||
from mainWindow import MainWindow |
||||
from mpvplayer import MPVPlayer |
||||
from playlist import Playlist, Video |
||||
|
||||
gi.require_version('Gtk', '3.0') |
||||
from gi.repository import Gtk |
||||
|
||||
pl = Playlist ( [Video("Big Buck Bunny", "data/test.mp4")] ) |
||||
hwnd = MainWindow ( "data/gtplay.glade", |
||||
pl ); |
||||
hwnd.show() |
||||
|
||||
Gtk.main() |
@ -0,0 +1,42 @@
|
||||
import gi |
||||
from mpvplayer import MPVPlayer |
||||
|
||||
gi.require_version("Gtk", "3.0") |
||||
from gi.repository import Gtk |
||||
|
||||
class MainWindow ( object ): |
||||
def __init__ ( self, gladeFile, playlist ): |
||||
self.builder = Gtk.Builder() |
||||
self.builder.add_from_file ( gladeFile ); |
||||
|
||||
window = self.builder.get_object ( "gtplayer" ); |
||||
window.connect ( "destroy", self.destroy ); |
||||
|
||||
videoArea = self.builder.get_object ( "videoArea" ); |
||||
videoArea.connect ( "realize", self.videoArea_realize, self ); |
||||
|
||||
self.playlist = playlist; |
||||
self.player = None; |
||||
|
||||
def destroy ( self, widget=None, data=None ): |
||||
if ( self.player != None ): |
||||
self.player.destroy() |
||||
Gtk.main_quit() |
||||
|
||||
def getWidget ( self, name ): |
||||
return self.builder.get_object( name ); |
||||
|
||||
def playlistPopulate ( self, playlist ): |
||||
pass |
||||
|
||||
def playlistAdd ( self, video ): |
||||
pass |
||||
|
||||
def show ( self ): |
||||
window = self.builder.get_object ( "gtplayer" ); |
||||
window.show_all () |
||||
|
||||
def videoArea_realize ( self, widget, data=None ): |
||||
self.player = MPVPlayer ( self.playlist, widget.get_window().get_xid() ) |
||||
self.player.start (); |
||||
|
@ -0,0 +1,50 @@
|
||||
import locale |
||||
import mpv |
||||
|
||||
from playlist import Playlist |
||||
from player import Player |
||||
|
||||
|
||||
class MPVPlayer ( Player ): |
||||
def __init__ ( self, playlist, xid ): |
||||
locale.setlocale ( locale.LC_NUMERIC, 'C' ); |
||||
self.mpv = mpv.MPV ( ytdl=True, wid=str(xid) ); |
||||
self.mpv.observe_property('time-pos', self.time_observer); |
||||
self.playlist = playlist; |
||||
|
||||
def pause ( self ): |
||||
self.mpv.command ( 'pause', None ); |
||||
|
||||
def resume ( self ): |
||||
self.mpv.command ( 'resume', None ); |
||||
|
||||
def play ( self, video ): |
||||
self.mpv.play ( video.url ); |
||||
|
||||
def destroy ( self ): |
||||
self.mpv.terminate(); |
||||
|
||||
def time ( self ): |
||||
return self.time; |
||||
|
||||
def seek ( self, time ): |
||||
hrs = 0; |
||||
m = int(time/60); |
||||
time -= m*60; |
||||
|
||||
hrs = int(m/60); |
||||
m -= hrs*60; |
||||
|
||||
self.mpv.seek ( "%0d:%0d:%0d"%(hrs,m,time), reference="absolute"); |
||||
|
||||
def start ( self ): |
||||
self.play ( self.playlist.first() ); |
||||
|
||||
def ioctl ( self, cmd, val ): |
||||
if ( cmd == "SETXID" ): |
||||
#self.xid = val; |
||||
self.mpv._mpv_set_option_string(self.mpv.handle, "wid".encode('utf-8'), istr((str(val)).encode('utf-8'))) |
||||
|
||||
def time_observer(self, _name, value): |
||||
self.time = value; |
||||
print('Now playing at {:.2f}s'.format(value)) |
@ -0,0 +1,39 @@
|
||||
from playlist import Playlist |
||||
|
||||
class Player ( object ): |
||||
def __init__ ( self, playlist ): |
||||
self.playlist = playlist; |
||||
|
||||
self.currentFile = ""; |
||||
self.playing = False; |
||||
self.time = 0; |
||||
self.fullscreen = False; |
||||
self.loop = False; |
||||
|
||||
def pause ( self ): |
||||
pass |
||||
def resume ( self ): |
||||
pass |
||||
def stop ( self ): |
||||
pass |
||||
def play ( self, video ): |
||||
pass |
||||
def next ( self ): |
||||
return self.play ( self.playlist.next() ); |
||||
def prev ( self ): |
||||
return self.play ( self.playlist.prev() ); |
||||
|
||||
def destroy ( self ): |
||||
pass |
||||
|
||||
def time ( self ): |
||||
pass |
||||
|
||||
def seek ( self, time ): |
||||
pass |
||||
|
||||
def start ( self ): |
||||
pass |
||||
|
||||
def ioctl ( self, cmd, val ): |
||||
pass |
@ -0,0 +1,98 @@
|
||||
class PlaylistEnd ( Exception ): |
||||
pass |
||||
class PlaylistEmpty ( Exception ): |
||||
pass |
||||
class PlaylistOutOfRange ( Exception ): |
||||
pass |
||||
class PlaylistEntryNotFound ( Exception ): |
||||
pass |
||||
|
||||
class Video ( object ): |
||||
def __init__ ( self, name, url ): |
||||
self.name = name; |
||||
self.url = url; |
||||
|
||||
class Playlist ( object ): |
||||
def __init__ ( self, pl=None ): |
||||
self.pl = pl or []; |
||||
self._current = None; |
||||
|
||||
def first ( self ): |
||||
if len(self.pl) == 0: |
||||
raise PlaylistEmpty() |
||||
|
||||
self._current = 0; |
||||
return self.pl[self._current]; |
||||
|
||||
def last ( self ): |
||||
if len(self.pl) == 0: |
||||
raise PlaylistEmpty() |
||||
|
||||
self._current = len(self.pl)-1 |
||||
return self.pl[self._current]; |
||||
|
||||
def prev ( self ): |
||||
if len(self.pl) == 0: |
||||
raise PlaylistEmpty() |
||||
|
||||
if (self._current == None or |
||||
self._current < 0 or |
||||
self._current >= len(self.pl)): |
||||
self._current = 0; |
||||
else: |
||||
self._current -= 1 |
||||
|
||||
if self._current < 0: |
||||
self._current = 0; |
||||
|
||||
return self.pl[self._current]; |
||||
|
||||
def next ( self ): |
||||
if len(self.pl) == 0: |
||||
raise PlaylistEmpty() |
||||
|
||||
if (self._current == None or |
||||
self._current < 0 or |
||||
self._current >= len(self.pl)): |
||||
self._current = 0; |
||||
else: |
||||
self._current += 1 |
||||
|
||||
if self._current >= len(self.pl): |
||||
raise PlaylistEnd(); |
||||
|
||||
return self.pl[self._current] |
||||
|
||||
def index ( self, index ): |
||||
index = int(index); |
||||
if (index < 0 or |
||||
index >= len(self.pl)): |
||||
raise PlaylistOutOfRange(); |
||||
|
||||
return self.pl[index]; |
||||
|
||||
def push ( self, obj ): |
||||
if ( type(obj) is Video ): |
||||
self.pl.append ( obj ); |
||||
else: |
||||
raise TypeError("This object is not a Video"); |
||||
|
||||
def pop ( self ): |
||||
self.pl.pop(); |
||||
|
||||
def remove ( self, index ): |
||||
index = int(index); |
||||
if (index < 0 or |
||||
index >= len(self.pl)): |
||||
raise PlaylistOutOfRange(); |
||||
|
||||
return self.pl.pop ( index ); |
||||
|
||||
def clear ( self, index ): |
||||
self.pl.clear(); |
||||
|
||||
def searchByName ( self, name ): |
||||
for v in self.pl: |
||||
if v.name == name : |
||||
return v; |
||||
raise PlaylistEntryNotFound(); |
Loading…
Reference in new issue