Browse Source

prototyping: class structure and MPV Prove of concept

master
Stefan Naumann 3 years ago
parent
commit
6a5e5e67ca
  1. 244
      data/gtplay.glade
  2. BIN
      data/test.mp4
  3. BIN
      src/__pycache__/mainWindow.cpython-37.pyc
  4. BIN
      src/__pycache__/mpvplayer.cpython-37.pyc
  5. BIN
      src/__pycache__/player.cpython-37.pyc
  6. BIN
      src/__pycache__/playlist.cpython-37.pyc
  7. 16
      src/gtplay.py
  8. 42
      src/mainWindow.py
  9. 50
      src/mpvplayer.py
  10. 39
      src/player.py
  11. 98
      src/playlist.py

244
data/gtplay.glade

@ -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>

BIN
data/test.mp4

Binary file not shown.

BIN
src/__pycache__/mainWindow.cpython-37.pyc

Binary file not shown.

BIN
src/__pycache__/mpvplayer.cpython-37.pyc

Binary file not shown.

BIN
src/__pycache__/player.cpython-37.pyc

Binary file not shown.

BIN
src/__pycache__/playlist.cpython-37.pyc

Binary file not shown.

16
src/gtplay.py

@ -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()

42
src/mainWindow.py

@ -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 ();

50
src/mpvplayer.py

@ -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))

39
src/player.py

@ -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

98
src/playlist.py

@ -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…
Cancel
Save