diff --git a/RaiTV/ChannelLoader.py b/RaiTV/ChannelLoader.py new file mode 100644 index 0000000..ab5c971 --- /dev/null +++ b/RaiTV/ChannelLoader.py @@ -0,0 +1,57 @@ +# +# -*- coding: utf-8 -*- +# +# Scarica la lista di URI per vedere i canali rai +# + +import urllib2, re, httplib + +class ChannelList(): + + def __init__(self): + + ## Inizializzo un dizionario di canali + self.channels = {} + + self.UA = 'Mozilla/5.0 (X11; U; Linux i686; it; rv:1.9.0.6) Gecko/2009011912 Firefox/3.0.11' + + def updateChannels(self): + + ## Qui dobbiamo un pochino imbrogliare..ehm ehm + req = urllib2.Request("http://www.rai.tv/dl/RaiTV/videoWall/PublishingBlock-5566288c-3d21-48dc-b3e2-af7fbe3b2af8.xml", + None, + { 'User-Agent': self.UA }) + r = urllib2.urlopen(req) + self.parseChannels(r.read()) + + def parseChannels(self, xmlfile): + """Fai il parse dei canali scaricati dalla rai""" + + for channel, url in re.findall("<videoUnit name=\"([^\"]*)\".*>.*\\n.*<url>(\S*)</url>", xmlfile): + url = re.sub(r"&", "&", url) + self.channels[channel] = url + + + def getChannel(self, key): + """Ottiene il vero canale da cui guardare.. :)""" + + if not self.channels.has_key(key): + return None + + host = re.search(r"^.*//([^/]*)/", self.channels[key]).group(1) + # print " => host = %s" % host + path = re.search(r"%s/(.*)$" % host, self.channels[key]).group(1) + # print " => path = %s" % path + + req = urllib2.Request(self.channels[key], + None, + {'User-Agent': self.UA}) + + r = urllib2.urlopen(req) + mms = r.read() + mms = re.search(r"HREF=\"(\S*)\"", mms).group(1) + return mms + + + + diff --git a/RaiTV/Interface.py b/RaiTV/Interface.py index 1e66d2b..c1e162a 100644 --- a/RaiTV/Interface.py +++ b/RaiTV/Interface.py @@ -10,20 +10,83 @@ import gtk, pygtk ## avrò bisogno di recuperare from VideoWidget import VideoWidget +from ChannelLoader import ChannelList -builder = gtk.Builder() -builder.add_from_file("ui/RaiTV.ui") +class UI(): + + def __init__(self): + """Recupera tutti gli oggetti necessari aprendo + il file .ui e costruisce quelli che mancano""" + + self.builder = gtk.Builder() + self.builder.add_from_file("ui/RaiTV.ui") + + self.win = self.builder.get_object("win") + self.listacanali = self.builder.get_object("listacanali") + + ## Lista dei canali (in astratto) + self.channellist = ChannelList() + + + ## Questo hbox è quello dove dobbiamo inserire + ## la videowidget + self.hbox1 = self.builder.get_object("hbox1") + + self.videowidget = VideoWidget() + self.hbox1.pack_start(self.videowidget) + + ## Qualche setting prima di partire + self.win.resize(640,480) + + ## Carico i pulsanti + self.stop_btn, self.play_btn, self.pause_btn, self.record_btn, self.updatelist = \ + self.builder.get_object("stop"), self.builder.get_object("play"), \ + self.builder.get_object("pause"), self.builder.get_object("record"), \ + self.builder.get_object("updatelist") + + ## La statusbar + self.statusbar = self.builder.get_object("statusbar") + self.sb_info("Applicazione inizializzata") + + self.connect_buttons() + + + ## Connettiamo la richiesta di uscire a qualcosa che lo gestisca + self.win.connect("destroy", self.destroy) + + def show_all(self): + """Mostra tutta l'interfaccia""" + self.win.show_all() + + def sb_info(self, text): + """Pubblica delle informazioni nella statusbar""" + assert self.statusbar + id = self.statusbar.get_context_id("info") + self.statusbar.push(id, "Info: " + text) + + def connect_buttons(self): + """Connette i bottoni con le relative azioni""" + self.stop_btn.connect("clicked", lambda w: self.videowidget.stop() ) + self.play_btn.connect("clicked", lambda w: self.videowidget.play() ) + self.pause_btn.connect("clicked", lambda w: self.videowidget.pause() ) + self.updatelist.connect("clicked", lambda w: self.channellist.updateChannels() ) + + def start_video(self): + """Avvia il video""" + self.videowidget.registerXID() + self.videowidget.load_video("file:///home/leonardo/Video/The.Big.Bang.Theory.S03E02.HDTV.XviD-XII.avi") + # self.videowidget.load_video("mms://livestream.rai.it.edgestreams.net/reflector:64084?auth=daEcjcOancgdlaecAdqdccmdwbZbkb0aHd.-bk6_3l-b4-JlruuGt&aifp=V001") + # self.videowidget.load_video("mms://livestream.rai.it.edgestreams.net/reflector:64084?auth=daEcvcIa9clbgaEbjbfbFdHc_dkcCbUb7dQ-bk7abm-b4-BlvusGo&aifp=V001") + + def destroy(self, w): + """Chiamata per distruggere l'interfaccia""" + + ## Fermiamo il video + self.videowidget.stop() + + ## e ce ne andiamo + gtk.main_quit() -win = builder.get_object("win") -listacanali = builder.get_object("listacanali") -hbox1 = builder.get_object("hbox1") -videowidget = VideoWidget() -hbox1.pack_start(videowidget) -win.show_all() -win.resize(640,480) -videowidget.reset() -videowidget.registerXID() -videowidget.start_video("file:///home/leonardo/Video/The.Big.Bang.Theory.S03E02.HDTV.XviD-XII.avi") diff --git a/RaiTV/VideoWidget.py b/RaiTV/VideoWidget.py index 0a953e8..d4a93f7 100644 --- a/RaiTV/VideoWidget.py +++ b/RaiTV/VideoWidget.py @@ -17,6 +17,16 @@ class VideoWidget(gtk.DrawingArea): self.set_size_request(320,320) self.unset_flags(gtk.DOUBLE_BUFFERED) + ## Configurazione del player gstreamer + self.player = gst.element_factory_make("playbin", "player") + bus = self.player.get_bus() + bus.enable_sync_message_emission() + bus.add_signal_watch() + bus.connect("sync-message::element", self.on_sync_message) + bus.connect("message", self.on_message) + + + def do_expose_event(self, event): if self.imagesink: self.imagesink.expose() @@ -29,16 +39,19 @@ class VideoWidget(gtk.DrawingArea): self.imagesink = sink self.imagesink.set_xwindow_id(self.window.xid) - def start_video(self, uri): + def load_video(self, uri): """Start video playing with the specified URI""" - self.player = gst.element_factory_make("playbin", "player") self.player.set_property("uri", uri) - bus = self.player.get_bus() - bus.enable_sync_message_emission() - bus.add_signal_watch() - bus.connect("sync-message::element", self.on_sync_message) - bus.connect("message", self.on_message) + self.play() + + def pause(self): + self.player.set_state(gst.STATE_PAUSED) + + def stop(self): + self.player.set_state(gst.STATE_NULL) + + def play(self): self.player.set_state(gst.STATE_PLAYING) def on_sync_message(self, bus, message): @@ -46,7 +59,6 @@ class VideoWidget(gtk.DrawingArea): return if message.structure.get_name() == 'prepare-xwindow-id': gtk.gdk.threads_enter() - # gtk.gdk.display.get_default.sync() self.set_sink(message.src) message.src.set_property("force-aspect-ratio", True) gtk.gdk.threads_leave() diff --git a/raitv.py b/raitv.py index 7f7e92f..296070f 100644 --- a/raitv.py +++ b/raitv.py @@ -6,10 +6,10 @@ import gtk, pygtk, gst from RaiTV import VideoWidget, Interface -Interface.listacanali.show() -Interface.win.show() +ui = Interface.UI() -Interface.win.connect("destroy", gtk.main_quit) +ui.show_all() +ui.start_video() gtk.main() diff --git a/ui/RaiTV.ui b/ui/RaiTV.ui index 798d32c..c5537cd 100644 --- a/ui/RaiTV.ui +++ b/ui/RaiTV.ui @@ -2,13 +2,21 @@ <interface> <requires lib="gtk+" version="2.16"/> <!-- interface-naming-policy project-wide --> + <object class="GtkListStore" id="canalistore"> + <columns> + <!-- column-name nomecanale --> + <column type="gchararray"/> + <!-- column-name url --> + <column type="gchararray"/> + </columns> + </object> <object class="GtkWindow" id="win"> <child> <object class="GtkVBox" id="vbox1"> <property name="visible">True</property> <property name="orientation">vertical</property> <child> - <object class="GtkMenuBar" id="menubar1"> + <object class="GtkMenuBar" id="menubar"> <property name="visible">True</property> <child> <object class="GtkMenuItem" id="menuitem1"> @@ -151,13 +159,23 @@ <object class="GtkTreeView" id="listacanali"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="model">liststore1</property> + <property name="model">canalistore</property> </object> <packing> <property name="position">0</property> </packing> </child> <child> + <object class="GtkVSeparator" id="vseparator1"> + <property name="visible">True</property> + <property name="orientation">vertical</property> + </object> + <packing> + <property name="expand">False</property> + <property name="position">1</property> + </packing> + </child> + <child> <placeholder/> </child> </object> @@ -166,19 +184,110 @@ </packing> </child> <child> - <object class="GtkHButtonBox" id="hbuttonbox1"> + <object class="GtkHBox" id="hbox2"> <property name="visible">True</property> <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child> - <placeholder/> + <object class="GtkAlignment" id="alignment1"> + <property name="visible">True</property> + <property name="xalign">0</property> + <child> + <object class="GtkHButtonBox" id="hbuttonbox1"> + <property name="visible">True</property> + <child> + <object class="GtkButton" id="updatelist"> + <property name="label" translatable="yes">Aggiorna canali</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="play"> + <property name="label">gtk-media-play</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="pause"> + <property name="label">gtk-media-pause</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkButton" id="stop"> + <property name="label">gtk-media-stop</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkButton" id="record"> + <property name="label">gtk-media-record</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">4</property> + </packing> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> </child> <child> - <placeholder/> + <object class="GtkVolumeButton" id="volumebutton"> + <property name="label" translatable="yes">Volume</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="relief">none</property> + <property name="focus_on_click">False</property> + <property name="orientation">vertical</property> + <property name="icons">audio-volume-muted +audio-volume-high +audio-volume-low +audio-volume-medium</property> + </object> + <packing> + <property name="expand">False</property> + <property name="position">1</property> + </packing> </child> <child> <placeholder/> @@ -189,15 +298,18 @@ <property name="position">2</property> </packing> </child> + <child> + <object class="GtkStatusbar" id="statusbar"> + <property name="visible">True</property> + <property name="spacing">2</property> + </object> + <packing> + <property name="expand">False</property> + <property name="position">3</property> + </packing> + </child> </object> </child> </object> - <object class="GtkListStore" id="liststore1"> - <columns> - <!-- column-name nomecanale --> - <column type="gchararray"/> - <!-- column-name url --> - <column type="gchararray"/> - </columns> - </object> + <object class="GtkAction" id="action1"/> </interface>