- Creation of playlists
- Bulk of basic work done on AudioController
This commit is contained in:
parent
bc9c7f21a8
commit
5f03884d51
|
@ -24,18 +24,36 @@ class Backend(gobject.GObject):
|
|||
self.music_player = music_player
|
||||
self.dbMgr = music_player.dbMgr
|
||||
|
||||
self.directories = {}
|
||||
self.cache_artists = []
|
||||
self.cache_albums_by_artistID = {}
|
||||
self.cache_songs_by_albumID = {}
|
||||
self.cache_songs_by_artistID = {}
|
||||
|
||||
|
||||
self.get_directories()
|
||||
|
||||
#Setup a list of directory entries
|
||||
def get_directories(self):
|
||||
sql = "SELECT * FROM music_directories"
|
||||
if self.music_player.glossMgr.debug: print "Music Artist SQL: " + sql
|
||||
|
||||
dbMgr = mythDB()
|
||||
results = dbMgr.run_sql(sql)
|
||||
dbMgr.close_db()
|
||||
|
||||
#self.directories = [len(results)]
|
||||
for record in results:
|
||||
id = int(record[0])
|
||||
directory = record[1]
|
||||
self.directories[str(id)] = directory
|
||||
|
||||
#Returns a list of artist objects
|
||||
def get_artists(self, no_cache = False):
|
||||
#Check cache
|
||||
if (not no_cache) and (len(self.cache_artists) > 0):
|
||||
return self.cache_artists
|
||||
|
||||
#Load the videos into the cover viewer
|
||||
#Load the sql
|
||||
sql = "SELECT * FROM music_artists ORDER BY artist_name"
|
||||
if self.music_player.glossMgr.debug: print "Music Artist SQL: " + sql
|
||||
|
||||
|
@ -124,9 +142,45 @@ class Backend(gobject.GObject):
|
|||
for record in results:
|
||||
tempSong = song(self.music_player)
|
||||
tempSong.import_from_mythObject(record)
|
||||
tempSong.directory = self.directories[str(tempSong.directory_id)]
|
||||
songs.append(tempSong)
|
||||
#self.artistImageRow.add_object(tempArtist)
|
||||
self.emit("query-complete")
|
||||
self.cache_songs_by_albumID[str(id)] = songs
|
||||
return songs
|
||||
|
||||
#Given an artistID, returns a list of songs on the album
|
||||
def get_songs_by_artistID(self, id, no_cache = False):
|
||||
#Check cache
|
||||
if (not no_cache) and (self.cache_songs_by_artistID.has_key(str(id))):
|
||||
self.emit("query-complete")
|
||||
return self.cache_songs_by_artistID[str(id)]
|
||||
|
||||
|
||||
#Generate some SQL
|
||||
sql = "SELECT * FROM music_songs where artist_id='%s'" % (str(id))
|
||||
if self.music_player.glossMgr.debug: print "Music Song SQL: " + sql
|
||||
|
||||
#results = self.dbMgr.run_sql(sql)
|
||||
dbMgr = mythDB()
|
||||
results = dbMgr.run_sql(sql)
|
||||
dbMgr.close_db()
|
||||
|
||||
#Check for null return
|
||||
if results == None:
|
||||
print "MusicPlayer: No connection to DB or no songs found with artist ID %s" % (str(id))
|
||||
return None
|
||||
|
||||
pixbuf = None
|
||||
songs = []
|
||||
#Else add the entries in
|
||||
for record in results:
|
||||
tempSong = song(self.music_player)
|
||||
tempSong.import_from_mythObject(record)
|
||||
tempSong.directory = self.directories[str(tempSong.directory_id)]
|
||||
songs.append(tempSong)
|
||||
#self.artistImageRow.add_object(tempArtist)
|
||||
self.emit("query-complete")
|
||||
self.cache_songs_by_artistID[str(id)] = songs
|
||||
return songs
|
||||
|
|
@ -8,6 +8,7 @@ class MusicObject(gobject.GObject):
|
|||
|
||||
queued_threads = []
|
||||
running_threads = []
|
||||
threads_paused = False
|
||||
|
||||
#Setup signals
|
||||
__gsignals__ = {
|
||||
|
@ -26,15 +27,25 @@ class MusicObject(gobject.GObject):
|
|||
if len(self.running_threads) > self.MAX_THREADS:
|
||||
self.queued_threads.append(thread)
|
||||
else:
|
||||
self.running_threads.append(thread)
|
||||
thread.start()
|
||||
if (not self.threads_paused):
|
||||
self.running_threads.append(thread)
|
||||
thread.start()
|
||||
|
||||
return thread
|
||||
|
||||
def thread_finished(self):
|
||||
self.running_threads.pop(0)
|
||||
|
||||
if len(self.queued_threads) > 0:
|
||||
if (len(self.queued_threads) > 0) and (not self.threads_paused):
|
||||
thread = self.queued_threads.pop(0)
|
||||
self.running_threads.append(thread)
|
||||
thread.start()
|
||||
|
||||
def pause_threads(self):
|
||||
self.threads_paused = True
|
||||
|
||||
def unpause_threads(self):
|
||||
while (len(self.queued_threads) > 0) and (len(self.running_threads) < self.MAX_THREADS):
|
||||
thread = self.queued_threads.pop(0)
|
||||
self.running_threads.append(thread)
|
||||
thread.start()
|
|
@ -42,6 +42,7 @@ class song:
|
|||
self.sample_rate = mythObject[26]
|
||||
self.bitrate = mythObject[27]
|
||||
self.bpm = mythObject[28]
|
||||
self.directory_id = mythObject[29]
|
||||
|
||||
except IndexError, e:
|
||||
print "Music_Player: Found difference in DB structure for songs. Attempting to continue."
|
||||
|
|
|
@ -6,12 +6,13 @@ import threading
|
|||
from modules.music_player.backends.myth_music import Backend
|
||||
from modules.music_player.lastFM_interface import lastFM_interface
|
||||
from modules.music_player.music_object_row import MusicObjectRow
|
||||
from modules.music_player.playlist import Playlist
|
||||
from ui_elements.image_frame import ImageFrame
|
||||
from ui_elements.image_clone import ImageClone
|
||||
from ui_elements.label_list import LabelList
|
||||
|
||||
class Module:
|
||||
CONTEXT_HEADINGS, CONTEXT_ROW, CONTEXT_LIST1, CONTEXT_LIST2 = range(4)
|
||||
CONTEXT_HEADINGS, CONTEXT_ROW, CONTEXT_LIST1, CONTEXT_LIST2, CONTEXT_PLAYING = range(5)
|
||||
|
||||
title = "Music"
|
||||
num_columns = 6
|
||||
|
@ -29,6 +30,7 @@ class Module:
|
|||
self.songs = []
|
||||
|
||||
self.backend = Backend(self)
|
||||
self.playlist = Playlist(self)
|
||||
|
||||
self.artistImageRow = MusicObjectRow(self.glossMgr, self.stage.get_width(), 200, self.num_columns, self)
|
||||
|
||||
|
@ -89,6 +91,7 @@ class Module:
|
|||
self.artistImageRow.sleep = True
|
||||
self.artistImageRow.input_queue.input(event)
|
||||
#self.artistImageRow.input_queue.connect("queue-flushed", self.start_delay, self.load_albums, None)
|
||||
self.artistImageRow.objectLibrary[0].pause_threads()
|
||||
if self.queue_id == 0: self.queue_id = self.artistImageRow.input_queue.connect("queue-flushed", self.load_albums)
|
||||
self.artistImageRow.sleep = False
|
||||
|
||||
|
@ -96,6 +99,14 @@ class Module:
|
|||
elif (event.keyval == clutter.keysyms.Down):
|
||||
self.list1.select_first_elegant()
|
||||
self.current_context = self.CONTEXT_LIST1
|
||||
|
||||
elif (event.keyval == clutter.keysyms.Return):
|
||||
artist = self.artistImageRow.get_current_object()
|
||||
songs = self.backend.get_songs_by_artistID(artist.artistID)
|
||||
self.playlist.clear_songs()
|
||||
self.playlist.add_songs(songs)
|
||||
self.playlist.play()
|
||||
|
||||
elif self.current_context == self.CONTEXT_LIST1:
|
||||
|
||||
if (event.keyval == clutter.keysyms.Up):
|
||||
|
@ -129,6 +140,7 @@ class Module:
|
|||
self.artistImageRow.input_queue.disconnect(self.queue_id)
|
||||
self.queue_id = 0
|
||||
#Just a little test code
|
||||
self.artistImageRow.objectLibrary[0].unpause_threads()
|
||||
artist = self.artistImageRow.get_current_object()
|
||||
thread = threading.Thread(target=self.backend.get_albums_by_artistID, args=(artist.artistID,))
|
||||
thread.start()
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
from multimedia.AudioController import AudioController
|
||||
|
||||
class Playlist:
|
||||
|
||||
songs = []
|
||||
position = 0
|
||||
is_playing = False
|
||||
|
||||
|
||||
|
||||
def __init__(self, musicPlayer):
|
||||
self.musicPlayer = musicPlayer
|
||||
self.backend = musicPlayer.backend
|
||||
self.glossMgr = musicPlayer.glossMgr
|
||||
self.audio_controller = AudioController(self.glossMgr)
|
||||
self.audio_controller.connect("completed", self.next_song)
|
||||
|
||||
def clear_songs(self):
|
||||
self.songs = None
|
||||
self.songs = []
|
||||
|
||||
def play(self):
|
||||
if len(self.songs) == 0: return
|
||||
if self.position > len(self.songs): return
|
||||
|
||||
current_song = self.songs[self.position]
|
||||
current_song_filename = self.musicPlayer.base_dir + "/" + current_song.directory + "/" + current_song.filename
|
||||
current_song_uri = "file://" + current_song_filename
|
||||
if self.glossMgr.debug: print "Music_Player: Attempting to play file '%s'" % current_song_filename
|
||||
self.audio_controller.play_audio(current_song_uri)
|
||||
|
||||
#Called when the playback of one song finishes and the next is required
|
||||
def next_song(self):
|
||||
self.position += 1
|
||||
self.play()
|
||||
|
||||
def add_song(self, song):
|
||||
self.songs.append(song)
|
||||
|
||||
def add_songs(self, songs):
|
||||
for song in songs:
|
||||
self.songs.append(song)
|
|
@ -1,32 +1,19 @@
|
|||
import sys, clutter, clutter.cluttergst, gst, pygst, gtk, pygtk, gobject
|
||||
import threading
|
||||
import os
|
||||
from multimedia.MediaController import MediaController
|
||||
|
||||
|
||||
class VideoController(gobject.GObject):
|
||||
|
||||
#Setup signals
|
||||
__gsignals__ = {
|
||||
"playing": (
|
||||
gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, []),
|
||||
"stopped": (
|
||||
gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, [])
|
||||
}
|
||||
class AudioController(MediaController):
|
||||
|
||||
def __init__(self, glossMgr):
|
||||
gobject.GObject.__init__(self)
|
||||
self.stage = glossMgr.stage
|
||||
self.overlay = None
|
||||
self.blackdrop = None
|
||||
|
||||
# Primary video texture & sink definition
|
||||
self.video_texture = clutter.cluttergst.VideoTexture()
|
||||
self.video_sink = clutter.cluttergst.VideoSink(self.video_texture)
|
||||
self.video_texture.connect('size-change', self.set_fullscreen)
|
||||
self.video_texture.set_position(0,0)
|
||||
MediaController.__init__(self, glossMgr)
|
||||
|
||||
# Primary audio object
|
||||
self.audio = clutter.cluttergst.Audio()
|
||||
self.audio.connect("eos", self.stream_complete)
|
||||
self.media_element = self.audio
|
||||
|
||||
self.osd = osd(glossMgr)
|
||||
#self.osd = osd(glossMgr)
|
||||
|
||||
|
||||
def on_key_press_event(self, event):
|
||||
|
@ -37,211 +24,28 @@ class VideoController(gobject.GObject):
|
|||
|
||||
#self.osd.enter()
|
||||
|
||||
def play_video(self, uri, player):
|
||||
#self.customBin(uri)
|
||||
#return
|
||||
|
||||
self.player = player
|
||||
self.video_texture.set_uri(uri)
|
||||
|
||||
def play_audio(self, uri):
|
||||
self.audio.set_uri(uri)
|
||||
self.audio.set_playing(True)
|
||||
|
||||
#We need to connect to the message queue on the playbin to watch for any message (ie codec or file not found errors)
|
||||
self.bin = self.video_texture.get_playbin()
|
||||
#print "Queue: " + str(self.bin.get_property("queue_size"))
|
||||
#print "Queue: " + str(self.bin.get_property("queue_threshold"))
|
||||
#print "Queue: " + str(self.bin.get_property("queue_min_threshold"))
|
||||
bus = self.video_texture.get_playbin().get_bus()
|
||||
bus.add_signal_watch()
|
||||
bus.connect('message', self.on_bus_message)
|
||||
|
||||
#Now we can start the video
|
||||
self.video_texture.set_playing(True)
|
||||
#self.bin.set_state(gst.STATE_PAUSED)
|
||||
self.bin.set_state(gst.STATE_PLAYING)
|
||||
self.isPlaying = True
|
||||
|
||||
#decodebin = self.bin.get_by_name("decodebin0")
|
||||
#for element in decodebin.elements():
|
||||
# print "GST Element 1: " + str(element.get_name())
|
||||
#queue = decodebin.get_by_name("queue0")
|
||||
#print queue.get_name()
|
||||
#ypefind = decodebin.get_by_name("typefind")
|
||||
|
||||
#decodebin.connect("pad-added", self.on_pad_added)
|
||||
#vid = demuxer.get_by_name("video_00")
|
||||
#self.queue1 = gst.element_factory_make("queue", "queue1")
|
||||
#self.queue1.set_property("max-size-time", 50000)
|
||||
#self.queue1.set_property("max-size-buffers", 0)
|
||||
|
||||
#self.queue2 = gst.element_factory_make("queue", "queue2")
|
||||
#self.bin.add(self.queue1)
|
||||
#self.bin.add(self.queue2)
|
||||
#decodebin.link(self.queue1)
|
||||
#self.queue1.link(decodebin)
|
||||
self.video_texture.set_opacity(255)
|
||||
self.video_texture.set_position(0, 0)
|
||||
self.video_texture.show()
|
||||
#if self.video_texture.get_parent() is None:
|
||||
self.stage.add(self.video_texture)
|
||||
#self.stage.add(self.audio)
|
||||
|
||||
self.emit("playing")
|
||||
return self.video_texture
|
||||
return self.audio
|
||||
|
||||
#This handles any messages that are sent accross the playbin
|
||||
#Currently this is checking two types of msgs:
|
||||
# 1) A "codec not found" warning, at which stage playback is stopped
|
||||
# 2) A Buffering msg. This pauses the video until the buffer is at 100%
|
||||
def on_bus_message(self, bus, message):
|
||||
t = message.type
|
||||
#print "message type: " + str(t)
|
||||
if t == gst.MESSAGE_ELEMENT:
|
||||
#This occurs when an invalid codec is attempted to be played
|
||||
#Need to insert some form of message to the user here
|
||||
if self.player.glossMgr.debug: print "GStreamer Bus msg: " + message.structure.to_string()
|
||||
struc = message.structure
|
||||
if struc is None:
|
||||
return
|
||||
|
||||
if struc.get_name() == "missing-plugin":
|
||||
print "GStreamer Error (missing-plugin): " + message.structure.to_string()
|
||||
self.isPlaying = False
|
||||
self.video_texture.set_playing(False)
|
||||
self.player.stop_video()
|
||||
elif t == gst.MESSAGE_BUFFERING:
|
||||
percent = message.parse_buffering()
|
||||
print "Buffer: " + str(percent)
|
||||
if percent < 100:
|
||||
self.bin.set_state(gst.STATE_PAUSED)
|
||||
else:
|
||||
if not self.bin.get_state() == gst.STATE_PLAYING:
|
||||
self.bin.set_state(gst.STATE_PLAYING)
|
||||
elif t == gst.MESSAGE_STATE_CHANGED:
|
||||
prev, current, next = message.parse_state_changed()
|
||||
#print "State Changed. Previous state: " + str(prev)
|
||||
#print "State Changed. Current state: " + str(current)
|
||||
elif t == gst.STREAM_ERROR:
|
||||
#print "OHH NOES!"
|
||||
print "GST Stream Error: " + message.structure.to_string()
|
||||
else:
|
||||
if not self.player is None:
|
||||
if self.player.glossMgr.debug: print "GST Message: " + str(message)
|
||||
|
||||
def stop_video(self):
|
||||
if self.video_texture.get_playing():
|
||||
def stream_complete(self, audio):
|
||||
self.emit("completed")
|
||||
self.stop_audio
|
||||
|
||||
def stop_audio(self):
|
||||
if self.audio.get_playing():
|
||||
self.isPlaying = False
|
||||
self.player.stop_video()
|
||||
self.player = None
|
||||
self.video_texture.set_playing(False)
|
||||
|
||||
timeline = clutter.Timeline(15, 25)
|
||||
timeline.connect('completed', self.end_video_event)
|
||||
alpha = clutter.Alpha(timeline, clutter.ramp_inc_func)
|
||||
self.behaviour = clutter.BehaviourOpacity(opacity_start=255, opacity_end=0, alpha=alpha)
|
||||
self.behaviour.apply(self.video_texture)
|
||||
if not (self.blackdrop is None):
|
||||
self.behaviour.apply(self.blackdrop)
|
||||
self.audio.set_playing(False)
|
||||
self.emit("stopped")
|
||||
|
||||
|
||||
timeline.start()
|
||||
|
||||
def end_video_event(self, data):
|
||||
self.stage.remove(self.video_texture)
|
||||
if not (self.blackdrop is None):
|
||||
self.stage.remove(self.blackdrop)
|
||||
self.blackdrop = None
|
||||
|
||||
def customBin(self, fd):
|
||||
self.pipeline = gst.Pipeline("testPipeline")
|
||||
#self.src = gst.element_factory_make("filesrc", "src")
|
||||
#self.src.set_property("location", "test.mpg")
|
||||
self.src = gst.element_factory_make("fdsrc", "src");
|
||||
self.src.set_property("fd", int(fd))
|
||||
self.demux = gst.element_factory_make("ffdemux_mpegts", "demux")
|
||||
#self.demux = gst.element_factory_make("decodebin", "demux")
|
||||
self.queue1 = gst.element_factory_make("queue", "queue1")
|
||||
self.queue1.set_property("max-size-time", 500000)
|
||||
self.queue1.set_property("max-size-buffers", 0)
|
||||
self.queue2 = gst.element_factory_make("queue", "queue2")
|
||||
#self.deinterlace = gst.element_factory_make("ffdeinterlace", "deinterlace")
|
||||
self.vdecode = gst.element_factory_make("mpeg2dec", "vdecode")
|
||||
self.adecode = gst.element_factory_make("mad", "adecode")
|
||||
self.vsink = gst.element_factory_make("xvimagesink", "vsink")
|
||||
#self.vsink = self.video_sink #cluttergst.VideoSink(self.video_texture)
|
||||
self.asink = gst.element_factory_make("alsasink", "asink")
|
||||
|
||||
bus = self.pipeline.get_bus()
|
||||
bus.add_signal_watch()
|
||||
bus.connect('message', self.on_bus_message)
|
||||
|
||||
# add elements to the pipeline
|
||||
self.pipeline.add(self.src)
|
||||
self.pipeline.add(self.demux)
|
||||
self.pipeline.add(self.queue1)
|
||||
self.pipeline.add(self.queue2)
|
||||
self.pipeline.add(self.vdecode)
|
||||
#self.pipeline.add(self.deinterlace)
|
||||
self.pipeline.add(self.adecode)
|
||||
self.pipeline.add(self.vsink)
|
||||
self.pipeline.add(self.asink)
|
||||
|
||||
bus = self.pipeline.get_bus()
|
||||
gst.Bus.add_signal_watch (bus)
|
||||
|
||||
# we can't link demux until the audio and video pads are added
|
||||
# we need to listen for "pad-added" signals
|
||||
self.demux.connect("pad-added", self.on_pad_added)
|
||||
|
||||
# link all elements apart from demux
|
||||
print "linking..."
|
||||
gst.element_link_many(self.src, self.demux)
|
||||
gst.element_link_many(self.queue1, self.vdecode, self.vsink) #self.deinterlace, self.vsink)
|
||||
gst.element_link_many(self.queue2, self.adecode, self.asink)
|
||||
|
||||
self.pipeline.set_state(gst.STATE_PLAYING)
|
||||
|
||||
def on_pad_added(self, element, src_pad):
|
||||
caps = src_pad.get_caps()
|
||||
name = caps[0].get_name()
|
||||
# link demux to vdecode when video/mpeg pad added to demux
|
||||
if name == "video/mpeg":
|
||||
sink_pad = self.queue1.get_pad("sink")
|
||||
elif name == "audio/mpeg":
|
||||
sink_pad = self.queue2.get_pad("sink")
|
||||
else:
|
||||
return
|
||||
if not sink_pad.is_linked():
|
||||
src_pad.link(sink_pad)
|
||||
|
||||
def set_fullscreen(self, texture, width, height):
|
||||
texture.set_property("sync-size", False)
|
||||
texture.set_position(0, 0)
|
||||
ratio = float(self.stage.get_width()) / float(width)
|
||||
xy_ratio = float(width) / float(height)
|
||||
#print "Width: " + str(width)
|
||||
#print "Height: " + str(height)
|
||||
#print "XY Ratio: " + str(ratio)
|
||||
|
||||
width = int(self.stage.get_width())
|
||||
height = int ((height * ratio))
|
||||
#print "New Width: " + str(width)
|
||||
#print "New Height: " + str(height)
|
||||
|
||||
if height < self.stage.get_height():
|
||||
#Create a black backdrop that the video can sit on
|
||||
self.blackdrop = clutter.Rectangle()
|
||||
self.blackdrop.set_color(clutter.color_parse('Black'))
|
||||
self.blackdrop.set_size(self.stage.get_width(), self.stage.get_height())
|
||||
self.stage.remove(self.video_texture)
|
||||
self.stage.add(self.blackdrop)
|
||||
self.stage.add(self.video_texture)
|
||||
self.blackdrop.show()
|
||||
|
||||
#And move the video into the vertical center
|
||||
pos_y = int((self.stage.get_height() - height) / 2)
|
||||
self.video_texture.set_position(0, pos_y)
|
||||
|
||||
texture.set_size(width, height)
|
||||
|
||||
def pause_video(self, use_backdrop):
|
||||
def pause_audio(self, use_backdrop):
|
||||
if use_backdrop:
|
||||
#Use the overlay to go over show
|
||||
if self.overlay == None:
|
||||
|
@ -266,7 +70,7 @@ class VideoController(gobject.GObject):
|
|||
#Pause the video
|
||||
self.video_texture.set_playing(False)
|
||||
|
||||
def unpause_video(self):
|
||||
def unpause_audio(self):
|
||||
if not self.overlay is None:
|
||||
#Fade the backdrop in
|
||||
timeline_unpause = clutter.Timeline(10,30)
|
||||
|
@ -297,152 +101,4 @@ class VideoController(gobject.GObject):
|
|||
#Until then use:
|
||||
self.video_texture.set_property("position", int(new_pos))
|
||||
self.osd.shift_video(self.video_texture, amount)
|
||||
|
||||
import time
|
||||
|
||||
class osd:
|
||||
|
||||
def __init__(self, glossMgr):
|
||||
self.glossMgr = glossMgr
|
||||
self.stage = glossMgr.stage
|
||||
self.timerRunning = False
|
||||
self.setup_ui()
|
||||
|
||||
self.bar_group = clutter.Group()
|
||||
|
||||
|
||||
#self.background = clutter.Texture()
|
||||
#self.background.set_pixbuf( gtk.gdk.pixbuf_new_from_file("ui/default/osd_bar3.png") )
|
||||
#self.background.set_opacity(255)
|
||||
#self.background.set_width(stage.get_width())
|
||||
self.bar_group.add(self.background)
|
||||
self.bar_group.show_all()
|
||||
|
||||
def setup_ui(self):
|
||||
self.background = self.glossMgr.themeMgr.get_texture("video_osd_bar", self.stage, None)
|
||||
|
||||
def enter(self):
|
||||
self.stage.add(self.bar_group)
|
||||
self.bar_group.show()
|
||||
|
||||
self.bar_group.set_position(0, self.stage.get_height())
|
||||
bar_position_y = int(self.stage.get_height() - self.background.get_height())
|
||||
|
||||
knots = (\
|
||||
(self.bar_group.get_x(), self.bar_group.get_y()),\
|
||||
(self.bar_group.get_x(), bar_position_y) \
|
||||
)
|
||||
|
||||
self.timeline = clutter.Timeline(25, 50)
|
||||
self.alpha = clutter.Alpha(self.timeline, clutter.ramp_inc_func)
|
||||
self.enter_behaviour_path = clutter.BehaviourPath(self.alpha, knots)
|
||||
|
||||
self.enter_behaviour_path.apply(self.bar_group)
|
||||
|
||||
self.timeline.start()
|
||||
|
||||
self.timer = threading.Timer(3.0, self.exit)
|
||||
self.timer.start()
|
||||
|
||||
def exit(self):
|
||||
|
||||
knots = (\
|
||||
(self.bar_group.get_x(), self.bar_group.get_y()),\
|
||||
(self.bar_group.get_x(), int(self.stage.get_height())) \
|
||||
)
|
||||
|
||||
self.timeline = clutter.Timeline(25, 50)
|
||||
self.timeline.connect('completed', self.exit_end_event)
|
||||
self.alpha = clutter.Alpha(self.timeline, clutter.ramp_inc_func)
|
||||
self.exit_behaviour_path = clutter.BehaviourPath(self.alpha, knots)
|
||||
|
||||
self.exit_behaviour_path.apply(self.bar_group)
|
||||
self.timeline.start()
|
||||
|
||||
def exit_end_event(self, data):
|
||||
self.stage.remove(self.bar_group)
|
||||
|
||||
#Is called when the video is skipped forwards or backwards
|
||||
def shift_video(self, video, shift_amount):
|
||||
#Firstly check whether the label is already there from last time
|
||||
if self.timerRunning:
|
||||
#self.timer.cancel()
|
||||
#self.timer = threading.Timer(1.5, self.label_exit)
|
||||
#self.timerRunning = True
|
||||
#self.timer.start()
|
||||
return
|
||||
|
||||
shiftDistance = 100
|
||||
|
||||
self.shift_label = clutter.Label()
|
||||
self.shift_label.set_font_name("Lucida Grande 60")
|
||||
self.shift_label.set_opacity(0)
|
||||
self.shift_label.set_color(clutter.color_parse('White'))
|
||||
|
||||
#Set the string for the fast forward / rewind as well as the
|
||||
if shift_amount > 0:
|
||||
self.shift_label.set_text("+" + str(shift_amount) + "s >")
|
||||
shift_label_x = int(self.stage.get_width() - self.shift_label.get_width() - shiftDistance)
|
||||
direction = 1
|
||||
else:
|
||||
self.shift_label.set_text("< " + str(shift_amount) + "s")
|
||||
shift_label_x = int(0 + shiftDistance)
|
||||
direction = -1
|
||||
|
||||
shift_label_y = int(self.stage.get_height() - self.shift_label.get_height())
|
||||
self.shift_label.set_position( shift_label_x, shift_label_y )
|
||||
incoming_label_knots = (\
|
||||
( shift_label_x, shift_label_y ),\
|
||||
( int(shift_label_x + (shiftDistance*direction)), shift_label_y )\
|
||||
)
|
||||
|
||||
self.incoming_text_timeline = clutter.Timeline(20, 60)
|
||||
alpha = clutter.Alpha(self.incoming_text_timeline, clutter.ramp_inc_func)
|
||||
self.behaviour1 = clutter.BehaviourPath(alpha, incoming_label_knots)
|
||||
self.behaviour2 = clutter.BehaviourOpacity(opacity_start=0, opacity_end=120, alpha=alpha)
|
||||
|
||||
self.behaviour1.apply(self.shift_label)
|
||||
self.behaviour2.apply(self.shift_label)
|
||||
self.stage.add(self.shift_label)
|
||||
self.shift_label.show()
|
||||
|
||||
#self.timer = threading.Timer(1.5, self.label_exit)
|
||||
gobject.timeout_add(1500, self.label_exit)
|
||||
self.timerRunning = True
|
||||
#self.timer.start()
|
||||
|
||||
self.incoming_text_timeline.start()
|
||||
#print time.strftime("%H:%M:%S", time.gmtime(amount))
|
||||
|
||||
def label_exit(self):
|
||||
self.timerRunning = False
|
||||
#Check which way this label needs to go
|
||||
if self.shift_label.get_text()[0] == "<":
|
||||
end_x = int(self.shift_label.get_width() * -1)
|
||||
else:
|
||||
end_x = int(self.stage.get_width())
|
||||
|
||||
(starting_pos_x, starting_pos_y) = self.shift_label.get_abs_position()
|
||||
outgoing_label_knots = (\
|
||||
( starting_pos_x, starting_pos_y ),\
|
||||
( end_x, starting_pos_y )\
|
||||
)
|
||||
|
||||
self.outgoing_text_timeline = clutter.Timeline(20, 60)
|
||||
self.outgoing_text_timeline.connect('completed', self.removeLabel)
|
||||
alpha = clutter.Alpha(self.outgoing_text_timeline, clutter.ramp_inc_func)
|
||||
self.behaviour1 = clutter.BehaviourPath(alpha, outgoing_label_knots)
|
||||
self.behaviour2 = clutter.BehaviourOpacity(opacity_start=self.shift_label.get_opacity() , opacity_end=0, alpha=alpha)
|
||||
|
||||
self.behaviour1.apply(self.shift_label)
|
||||
self.behaviour2.apply(self.shift_label)
|
||||
|
||||
self.outgoing_text_timeline.start()
|
||||
|
||||
return False
|
||||
|
||||
def removeLabel(self, data):
|
||||
self.stage.remove(self.shift_label)
|
||||
|
||||
|
||||
|
||||
|
|
@ -8,6 +8,8 @@ class MediaController(gobject.GObject):
|
|||
__gsignals__ = {
|
||||
"playing": (
|
||||
gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, []),
|
||||
"completed": (
|
||||
gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, []),
|
||||
"stopped": (
|
||||
gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, [])
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue