Warning: mysql_connect() [function.mysql-connect]: Access denied for user 'db36126_wm161'@'64.13.192.44' (using password: YES) in /nfs/c01/h15/mnt/36126/domains/wm161.net/html/download.php on line 6

Warning: mysql_select_db() [function.mysql-select-db]: Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2) in /nfs/c01/h15/mnt/36126/domains/wm161.net/html/download.php on line 7

Warning: mysql_select_db() [function.mysql-select-db]: A link to the server could not be established in /nfs/c01/h15/mnt/36126/domains/wm161.net/html/download.php on line 7

Warning: Cannot modify header information - headers already sent by (output started at /nfs/c01/h15/mnt/36126/domains/wm161.net/html/download.php:6) in /nfs/c01/h15/mnt/36126/domains/wm161.net/html/download.php on line 86

Warning: Cannot modify header information - headers already sent by (output started at /nfs/c01/h15/mnt/36126/domains/wm161.net/html/download.php:6) in /nfs/c01/h15/mnt/36126/domains/wm161.net/html/download.php on line 87

Warning: mysql_query() [function.mysql-query]: Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2) in /nfs/c01/h15/mnt/36126/domains/wm161.net/html/download.php on line 90

Warning: mysql_query() [function.mysql-query]: A link to the server could not be established in /nfs/c01/h15/mnt/36126/domains/wm161.net/html/download.php on line 90

Warning: mysql_affected_rows() [function.mysql-affected-rows]: A link to the server could not be established in /nfs/c01/h15/mnt/36126/domains/wm161.net/html/download.php on line 91

Warning: mysql_query() [function.mysql-query]: Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2) in /nfs/c01/h15/mnt/36126/domains/wm161.net/html/download.php on line 94

Warning: mysql_query() [function.mysql-query]: A link to the server could not be established in /nfs/c01/h15/mnt/36126/domains/wm161.net/html/download.php on line 94
#!/usr/bin/env python ############################################################################ # Transcoder for Amarok # v1.2 # - Added support to tag the outputted files using TagLib # - Ported DCOP calls to use pyKDE # v1.1 # - Fixed typo in lame encoder (tcuya from kde-apps.org) # - Made setting maxjobs easier, although Amarok doesn't appear to issue # multiple requests :( # # Depends on: Python 2.2 # # The only user servicable part is the encode/decode (line 101) setup. # ############################################################################ # # Copyright (C) 2007 Daniel O'Connor. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # ############################################################################ import ConfigParser import os import sys import string import signal import logging import select import subprocess import tempfile from logging.handlers import RotatingFileHandler import urllib import urlparse import re import tagpy from dcopext import DCOPClient, DCOPApp class QueueMgr: queuedjobs = [] activejobs = [] def __init__(self, callback = None, maxjobs = 2): self.callback = callback self.maxjobs = maxjobs pass def add(self, job): log.debug("Job added") self.queuedjobs.append(job) def poll(self): """ Poll active jobs and check if we should make a new job active """ if (len(self.activejobs) == 0): needajob = True else: needajob = False for j in self.activejobs: if j.isfinished(): log.debug("job is done") needajob = True self.activejobs.remove(j) if (self.callback != None): self.callback(j) if needajob: #log.debug("Number of queued jobs = " + str(len(self.queuedjobs)) + ", number of active jobs = " + str(len(self.activejobs))) while len(self.queuedjobs) > 0 and len(self.activejobs) < self.maxjobs: newjob = self.queuedjobs.pop(0) newjob.start() self.activejobs.append(newjob) def isidle(self): """ Returns true if both queues are empty """ return(len(self.queuedjobs) == 0 and len(self.activejobs) == 0) class TranscodeJob: # Programs used to decode (to a wav stream) decode = {} decode["mp3"] = ["mpg123", "-w", "-", "-"] decode["ogg"] = ["ogg123", "-d", "wav", "-f", "-", "-"] # XXX: this is really fugly but faad refuses to read from a pipe decode["mp4"] = ["env", "MPLAYER_VERBOSE=-100", "mplayer", "-ao", "pcm:file=/dev/stdout", "-"] decode["m4a"] = decode["mp4"] # Programs used to encode (from a wav stream) encode = {} encode["mp3"] = ["lame", "--abr", "128", "-", "-"] encode["ogg"] = ["oggenc", "-q", "2", "-"] encode["mp4"] = ["faac", "-o", "/dev/stdout", "-"] encode["m4a"] = encode["mp4"] # Arguments supplied to tag output files tag = {} tag["mp3"] = {"title":"--tt", "artist":"--ta", "album":"--tl", "year":"--ty", "genre":"--tg", "track":"--tn", "year":"--ty", "comment":"--tc"} tag["ogg"] = {"title":"--title", "album":"--album", "artist":"--artist", "genre":"--genre", "track":"--tracknum"} tag["mp4"] = {"title":"--title", "artist":"--artist", "genre":"--genre", "album":"--album", "track":"--track", "year":"--year", "comment":"--comment"} tag["m4a"] = tag["mp4"] def __init__(self, _inurl, _tofmt): self.errormsg = None log.debug("Creating job") self.inurl = _inurl self.tofmt = string.lower(_tofmt) self.inext = string.lower(string.rsplit(self.inurl, ".", 1)[1]) if (self.inext in self.decode): log.debug("can decode with " + str(self.decode[self.inext])) else: log.debug("unable to decode " + self.inext) raise KeyError("no available decoder") if (self.tofmt in self.encode): log.debug("can encode with " + str(self.encode[self.tofmt])) else: log.debug("unable to encode " + self.tofmt) raise KeyError("no available encoder") def start(self): log.debug("Starting job") try: self.inputfile = urllib.urlopen(self.inurl) self.outfd, self.outfname = tempfile.mkstemp(prefix="transcode-", suffix="." + self.tofmt) #self.outfname = string.join(string.rsplit(self.inurl, ".")[:-1] + [self.tofmt], ".") self.errfh, self.errfname = tempfile.mkstemp(prefix="transcode-", suffix=".log") self.outurl = urlparse.urlunsplit(["file", None, self.outfname, None, None]) log.debug("Outputting to " + self.outfname + " " + self.outurl + ")") log.debug("Errors to " + self.errfname) self.decoder = subprocess.Popen(self.decode[self.inext], stdin=self.inputfile, stdout=subprocess.PIPE, stderr=self.errfh) self.encoder = subprocess.Popen(self.encode[self.tofmt], stdin=self.decoder.stdout, stdout=self.outfd, stderr=self.errfh) log.debug("Processes connected") except Exception, e: log.debug("Failed to start - " + str(e)) self.errormsg = str(e) try: os.unlink(self.outfname) except: pass def isfinished(self): if (self.errormsg != None): return(True) rtn = self.encoder.poll() if (rtn == None): return(False) if (rtn == 0): inTag = tagpy.FileRef(urllib.unquote(self.inurl.replace("file://",""))).tag() if inTag is not None: tagFile = tagpy.FileRef(self.outfname) outTag = tagFile.tag() outTag.setArtist(inTag.artist()) outTag.setAlbum(inTag.album()) outTag.setTitle(inTag.title()) outTag.setYear(inTag.year()) outTag.setTrack(inTag.track()) tagFile.save() os.unlink(self.errfname) self.errormsg = None else: log.debug("error in transcode, please review " + self.errfname) self.errormsg = "Unable to transcode, please review " + self.errfname try: os.unlink(self.outfname) except: pass return(True) #for tagName, switch in self.tag[self.tofmt].iteritems(): # if tagName == "title": #outTag.setTitle(inTag.title()) #if tagName == "artist": #outTag.setArtist(inTag.artist()) #if tagName == "album": #encodeArgs.append(switch) #encodeArgs.append(tags.album()) #if tagName == "genre": #encodeArgs.append(switch) #encodeArgs.append(tags.genre()) #if tagName == "track": #encodeArgs.append(switch) #encodeArgs.append(tags.track()) #if tagName == "year": #encodeArgs.append(switch) #encodeArgs.append(tags.year()) ############################################################################ # amaKode ############################################################################ class amaKode: """ The main application""" def __init__(self, args): """ Main loop waits for something to do then does it """ log.debug("Started.") self.readSettings() self.queue = QueueMgr(callback = self.notify, maxjobs = 1) while True: # Check for finished jobs, etc self.queue.poll() # Check if there's anything waiting on stdin res = select.select([sys.stdin.fileno()], [], [], 0.1) if (sys.stdin.fileno() in res[0]): # Let's hope we got a whole line or we stall here line = sys.stdin.readline() if line: self.customEvent(line) else: break def readSettings(self): """ Reads settings from configuration file """ try: foovar = config.get("General", "foo") except: log.debug("No config file found, using defaults.") def customEvent(self, string): """ Handles notifications """ #log.debug("Received notification: " + str(string)) if string.find("transcode") != -1: self.transcode(str(string)) if string.find("quit") != -1: self.quit() def transcode(self, line): """ Called when requested to transcode a track """ args = string.split(line) if (len(args) != 3): log.debug("Invalid transcode command") return log.debug("transcoding " + args[1] + " to " + args[2]) try: newjob = TranscodeJob(args[1], args[2]) except: log.debug("Can't create transcoding job") ok, void = transcodingFinished(re.escape(args[0]), "") self.queue.add(newjob) def notify(self, job): """ Report to amarok that the job is done """ if (job.errormsg == None): log.debug("Job " + job.inurl + " completed successfully.") log.debug("Moving to " + job.outurl + ".") ok, void = transcodingFinished(job.inurl, job.outurl) else: log.debug("Job " + job.inurl + " failed - " + job.errormsg) ok, void = transcodingFinished(job.inurl, "") def quit(self): log.debug("quitting") sys.exit() ############################################################################ def debug(message): """ Prints debug message to stdout """ log.debug(message) def onStop(signum, stackframe): """ Called when script is stopped by user """ log.debug("signalled exit") sys.exit() def initLog(): # Init our logging global log log = logging.getLogger("amaKode") # Default to warts and all logging log.setLevel(logging.DEBUG) # Log to this file logfile = logging.handlers.RotatingFileHandler(filename = "/tmp/amakode.log", maxBytes = 10000, backupCount = 3) # And stderr logstderr = logging.StreamHandler() # Format it nicely formatter = logging.Formatter("[%(name)s] %(message)s") # Glue it all together logfile.setFormatter(formatter) logstderr.setFormatter(formatter) log.addHandler(logfile) log.addHandler(logstderr) return(log) def reportJob(job): """ Report to amarok that the job is done """ if (job.errormsg == None): log.debug("Job " + job.inurl + " completed successfully") ok, void = transcodingFinished(job.inurl, job.outurl) else: log.debug("Job " + job.inurl + " failed - " + job.errormsg) ok, void = transcodingFinished(job.inurl, "") def initDCOP(dcopClient=None): if dcopClient is None: dcopClient = DCOPClient() dcopClient.attach() return DCOPApp('amarok',dcopClient) # Global Variables amarok = initDCOP() transcodingFinished = amarok.mediabrowser.transcodingFinished if __name__ == "__main__": initLog() signal.signal(signal.SIGINT, onStop) signal.signal(signal.SIGHUP, onStop) signal.signal(signal.SIGTERM, onStop) if 1: # Run normal application app = amaKode(sys.argv) else: # Quick test case q = QueueMgr(reportJob) j = TranscodeJob("file:///tmp/test.mp3", "ogg") q.add(j) j2 = TranscodeJob("file:///tmp/test2.mp3", "m4a") q.add(j2) while not q.isidle(): q.poll() res = select.select([], [], [], 1) log.debug("jobs all done")