gloss-mc/modules/video_player/video_player.py

370 lines
16 KiB
Python
Raw Normal View History

2007-08-14 18:10:53 -07:00
import pygtk
import gtk
import pygst
import gst
import gobject
import pango
2007-08-14 18:10:53 -07:00
import clutter
import os
from clutter import cluttergst
from VideoController import VideoController
from modules.video_player.elements.cover_viewer import coverViewer
from modules.video_player.elements.video_details import video_details
from modules.video_player.elements.folder_menu import folderMenu
from modules.video_player.video_object import videoItem
2007-08-14 18:10:53 -07:00
2008-01-06 04:11:17 -08:00
#===============================================================================
#This module displays a basic cover viewer for videos within myth's Mythvideo table
#It defines the following theme elements:
#video_menu_image (Texture): The graphic used on the menu to represent this module
#video_cover_bg_image (Texture): Graphic that serves as the background for the cover viewer grid
#===============================================================================
2007-11-19 03:38:15 -08:00
class Module():
title = "Videos"
STATE_FOLDERS, STATE_COVERS, STATE_VIDEO = range(3)
2008-01-06 04:11:17 -08:00
#The are just some default values to be used in case of an emergency
coverViewerWidth = 750
coverViewerHeight = 600
coverViewerPosX = 300
coverViewerPosY = 50
coverViewerRows = 3
coverViewerColumns = 4
coverDetailsWidth = 750
foldersPosX = 50
foldersPosX = 50
cover_size = int(coverViewerWidth / coverViewerColumns)
2008-02-13 15:51:35 -08:00
#Basic UI elements
currentViewer = None
backdrop = None
video_details = None
covers_background = None
2007-08-14 18:10:53 -07:00
2007-12-21 03:39:50 -08:00
def __init__(self, glossMgr, dbMgr):
self.stage = glossMgr.get_stage()
self.glossMgr = glossMgr
self.dbMgr = dbMgr
2008-01-06 04:11:17 -08:00
self.setup_ui()
self.viewerLibrary = []
self.folderLibrary = []
self.videoController = VideoController(glossMgr)
2008-01-06 04:11:17 -08:00
#Setup initial vars
2007-08-14 18:10:53 -07:00
self.is_playing = False
self.controlState = self.STATE_FOLDERS
2007-08-14 18:10:53 -07:00
#This block can be moved to begin() but causes a performance hit when loading the module *shrug*
#All it does is load the initial folders into the viewers
self.baseDir = dbMgr.get_setting("VideoStartupDir")
2008-02-13 15:51:35 -08:00
if self.glossMgr.debug: print "VideoPlayer: Base directory=" + str(self.baseDir)
self.cwd = self.baseDir
self.folder_level = 0
self.base_folder_menu = folderMenu(glossMgr, self.coverViewerRows, self.folders_cover_size)
self.base_folder_menu.set_position(self.foldersPosX, self.foldersPosY)
self.folderLibrary.append(self.base_folder_menu)
self.load_base_folders(self.baseDir, self.base_folder_menu)
#Set the current viewer
self.currentViewer = self.base_folder_menu.get_current_viewer()
2008-01-28 11:36:43 -08:00
#self.currentViewer.set_depth(self.currentViewer.cover_size)
#Create the details group
self.video_details = video_details(self.coverDetailsWidth)
self.video_details.set_position(self.coverDetailsPosX, self.coverDetailsPosY)
2008-01-06 04:11:17 -08:00
def setup_ui(self):
self.menu_image = self.glossMgr.themeMgr.get_texture("video_menu_image", None, None)
#Add the background
self.covers_background = self.glossMgr.themeMgr.get_texture("video_covers_background", self.stage, None)
#Set the number of rows / cols for the viewer (These come from the MythVideo settings in the backend DB)
tmp_rows = self.dbMgr.get_setting("VideoGalleryRowsPerPage")
tmp_cols = self.dbMgr.get_setting("VideoGalleryColsPerPage")
if not tmp_rows is None: self.coverViewerRows = int(tmp_rows)
if not tmp_cols is None: self.coverViewerColumns = int(tmp_cols)
#Set the size / position of the cover_viewer
element = self.glossMgr.themeMgr.search_docs("video_cover_viewer", "main").childNodes
(self.coverViewerWidth, self.coverViewerHeight) = self.glossMgr.themeMgr.get_dimensions(element, self.stage)
(self.coverViewerPosX, self.coverViewerPosY) = self.glossMgr.themeMgr.get_position(element, self.stage)
#Set the all important cover size
self.cover_size = int(self.coverViewerWidth / self.coverViewerColumns)
#set the size / position of the details group
element = self.glossMgr.themeMgr.search_docs("video_cover_details", "main").childNodes
(self.coverDetailsWidth, self.coverDetailsHeight) = self.glossMgr.themeMgr.get_dimensions(element, self.stage)
(self.coverDetailsPosX, self.coverDetailsPosY) = self.glossMgr.themeMgr.get_position(element, self.stage)
#set the size / position of the folder menu
element = self.glossMgr.themeMgr.search_docs("video_folder_menu", "main").childNodes
(self.foldersWidth, self.foldersHeight) = self.glossMgr.themeMgr.get_dimensions(element, self.stage)
(self.foldersPosX, self.foldersPosY) = self.glossMgr.themeMgr.get_position(element, self.stage)
self.folders_cover_size = self.foldersWidth #int(self.foldersWidth / self.coverViewerColumns)
def load_base_folders(self, dirPath, folder_menu):
2007-12-11 02:50:45 -08:00
try:
new_file_list = os.listdir(dirPath)
except os.error, (errno, errstr):
2008-02-13 15:51:35 -08:00
self.glossMgr.display_msg("VideoPlayer File Error", "Could not load Video directory")
2007-12-11 02:50:45 -08:00
return
2008-02-13 15:51:35 -08:00
#Videos and Directories
for dir_entry in new_file_list:
tempPath = dirPath + "/" + dir_entry
if os.path.isdir(tempPath) and not ( dir_entry[0] == "."):
tempViewer = coverViewer(self.glossMgr, self.coverViewerWidth, self.coverViewerHeight, self.coverViewerRows, self.coverViewerColumns)
self.loadDir(tempPath, tempViewer)
folder_menu.add_base_dir(dir_entry, tempViewer)
def loadDir(self, dirPath, cover_viewer):
if not os.path.isdir(dirPath):
2008-02-13 15:51:35 -08:00
print "ERROR VideoPlayer: Invalid video path"
return None
final_file_list = []
new_file_list = os.listdir(dirPath)
2007-12-11 02:50:45 -08:00
2008-02-13 15:51:35 -08:00
#Videos and Directories
for dir_entry in new_file_list:
if os.path.isdir(dirPath + "/" + dir_entry) and not ( dir_entry[0] == "."):
cover_viewer.add_folder(dir_entry)
2007-12-21 03:39:50 -08:00
#print dir_entry
else:
final_file_list.append(dir_entry)
#Check if we're empty
if len(final_file_list) == 0:
return
#Make sure the dirPath ends in "/"
if not dirPath[-1] == "/":
dirPath = dirPath + "/"
#Generate some SQL to retrieve videos that were in the final_file_list
#Load the videos into the cover viewer
sql = "SELECT * FROM videometadata WHERE filename IN ("
for filename in final_file_list:
filename = dirPath + filename
sql = sql + "\"" + filename + "\", "
sqlLength = int(len(sql) - 2)
sql = sql[:sqlLength]
sql = sql + ")"
2008-02-13 15:51:35 -08:00
if self.glossMgr.debug: print "Video SQL: " + sql
results = self.dbMgr.run_sql(sql)
#Check for null return
if results == None:
print "VideoPlayer: No connection to DB or no videos found in DB"
return None
#Else add the entries in
for record in results:
tempVideo = videoItem()
tempVideo.importFromMythObject(record)
cover_viewer.add_video(tempVideo)
2007-11-19 03:38:15 -08:00
#Action to take when menu item is selected
def action(self):
return self
2007-08-14 18:10:53 -07:00
def on_key_press_event (self, stage, event):
up = clutter.keysyms.Up
down = clutter.keysyms.Down
left = clutter.keysyms.Left
right= clutter.keysyms.Right
if event.keyval == clutter.keysyms.q:
clutter.main_quit()
#*****************************************************************
#"State based input handling
if self.controlState == self.STATE_FOLDERS:
if event.keyval == clutter.keysyms.Escape:
return True
elif event.keyval == right:
self.controlState = self.STATE_COVERS
self.currentViewer = self.folderLibrary[self.folder_level].get_current_viewer()
self.currentViewer.select_first()
self.folderLibrary[self.folder_level].on_key_press_event(event)
self.currentViewer = self.folderLibrary[self.folder_level].get_current_viewer()
#**********************************************************
elif self.controlState == self.STATE_VIDEO:
if event.keyval == clutter.keysyms.Escape:
self.videoController.stop_video()
self.is_playing = False
self.controlState = self.STATE_COVERS
else:
self.videoController.on_key_press_event(event)
return False
if event.keyval == clutter.keysyms.p:
if self.paused:
self.unpause()
else:
self.pause()
#**********************************************************
elif self.controlState == self.STATE_COVERS:
if (event.keyval == up) or (event.keyval == down) or (event.keyval == left) or (event.keyval == right):
timeline = self.currentViewer.on_key_press_event(event)
video = self.currentViewer.get_current_video()
#Do a check to see if the input queue is currently processing
#
if not self.currentViewer.input_queue.is_in_queue():
if not video is None:
self.video_details.set_video_bare(video)
self.currentViewer.set_details_update(False, None)
else:
self.video_details.set_folder(self.currentViewer.folderLibrary[(self.currentViewer.currentSelection-len(self.currentViewer.folderLibrary))])
#self.video_details.clear()
else:
self.currentViewer.set_details_update(True, self.video_details)
if event.keyval == clutter.keysyms.Return:
#Find whether the current item is a folder or video
item = self.currentViewer.get_current_item()
if item.isFolder:
self.glossMgr.display_msg("Msg", "Its a folder")
else:
self.play_video()
if event.keyval == clutter.keysyms.Escape:
self.currentViewer.select_none()
self.controlState = self.STATE_FOLDERS
2007-08-14 18:10:53 -07:00
2007-12-21 03:39:50 -08:00
def begin(self, glossMgr):
#Check that the library actually contains something
2007-12-11 02:50:45 -08:00
#if len(self.currentViewer.textureLibrary) == 0:
if self.currentViewer is None:
self.glossMgr.display_msg("Error: No videos", "There are no videos available in the library. This maybe caused by an empty library or a failed connection to the server.")
self.stop()
return
2007-08-14 18:10:53 -07:00
#Create a backdrop for the player. In this case we just use the same background as the menus
self.backdrop = glossMgr.get_themeMgr().get_texture("background", None, None) #clutter.CloneTexture(glossMgr.get_skinMgr().get_Background())
2007-08-14 18:10:53 -07:00
self.backdrop.set_size(self.stage.get_width(), self.stage.get_height())
self.backdrop.set_opacity(0)
self.backdrop.show()
self.stage.add(self.backdrop)
#Add the covers background
self.covers_background.set_opacity(0)
self.covers_background.show()
self.stage.add(self.covers_background)
#Add the folders menu
self.folderLibrary[0].set_opacity(0)
self.folderLibrary[0].show()
self.stage.add(self.folderLibrary[0])
#Add the cover viewer
self.currentViewer.set_opacity(0)
self.currentViewer.show_all()
self.currentViewer.show()
self.currentViewer.set_position(self.coverViewerPosX, self.coverViewerPosY)
self.stage.add(self.currentViewer)
#Add the video details
self.video_details.set_opacity(0)
self.video_details.show_all()
self.video_details.show()
self.stage.add(self.video_details)
#Fade everything in
timeline_begin = clutter.Timeline(10,40)
alpha = clutter.Alpha(timeline_begin, clutter.ramp_inc_func)
self.begin_behaviour = clutter.BehaviourOpacity(opacity_start=0, opacity_end=255, alpha=alpha)
self.begin_behaviour.apply(self.backdrop)
self.begin_behaviour.apply(self.folderLibrary[0])
self.begin_behaviour.apply(self.covers_background)
self.begin_behaviour.apply(self.currentViewer)
self.begin_behaviour.apply(self.video_details)
#self.viewerLibrary[0].set_position(50, 40)
#self.currentViewer.toggle_details() #Turns the details group on
#self.currentViewer.select_first()
2007-08-14 18:10:53 -07:00
timeline_begin.start()
#self.folder_menu = folderMenu(self.stage, self.currentViewer.num_visible_rows, self.currentViewer.cover_size)
#self.folder_menu.set_dir_cover_viewer(self.currentViewer)
2007-08-14 18:10:53 -07:00
def stop(self):
2007-12-21 03:39:50 -08:00
self.glossMgr.currentPlugin = None
#Fade everything out
timeline_stop = clutter.Timeline(10,30)
alpha = clutter.Alpha(timeline_stop, clutter.ramp_inc_func)
self.stop_behaviour = clutter.BehaviourOpacity(opacity_start=255, opacity_end=0, alpha=alpha)
if not self.currentViewer is None: self.stop_behaviour.apply(self.currentViewer)
if not self.backdrop is None: self.stop_behaviour.apply(self.backdrop)
if not self.folderLibrary[self.folder_level] is None: self.stop_behaviour.apply(self.folderLibrary[self.folder_level])
if not self.video_details is None: self.stop_behaviour.apply(self.video_details)
if not self.covers_background is None: self.stop_behaviour.apply(self.covers_background)
timeline_stop.connect('completed', self.destroyPlugin)
timeline_stop.start()
def destroyPlugin(self, data):
self.stage.remove(self.currentViewer)
self.stage.remove(self.folderLibrary[self.folder_level])
self.stage.remove(self.video_details)
self.stage.remove(self.covers_background)
self.backdrop.hide()
#self.stage.remove(self.overlay)
def play_video(self):
vid = self.currentViewer.get_current_item().video
uri = "file://" + str(vid.filename)
self.videoController.play_video(uri, self)
self.is_playing = True
self.controlState = self.STATE_VIDEO
self.stage.remove(self.currentViewer)
self.stage.remove(self.base_folder_menu)
def stop_video(self):
if not self.is_playing:
return
self.is_playing = False
2007-08-14 18:10:53 -07:00
2007-11-19 03:38:15 -08:00
timeline = clutter.Timeline(15, 25)
self.currentViewer.set_opacity(0)
self.base_folder_menu.set_opacity(0)
2007-11-19 03:38:15 -08:00
alpha = clutter.Alpha(timeline, clutter.ramp_inc_func)
self.behaviour = clutter.BehaviourOpacity(opacity_start=0, opacity_end=255, alpha=alpha)
self.behaviour.apply(self.currentViewer)
self.behaviour.apply(self.base_folder_menu)
2007-11-19 03:38:15 -08:00
self.stage.add(self.currentViewer)
self.stage.add(self.base_folder_menu)
self.currentViewer.show()
2007-11-19 03:38:15 -08:00
timeline.start()
2007-08-14 18:10:53 -07:00
def pause(self):
pass
def unpause(self):
pass
2007-08-14 18:10:53 -07:00