diff --git a/src/config.py b/src/config.py index 2d8fa38a..a45e27b3 100644 --- a/src/config.py +++ b/src/config.py @@ -1,18 +1,76 @@ -import ocarina -from ct.opts import args +################################################################################ +################################################################################ +## ## +## This configuration file applies to both ocarina-core and ocarina-extra. ## +## The ocarina-core section is to configure the variables used by ## +## ocarina-core. Most of the ocarina-core variables also apply to ## +## ocarina-extra. ## +## ## +################################################################################ +################################################################################ + +# Import helpful modules +from ocarina import vars from ct.path import * from ct.call import * -# Disable immediately playing a song when it is loaded -ocarina.vars["$playonload"] = False +# Helpful variables used by the application +# vars["$user"] is the users home directory +# vars["$ocarina"] is the directory ocarina uses to store all its files +# vars["$lockfile"] is the lockfile used by the application +# vars["$writeenable"] controls enables printing from ct.call.write() -# Load a song if we were passed one on load -space = ' ' -song = space.join(args) -if exists( song ): - load(song) +################################################################################ +################################################################################ +## ## +## Section 1.1 ocarina-core variable configuration ## +## The goal of ocarina-core is to provide a simple, command line music ## +## player built on python and gstreamer. Many of the variables set in this ## +## section also apply to ocarina-extra ## +## ## +################################################################################ +################################################################################ +# Set this variable to force verbocity to always be at the same value. +# Calling ocarina with the -v option will have no effect. A higher value will +# print more output +#vars["$verbose"] = 0 + +# Setting this variable to change the prompt that is presented to the user +# by the built in command line. This variable is only used in ocarina-core +#vars["$prompt"] = ">>>" + +# This variable controls if ocarina begins playback as soon as a song is loaded +# The default value is True +vars["$playonload"] = False + +# This variable controls the gstreamer volume at startup. Values must be +# between 0.0 and 1.0, values less than 0.0 will be changed to 0.0 and values +# greater than 1.0 will be changed to 1.0 +#vars["$volume"] = 1.0 + +# This variable controls how much the volume changes when calling +# volup() or voldown() +#vars["$volumeincr"] = 0.05 + +# This variable controls the port that ocarina listens on for requests. Other +# ocarina instances will connect to this port to forward a song to load. +# Setting this variable to 0 will cause ocarina to use a random port. +#vars["$port"] = 12345 + + + +################################################################################ +################################################################################ +## ## +## Section 1.2 ocarina-core additional configuration ## +## The rest of this section generall applies to features added to the ## +## ocarina-core command line. readline and rlcompleter, for example, are ## +## used to provide tab completion and a stored history. ## +## ## +################################################################################ +################################################################################ # Enable readline tab completion import readline diff --git a/src/core/coredefaults.py b/src/core/coredefaults.py index d69fa940..fee0eedd 100644 --- a/src/core/coredefaults.py +++ b/src/core/coredefaults.py @@ -1,31 +1,33 @@ #! /usr/bin/python -# To change this template, choose Tools | Templates -# and open the template in the editor. - __author__="bjschuma" __date__ ="$Mar 15, 2010 9:53:46 PM$" import ocarina +import os from ct import path from ct import opts from ocarina import vars +# Set the default values of ocarina variables vars["$user"] = path.expand("~") vars["$ocarina"] = path.join(vars["$user"],".ocarina3") +vars["$lockfile"] = path.join(vars["$ocarina"],"lock") +vars["$writeenable"] = True + vars["$verbose"] = 0 -vars["$path"] = "coreplug" vars["$prompt"] = ">>>" vars["$playonload"] = True vars["$playing"] = False -vars["$writeenable"] = True vars["$volume"] = 1.0 vars["$volumeincr"] = 0.05 +vars["$port"] = 0 opts.parse() path.mkdir(vars["$ocarina"]) + # Set verbose value if opts.opts.has("v") == True: @@ -33,4 +35,4 @@ if opts.opts.has("v") == True: if opts.opts.has("verbose") == True: vars["$verbose"] += opts.opts["verbose"] -import gstreamer +#import gstreamer diff --git a/src/core/ct/__init__.py b/src/core/ct/__init__.py index ff944f0b..24d9c675 100644 --- a/src/core/ct/__init__.py +++ b/src/core/ct/__init__.py @@ -2,4 +2,4 @@ __author__="bjschuma" __date__ ="$Mar 13, 2010 4:20:16 PM$" -__all__ = ["call", "dict", "opts", "path", "plugin", "slist", "times"] \ No newline at end of file +__all__ = ["call", "dict", "opts", "path", "plugin", "slist", "tcp", "times"] \ No newline at end of file diff --git a/src/core/ct/call.py b/src/core/ct/call.py index f3cb7091..3bfebb53 100644 --- a/src/core/ct/call.py +++ b/src/core/ct/call.py @@ -8,10 +8,19 @@ __date__ ="$Mar 30, 2010 11:24:43 PM$" import ocarina +import sys from ct import times from ct import path +def exit(): + '''Safely exit ocarina''' + path.rm(ocarina.vars["$lockfile"]) + import gstreamer + ocarina.events.start("ocarina-close") + sys.exit(0) + + def about(): print "Ocarina Version 3.0" print "Written by Bryan Schumaker (bjschuma@umich.edu)" diff --git a/src/core/ct/path.py b/src/core/ct/path.py index 0294de3c..818145f5 100644 --- a/src/core/ct/path.py +++ b/src/core/ct/path.py @@ -27,6 +27,12 @@ def isdir(path): if exists(path) == True: return os.path.isdir( expand(path) ) return False + + +def isfile(path): + if exists(path) == True: + return os.path.isfile(path) + return False def ls(path): @@ -36,6 +42,11 @@ def ls(path): return None +def rm(path): + if isfile(path): + os.remove(path) + + def mkdir(path): if exists(path) == False: os.mkdir(path) diff --git a/src/core/ct/tcp.py b/src/core/ct/tcp.py new file mode 100644 index 00000000..83347dc0 --- /dev/null +++ b/src/core/ct/tcp.py @@ -0,0 +1,53 @@ +#! /usr/bin/python + +# To change this template, choose Tools | Templates +# and open the template in the editor. + +__author__="bjschuma" +__date__ ="$Apr 1, 2010 12:52:37 PM$" + +import socket +import ocarina +import thread +from ct import call +from ct import path + + +def send(port,song): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect( ("localhost", port) ) + totalsent = 0 + while totalsent < len(song): + sent = s.send(song[totalsent:]) + if sent == 0: + raise RuntimeError, "Socket connection broken!" + totalsent += sent + + +def server(): + #create an INET, STREAMing socket + server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + #bind the socket to localhost at the user specified port + server.bind(("localhost", ocarina.vars["$port"])) + except: + # Bind to an os-assigned port if the user defined port fails + server.bind(("localhost",0)) + + # listen for connections with a queue size of 5 + server.listen(5) + + # Find what port we are connected to + port = server.getsockname()[1] + + def watch(addr,port): + while 1: + #accept connections from outside + (clientsocket, address) = server.accept() + message = clientsocket.recv(4096)#print clientsocket, address + if path.exists(message): + call.load(message) + thread.start_new_thread(watch,("localhost",port)) + + # Return the port we are using + return port diff --git a/src/core/gstreamer.py b/src/core/gstreamer.py index bac4e48d..de6e8d45 100644 --- a/src/core/gstreamer.py +++ b/src/core/gstreamer.py @@ -138,32 +138,32 @@ def seek(prcnt,fraction=False): def setvol(volume): global player + if volume > 1.0: + volume = 1.0 + elif volume < 0.0: + volume = 0.0 player.set_property("volume",volume) + ocarina.vars["$volume"] = volume def volup(): volume = ocarina.vars["$volume"] volume += ocarina.vars["$volumeincr"] - if volume >= 1.0: - volume = 1.0 - ocarina.vars["$volume"] = volume setvol(volume) def voldown(): volume = ocarina.vars["$volume"] volume -= ocarina.vars["$volumeincr"] - if volume <= 0.0: - volume = 0.0 - ocarina.vars["$volume"] = volume setvol(volume) bus.add_signal_watch() bus.connect("message", onMessage) -ocarina.events.invite("ocarina-stop", uninit) +ocarina.events.invite("ocarina-close", uninit) ocarina.events.invite("ocarina-play", play,50) ocarina.events.invite("ocarina-pause", pause,50) +setvol(ocarina.vars["$volume"]) # #def setvol(value): diff --git a/src/core/ocarina-core.py b/src/core/ocarina-core.py index 8f7d2e5d..05576b2a 100644 --- a/src/core/ocarina-core.py +++ b/src/core/ocarina-core.py @@ -8,6 +8,7 @@ import coredefaults import cli from ct.call import * +from ct import tcp @@ -16,8 +17,9 @@ def main(): write("Welcome to Ocarina (core)", 1) ocarina.events.start("ocarina-start") - ocarina.config() - cli.loop() + code = ocarina.config() + if code == 0: + cli.loop() if __name__ == "__main__":main() diff --git a/src/core/ocarina.py b/src/core/ocarina.py index 457dfb7c..926bbc04 100644 --- a/src/core/ocarina.py +++ b/src/core/ocarina.py @@ -14,6 +14,54 @@ global events vars = Dict() events = event.Event() + +def postConfig(): + from ct import tcp + global vars + lock = vars["$lockfile"] + + from ct.opts import args + # Load a song if we were passed one on load + space = ' ' + song = space.join(args) + #if exists( song ): + # load(song) + + # Check if another instance already has the lock + if path.exists(lock) == True: + # Print a warning message, and tell where the lock file is so the user + # can remove it if this message is in error + print "Warning: an instance of Ocarina may already be running!" + print "If this is not the case, remove the lock file located at:" + print lock + # Find the port of the other application + fin = open(lock) + port = int(fin.read()) + fin.close() + try: + # Try to send the song to the other application + tcp.send(port,song) + return -1 + except: + print "Alert: I could not connect to port",port + print "We will continue as if this is the only Ocarina" + + # Become a tcp server + port = tcp.server() + # Write the port to a file + out = open(lock,'w') + out.write( str(port)+"\n" ) + out.close() + + # Load a song if we were passed one on startup + if path.exists(song) == True: + from ct import call + call.load(song) + + return 0 + + + '''Attempt to read in a configuration file''' def config(): global vars @@ -21,3 +69,5 @@ def config(): config = "config.py" pyfile(path.join(vars["$ocarina"],config)) pyfile(config) + return postConfig() + diff --git a/src/extra/db.py b/src/extra/db.py index f63cc5ba..eb732f8d 100644 --- a/src/extra/db.py +++ b/src/extra/db.py @@ -7,7 +7,7 @@ __author__="bjschuma" __date__ ="$Jan 27, 2010 6:21:27 PM$" -from ct.message import write +from ct.call import write from sqlite3 import * from et import sql from ct.path import expand diff --git a/src/extra/et/__init__.py b/src/extra/et/__init__.py index 6fa7fdf6..f8f7b25d 100644 --- a/src/extra/et/__init__.py +++ b/src/extra/et/__init__.py @@ -1,4 +1,4 @@ __author__="bjschuma" __date__ ="$Mar 14, 2010 9:53:12 PM$" -__all__ = ["needle", "scanlib", "sql", "times", "xm"] \ No newline at end of file +__all__ = ["needle", "scanlib", "sql", "xm"] \ No newline at end of file diff --git a/src/extra/et/scanlib.py b/src/extra/et/scanlib.py index 709045f6..56c1cf43 100644 --- a/src/extra/et/scanlib.py +++ b/src/extra/et/scanlib.py @@ -10,7 +10,7 @@ __date__ ="$Jan 30, 2010 3:57:53 PM$" from et import sql #from bt import needle from ct.path import * -from ct.message import write +from ct.call import write import ocarina import index diff --git a/src/extra/extradefaults.py b/src/extra/extradefaults.py index bcc91e3c..a9a60632 100644 --- a/src/extra/extradefaults.py +++ b/src/extra/extradefaults.py @@ -9,9 +9,13 @@ __date__ ="$Mar 15, 2010 9:56:53 PM$" from ocarina import vars import coredefaults -#vars["$theme"] = "themes/simple.xml" -vars["$theme"] = "themes/classic.xml" +vars["$theme"] = "themes/simple.xml" +#vars["$theme"] = "themes/classic.xml" vars["$artist"] = "" vars["$album"] = "" vars["$title"] = "" -vars["$filterText"] = "" \ No newline at end of file +vars["$filterText"] = "" + + +import guibuilder +from oGtk import * \ No newline at end of file diff --git a/src/extra/guibuilder.py b/src/extra/guibuilder.py index 89a0f274..12aeda6d 100644 --- a/src/extra/guibuilder.py +++ b/src/extra/guibuilder.py @@ -9,7 +9,7 @@ __date__ ="$Mar 14, 2010 9:52:10 PM$" import ocarina from et import xm -from ct.message import write +from ct.call import write #from oGtk import * import gtk diff --git a/src/extra/oGtk/button.py b/src/extra/oGtk/button.py index 696c3919..37cb21df 100644 --- a/src/extra/oGtk/button.py +++ b/src/extra/oGtk/button.py @@ -6,7 +6,7 @@ __date__ ="$Mar 14, 2010 11:13:03 PM$" import gtk import ocarina import guibuilder -from ct import cmd +from ct import call class Button(gtk.Button): def __init__(self,attrs,cmd): @@ -45,14 +45,14 @@ class Button(gtk.Button): class ButtonImage(gtk.Button): - def __init__(self,attrs,stock,cmd=""): + def __init__(self,attrs,stock): gtk.Button.__init__(self) size = gtk.ICON_SIZE_BUTTON show = None hide = None shownow = True relief = gtk.RELIEF_NORMAL - self.cmd = "" + self.func = None for a in attrs: if a=="size": if attrs[a] == "large": @@ -63,8 +63,8 @@ class ButtonImage(gtk.Button): hide = attrs[a] elif a=="shownow" and attrs[a]=="false": shownow = False - elif a=="cmd": - self.cmd = attrs[a] + elif a=="func": + self.func = attrs[a] elif a=="relief": if attrs[a] == "none": relief = gtk.RELIEF_NONE @@ -86,7 +86,8 @@ class ButtonImage(gtk.Button): self.connect("clicked",self.onclick) def onclick(self,button): - cmd.run(self.cmd) + if self.func != None: + self.func() @@ -95,19 +96,19 @@ def make_button(attrs):return Button(attrs) def make_buttonplay(attrs): attrs["show"] = "ocarina-pause" attrs["hide"] = "ocarina-play" - attrs["cmd"] = "play" + attrs["func"] = call.play attrs["shownow"] = str( not ocarina.vars["$playing"] ).lower() return ButtonImage(attrs,gtk.STOCK_MEDIA_PLAY) def make_buttonpause(attrs): attrs["show"] = "ocarina-play" attrs["hide"] = "ocarina-pause" - attrs["cmd"] = "pause" + attrs["func"] = call.pause attrs["shownow"] = str( ocarina.vars["$playing"] ).lower() return ButtonImage(attrs,gtk.STOCK_MEDIA_PAUSE) def make_buttonstop(attrs): - attrs["cmd"] = "stop" + attrs["func"] = call.stop return ButtonImage(attrs,gtk.STOCK_MEDIA_STOP) diff --git a/src/extra/oGtk/dialog.py b/src/extra/oGtk/dialog.py index d17f072e..5f75374f 100644 --- a/src/extra/oGtk/dialog.py +++ b/src/extra/oGtk/dialog.py @@ -10,7 +10,7 @@ __date__ ="$Mar 18, 2010 11:48:15 AM$" import gtk import db import ocarina -import scripting +#import scripting from oGtk import progbar class FileChooser(gtk.FileChooserDialog): diff --git a/src/extra/oGtk/list.py b/src/extra/oGtk/list.py index e86435fb..f7af180b 100644 --- a/src/extra/oGtk/list.py +++ b/src/extra/oGtk/list.py @@ -13,8 +13,8 @@ import ocarina from et import needle import re import index -from ct import cmd from et import times +from ct.call import * class SongList(gtk.TreeView): @@ -63,7 +63,7 @@ class SongList(gtk.TreeView): # Add a row to the list def insert(self,trackid): file = list(db.gettrack(trackid)) - file[2] = times.ftime(file[2],False) + file[2] = times.ftime(file[2]) self.list.append(file) #self.list.insert(len(self.list),file) if self.countvar != None: @@ -93,8 +93,10 @@ class SongList(gtk.TreeView): def doubleClick(self,tree,index,col): trid = self.sort[index][0] path = db.getpath(trid) - cmd.run("load "+path) - cmd.run("play") + load(path) + play() + #cmd.run("load "+path) + #cmd.run("play") #print self.sort[index][1],self.sort[index][0] @@ -119,8 +121,8 @@ class LibraryList(SongList): ocarina.events.start("ocarina-filter-start") for track in db.getsongs(libid): self.insert(track[1]) - except: - pass + except Exception,e: + print e self.show_all() diff --git a/src/extra/oGtk/menu.py b/src/extra/oGtk/menu.py index acf2cdc5..f792382c 100644 --- a/src/extra/oGtk/menu.py +++ b/src/extra/oGtk/menu.py @@ -10,11 +10,12 @@ import gtk import ocarina import guibuilder -from ct import cmd +#from ct import cmd from oGtk import dialog from oGtk import window from et import scanlib from et import needle +from ct import call import db @@ -64,7 +65,8 @@ class MenuPlay(gtk.ImageMenuItem): self.show() def clicked(self,item): - cmd.run("play") + call.play() + #cmd.run("play") @@ -76,18 +78,19 @@ class MenuPause(gtk.ImageMenuItem): self.connect("activate",self.clicked) def clicked(self,item): - cmd.run("pause") + call.pause() class MenuStop(gtk.ImageMenuItem): def __init__(self): gtk.ImageMenuItem.__init__(self,gtk.STOCK_MEDIA_STOP) + ocarina.events.invite("ocarina-pause",self.hide) + ocarina.events.invite("ocarina-play",self.show) self.connect("activate",self.clicked) - self.show() def clicked(self,item): - cmd.run("stop") + call.stop() diff --git a/src/extra/oGtk/window.py b/src/extra/oGtk/window.py index e14c0522..45438aa4 100644 --- a/src/extra/oGtk/window.py +++ b/src/extra/oGtk/window.py @@ -11,6 +11,7 @@ import gtk import guibuilder import ocarina from oGtk import progbar +from ct import call class Window(gtk.Window): def __init__(self, attrs): @@ -34,7 +35,8 @@ class Window(gtk.Window): def onQuit(self,a,b): - ocarina.events.start(self.quitEvent) + call.exit() + #ocarina.events.start(self.quitEvent) class LibScanWin(gtk.Window): diff --git a/src/extra/ocarina-extra.py b/src/extra/ocarina-extra.py index 93820d66..049e7ac8 100644 --- a/src/extra/ocarina-extra.py +++ b/src/extra/ocarina-extra.py @@ -10,25 +10,24 @@ sys.path.append("core") import ocarina import extradefaults -from ct.message import write +from ct.call import write -import guibuilder -from oGtk import * +#import guibuilder +#from oGtk import * import gtk import gobject gobject.threads_init() -from et import needle - - def main(): # Potentially the first thing printed write("Welcome to Ocarina (extra)", 1) ocarina.events.start("ocarina-start") - gtk.main() + code = ocarina.config() + if code == 0: + gtk.main() if __name__ == "__main__":main()