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")