mirror of
https://github.com/clinton-hall/nzbToMedia.git
synced 2025-08-21 05:43:16 -07:00
clean up files
This commit is contained in:
parent
99a6dab498
commit
608a0f1eaa
10 changed files with 0 additions and 1303 deletions
|
@ -1,93 +0,0 @@
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
import ConfigParser
|
|
||||||
import logging
|
|
||||||
from subprocess import call
|
|
||||||
|
|
||||||
Logger = logging.getLogger()
|
|
||||||
|
|
||||||
def Transcode_directory(dirName):
|
|
||||||
|
|
||||||
if os.name == 'nt':
|
|
||||||
ffmpeg = os.path.join(os.path.dirname(sys.argv[0]), 'ffmpeg\\bin\\ffmpeg.exe') # note, will need to package in this dir.
|
|
||||||
if not os.path.isfile(ffmpeg): # problem
|
|
||||||
Logger.error("ffmpeg not found. ffmpeg needs to be located at: %s", ffmpeg)
|
|
||||||
Logger.info("Cannot transcode files in folder %s", dirName)
|
|
||||||
return 1 # failure
|
|
||||||
else:
|
|
||||||
if call(['which', ffmpeg]):
|
|
||||||
res = call([os.path.join(os.path.dirname(sys.argv[0]),'getffmpeg.sh')])
|
|
||||||
if res or call(['which', ffmpeg]): # did not install or ffmpeg still not found.
|
|
||||||
Logger.error("Failed to install ffmpeg. Please install manually")
|
|
||||||
Logger.info("Cannot transcode files in folder %s", dirName)
|
|
||||||
return 1 # failure
|
|
||||||
else:
|
|
||||||
ffmpeg = 'ffmpeg'
|
|
||||||
|
|
||||||
config = ConfigParser.ConfigParser()
|
|
||||||
configFilename = os.path.join(os.path.dirname(sys.argv[0]), "autoProcessMedia.cfg")
|
|
||||||
Logger.info("Loading config from %s", configFilename)
|
|
||||||
|
|
||||||
if not os.path.isfile(configFilename):
|
|
||||||
Logger.error("You need an autoProcessMedia.cfg file - did you rename and edit the .sample?")
|
|
||||||
return 1 # failure
|
|
||||||
|
|
||||||
config.read(configFilename)
|
|
||||||
|
|
||||||
mediaContainer = (config.get("Extensions", "mediaExtensions")).split(',')
|
|
||||||
duplicate = int(config.get("Transcoder", "duplicate"))
|
|
||||||
ignoreExtensions = (config.get("Transcoder", "ignoreExtensions")).split(',')
|
|
||||||
outputVideoExtension = config.get("Transcoder", "outputVideoExtension")
|
|
||||||
outputVideoCodec = config.get("Transcoder", "outputVideoCodec")
|
|
||||||
outputVideoFramerate = config.get("Transcoder", "outputVideoFramerate")
|
|
||||||
outputVideoBitrate = config.get("Transcoder", "outputVideoBitrate")
|
|
||||||
outputAudioCodec = config.get("Transcoder", "outputAudioCodec")
|
|
||||||
outputAudioBitrate = config.get("Transcoder", "outputAudioBitrate")
|
|
||||||
|
|
||||||
Logger.info("Checking for files to be transcoded")
|
|
||||||
final_result = 0 # initialize as successful
|
|
||||||
for dirpath, dirnames, filenames in os.walk(dirName):
|
|
||||||
for file in filenames:
|
|
||||||
filePath = os.path.join(dirpath, file)
|
|
||||||
name, ext = os.path.splitext(filePath)
|
|
||||||
if ext in mediaContainer: # If the file is a video file
|
|
||||||
if ext in ignoreExtensions:
|
|
||||||
Logger.info("No need to transcode video type %s", ext)
|
|
||||||
continue
|
|
||||||
if ext == outputVideoExtension: # we need to change the name to prevent overwriting itself.
|
|
||||||
outputVideoExtension = '-transcoded' + outputVideoExtension # adds '-transcoded.ext'
|
|
||||||
newfilePath = os.path.normpath(name + outputVideoExtension)
|
|
||||||
|
|
||||||
command = [ffmpeg, '-i', filePath]
|
|
||||||
if outputVideoCodec:
|
|
||||||
command.append('-c:v')
|
|
||||||
command.append(outputVideoCodec)
|
|
||||||
if outputVideoFramerate:
|
|
||||||
command.append('-r')
|
|
||||||
command.append(outputVideoFramerate)
|
|
||||||
if outputVideoBitrate:
|
|
||||||
command.append('-b:v')
|
|
||||||
command.append(outputVideoBitrate)
|
|
||||||
if outputAudioCodec:
|
|
||||||
command.append('-c:a')
|
|
||||||
command.append(outputAudioCodec)
|
|
||||||
if outputAudioBitrate:
|
|
||||||
command.append('-b:a')
|
|
||||||
command.append(outputAudioBitrate)
|
|
||||||
command.append(newfilePath)
|
|
||||||
|
|
||||||
Logger.debug("Transcoding video %s to %s", filePath, newfilePath)
|
|
||||||
result = 1 # set result to failed in case call fails.
|
|
||||||
try:
|
|
||||||
result = call(command)
|
|
||||||
except e:
|
|
||||||
Logger.error("Transcoding of video %s failed due to: ", filePath, str(e))
|
|
||||||
if result == 0:
|
|
||||||
Logger.info("Transcoding of video %s to %s succeded", filePath, newfilePath)
|
|
||||||
if duplicate == 0: # we get rid of the original file
|
|
||||||
os.unlink(filePath)
|
|
||||||
else:
|
|
||||||
Logger.error("Transcoding of video %s to %s failed", filePath, newfilePath)
|
|
||||||
# this will be 0 (successful) it all are sucessful, else will return a positive integer for failure.
|
|
||||||
final_result = final_result + result
|
|
||||||
return final_result
|
|
|
@ -1,92 +0,0 @@
|
||||||
import sys
|
|
||||||
import urllib
|
|
||||||
import os.path
|
|
||||||
import time
|
|
||||||
import ConfigParser
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from nzbToMediaEnv import *
|
|
||||||
from nzbToMediaSceneExceptions import process_all_exceptions
|
|
||||||
|
|
||||||
Logger = logging.getLogger()
|
|
||||||
|
|
||||||
class AuthURLOpener(urllib.FancyURLopener):
|
|
||||||
def __init__(self, user, pw):
|
|
||||||
self.username = user
|
|
||||||
self.password = pw
|
|
||||||
self.numTries = 0
|
|
||||||
urllib.FancyURLopener.__init__(self)
|
|
||||||
|
|
||||||
def prompt_user_passwd(self, host, realm):
|
|
||||||
if self.numTries == 0:
|
|
||||||
self.numTries = 1
|
|
||||||
return (self.username, self.password)
|
|
||||||
else:
|
|
||||||
return ('', '')
|
|
||||||
|
|
||||||
def openit(self, url):
|
|
||||||
self.numTries = 0
|
|
||||||
return urllib.FancyURLopener.open(self, url)
|
|
||||||
|
|
||||||
|
|
||||||
def processEpisode(dirName, nzbName=None, status=0):
|
|
||||||
|
|
||||||
config = ConfigParser.ConfigParser()
|
|
||||||
configFilename = os.path.join(os.path.dirname(sys.argv[0]), "autoProcessMedia.cfg")
|
|
||||||
Logger.info("Loading config from %s", configFilename)
|
|
||||||
|
|
||||||
if not os.path.isfile(configFilename):
|
|
||||||
Logger.error("You need an autoProcessMedia.cfg file - did you rename and edit the .sample?")
|
|
||||||
return 1 # failure
|
|
||||||
|
|
||||||
try:
|
|
||||||
fp = open(configFilename, "r")
|
|
||||||
config.readfp(fp)
|
|
||||||
fp.close()
|
|
||||||
except IOError, e:
|
|
||||||
Logger.error("Could not read configuration file: %s", str(e))
|
|
||||||
return 1 # failure
|
|
||||||
|
|
||||||
host = config.get("Mylar", "host")
|
|
||||||
port = config.get("Mylar", "port")
|
|
||||||
username = config.get("Mylar", "username")
|
|
||||||
password = config.get("Mylar", "password")
|
|
||||||
try:
|
|
||||||
ssl = int(config.get("Mylar", "ssl"))
|
|
||||||
except (ConfigParser.NoOptionError, ValueError):
|
|
||||||
ssl = 0
|
|
||||||
|
|
||||||
try:
|
|
||||||
web_root = config.get("Mylar", "web_root")
|
|
||||||
except ConfigParser.NoOptionError:
|
|
||||||
web_root = ""
|
|
||||||
|
|
||||||
params = {}
|
|
||||||
|
|
||||||
params['nzb_folder'] = dirName
|
|
||||||
if nzbName != None:
|
|
||||||
params['nzb_name'] = nzbName
|
|
||||||
|
|
||||||
myOpener = AuthURLOpener(username, password)
|
|
||||||
|
|
||||||
if ssl:
|
|
||||||
protocol = "https://"
|
|
||||||
else:
|
|
||||||
protocol = "http://"
|
|
||||||
|
|
||||||
url = protocol + host + ":" + port + web_root + "/post_process?" + urllib.urlencode(params)
|
|
||||||
|
|
||||||
Logger.debug("Opening URL: %s", url)
|
|
||||||
|
|
||||||
try:
|
|
||||||
urlObj = myOpener.openit(url)
|
|
||||||
except IOError, e:
|
|
||||||
Logger.error("Unable to open URL: %s", str(e))
|
|
||||||
return 1 # failure
|
|
||||||
|
|
||||||
result = urlObj.readlines()
|
|
||||||
for line in result:
|
|
||||||
Logger.info("%s", line)
|
|
||||||
|
|
||||||
time.sleep(60) #wait 1 minute for now... need to see just what gets logged and how long it takes to process
|
|
||||||
return 0 # Success
|
|
|
@ -1,94 +0,0 @@
|
||||||
import sys
|
|
||||||
import urllib
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
import ConfigParser
|
|
||||||
import datetime
|
|
||||||
import time
|
|
||||||
import json
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from nzbToMediaEnv import *
|
|
||||||
|
|
||||||
Logger = logging.getLogger()
|
|
||||||
|
|
||||||
class AuthURLOpener(urllib.FancyURLopener):
|
|
||||||
def __init__(self, user, pw):
|
|
||||||
self.username = user
|
|
||||||
self.password = pw
|
|
||||||
self.numTries = 0
|
|
||||||
urllib.FancyURLopener.__init__(self)
|
|
||||||
|
|
||||||
def prompt_user_passwd(self, host, realm):
|
|
||||||
if self.numTries == 0:
|
|
||||||
self.numTries = 1
|
|
||||||
return (self.username, self.password)
|
|
||||||
else:
|
|
||||||
return ('', '')
|
|
||||||
|
|
||||||
def openit(self, url):
|
|
||||||
self.numTries = 0
|
|
||||||
return urllib.FancyURLopener.open(self, url)
|
|
||||||
|
|
||||||
def process(dirName, nzbName=None, status=0):
|
|
||||||
|
|
||||||
status = int(status)
|
|
||||||
config = ConfigParser.ConfigParser()
|
|
||||||
configFilename = os.path.join(os.path.dirname(sys.argv[0]), "autoProcessMedia.cfg")
|
|
||||||
Logger.info("Loading config from %s", configFilename)
|
|
||||||
|
|
||||||
if not os.path.isfile(configFilename):
|
|
||||||
Logger.error("You need an autoProcessMedia.cfg file - did you rename and edit the .sample?")
|
|
||||||
return 1 # failure
|
|
||||||
|
|
||||||
config.read(configFilename)
|
|
||||||
|
|
||||||
host = config.get("Gamez", "host")
|
|
||||||
port = config.get("Gamez", "port")
|
|
||||||
username = config.get("Gamez", "username")
|
|
||||||
password = config.get("Gamez", "password")
|
|
||||||
apikey = config.get("Gamez", "apikey")
|
|
||||||
|
|
||||||
try:
|
|
||||||
ssl = int(config.get("Gamez", "ssl"))
|
|
||||||
except (ConfigParser.NoOptionError, ValueError):
|
|
||||||
ssl = 0
|
|
||||||
|
|
||||||
try:
|
|
||||||
web_root = config.get("Gamez", "web_root")
|
|
||||||
except ConfigParser.NoOptionError:
|
|
||||||
web_root = ""
|
|
||||||
|
|
||||||
myOpener = AuthURLOpener(username, password)
|
|
||||||
|
|
||||||
if ssl:
|
|
||||||
protocol = "https://"
|
|
||||||
else:
|
|
||||||
protocol = "http://"
|
|
||||||
|
|
||||||
baseURL = protocol + host + ":" + port + web_root + "/api?api_key=" + apikey + "&mode="
|
|
||||||
|
|
||||||
fields = nzbName.split("-")
|
|
||||||
gamezID = fields[0].replace("[","").replace("]","").replace(" ","")
|
|
||||||
downloadStatus = 'Wanted'
|
|
||||||
if status == 0:
|
|
||||||
downloadStatus = 'Downloaded'
|
|
||||||
|
|
||||||
URL = baseURL + "UPDATEREQUESTEDSTATUS&db_id=" + gamezID + "&status=" + downloadStatus
|
|
||||||
|
|
||||||
Logger.debug("Opening URL: %s", url)
|
|
||||||
|
|
||||||
try:
|
|
||||||
urlObj = myOpener.openit(url)
|
|
||||||
except IOError, e:
|
|
||||||
Logger.error("Unable to open URL: %s", str(e))
|
|
||||||
return 1 # failure
|
|
||||||
|
|
||||||
result = json.load(urlObj)
|
|
||||||
Logger.info("Gamez returned %s", result)
|
|
||||||
if result['success']:
|
|
||||||
Logger.info("Status for %s has been set to %s in Gamez", gamezID, downloadStatus)
|
|
||||||
return 0 # Success
|
|
||||||
else:
|
|
||||||
Logger.error("Status for %s has NOT been updated in Gamez", gamezID)
|
|
||||||
return 1 # failure
|
|
|
@ -1,244 +0,0 @@
|
||||||
import sys
|
|
||||||
import urllib
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
import ConfigParser
|
|
||||||
import datetime
|
|
||||||
import time
|
|
||||||
import json
|
|
||||||
import logging
|
|
||||||
|
|
||||||
import Transcoder
|
|
||||||
from nzbToMediaEnv import *
|
|
||||||
from nzbToMediaSceneExceptions import process_all_exceptions
|
|
||||||
|
|
||||||
Logger = logging.getLogger()
|
|
||||||
|
|
||||||
class AuthURLOpener(urllib.FancyURLopener):
|
|
||||||
def __init__(self, user, pw):
|
|
||||||
self.username = user
|
|
||||||
self.password = pw
|
|
||||||
self.numTries = 0
|
|
||||||
urllib.FancyURLopener.__init__(self)
|
|
||||||
|
|
||||||
def prompt_user_passwd(self, host, realm):
|
|
||||||
if self.numTries == 0:
|
|
||||||
self.numTries = 1
|
|
||||||
return (self.username, self.password)
|
|
||||||
else:
|
|
||||||
return ('', '')
|
|
||||||
|
|
||||||
def openit(self, url):
|
|
||||||
self.numTries = 0
|
|
||||||
return urllib.FancyURLopener.open(self, url)
|
|
||||||
|
|
||||||
def get_imdb(nzbName, dirName):
|
|
||||||
|
|
||||||
a=nzbName.find('.cp(')+4 #search for .cptt( in nzbName
|
|
||||||
b=nzbName[a:].find(')')+a
|
|
||||||
imdbid=nzbName[a:b]
|
|
||||||
|
|
||||||
if imdbid:
|
|
||||||
Logger.info("Found movie id %s in name", imdbid)
|
|
||||||
return imdbid
|
|
||||||
|
|
||||||
a=dirName.find('.cp(')+4 #search for .cptt( in dirname
|
|
||||||
b=dirName[a:].find(')')+a
|
|
||||||
imdbid=dirName[a:b]
|
|
||||||
|
|
||||||
if imdbid:
|
|
||||||
Logger.info("Found movie id %s in directory", imdbid)
|
|
||||||
return imdbid
|
|
||||||
else:
|
|
||||||
Logger.warning("Could not find an imdb id in directory or name")
|
|
||||||
Logger.info("Postprocessing will continue, but the movie may not be identified correctly by CouchPotato")
|
|
||||||
return ""
|
|
||||||
|
|
||||||
def get_movie_info(myOpener, baseURL, imdbid):
|
|
||||||
|
|
||||||
if not imdbid:
|
|
||||||
return ""
|
|
||||||
url = baseURL + "movie.list"
|
|
||||||
|
|
||||||
Logger.debug("Opening URL: %s", url)
|
|
||||||
|
|
||||||
try:
|
|
||||||
urlObj = myOpener.openit(url)
|
|
||||||
except IOError, e:
|
|
||||||
Logger.error("Unable to open URL: %s", str(e))
|
|
||||||
return ""
|
|
||||||
|
|
||||||
movie_id = ""
|
|
||||||
result = json.load(urlObj)
|
|
||||||
movieid = [item["id"] for item in result["movies"]]
|
|
||||||
library = [item["library"]["identifier"] for item in result["movies"]]
|
|
||||||
for index in range(len(movieid)):
|
|
||||||
if library[index] == imdbid:
|
|
||||||
movie_id = str(movieid[index])
|
|
||||||
Logger.info("Found movie id %s in CPS database for movie %s", movie_id, imdbid)
|
|
||||||
break
|
|
||||||
return movie_id
|
|
||||||
|
|
||||||
def get_status(myOpener, baseURL, movie_id):
|
|
||||||
|
|
||||||
if not movie_id:
|
|
||||||
return ""
|
|
||||||
url = baseURL + "movie.get/?id=" + str(movie_id)
|
|
||||||
|
|
||||||
Logger.debug("Opening URL: %s", url)
|
|
||||||
|
|
||||||
try:
|
|
||||||
urlObj = myOpener.openit(url)
|
|
||||||
except IOError, e:
|
|
||||||
Logger.error("Unable to open URL: %s", str(e))
|
|
||||||
return ""
|
|
||||||
result = json.load(urlObj)
|
|
||||||
try:
|
|
||||||
movie_status = result["movie"]["status"]["identifier"]
|
|
||||||
Logger.debug("This movie is marked as status %s in CouchPotatoServer", movie_status)
|
|
||||||
return movie_status
|
|
||||||
except e: # index out of range/doesn't exist?
|
|
||||||
Logger.error("Could not find a status for this movie due to: %s", str(e))
|
|
||||||
return ""
|
|
||||||
|
|
||||||
def process(dirName, nzbName=None, status=0):
|
|
||||||
|
|
||||||
status = int(status)
|
|
||||||
config = ConfigParser.ConfigParser()
|
|
||||||
configFilename = os.path.join(os.path.dirname(sys.argv[0]), "autoProcessMedia.cfg")
|
|
||||||
Logger.info("Loading config from %s", configFilename)
|
|
||||||
|
|
||||||
if not os.path.isfile(configFilename):
|
|
||||||
Logger.error("You need an autoProcessMedia.cfg file - did you rename and edit the .sample?")
|
|
||||||
return 1 # failure
|
|
||||||
|
|
||||||
config.read(configFilename)
|
|
||||||
|
|
||||||
host = config.get("CouchPotato", "host")
|
|
||||||
port = config.get("CouchPotato", "port")
|
|
||||||
username = config.get("CouchPotato", "username")
|
|
||||||
password = config.get("CouchPotato", "password")
|
|
||||||
apikey = config.get("CouchPotato", "apikey")
|
|
||||||
delay = float(config.get("CouchPotato", "delay"))
|
|
||||||
method = config.get("CouchPotato", "method")
|
|
||||||
delete_failed = int(config.get("CouchPotato", "delete_failed"))
|
|
||||||
|
|
||||||
try:
|
|
||||||
ssl = int(config.get("CouchPotato", "ssl"))
|
|
||||||
except (ConfigParser.NoOptionError, ValueError):
|
|
||||||
ssl = 0
|
|
||||||
|
|
||||||
try:
|
|
||||||
web_root = config.get("CouchPotato", "web_root")
|
|
||||||
except ConfigParser.NoOptionError:
|
|
||||||
web_root = ""
|
|
||||||
|
|
||||||
try:
|
|
||||||
transcode = int(config.get("Transcoder", "transcode"))
|
|
||||||
except (ConfigParser.NoOptionError, ValueError):
|
|
||||||
transcode = 0
|
|
||||||
|
|
||||||
myOpener = AuthURLOpener(username, password)
|
|
||||||
|
|
||||||
nzbName = str(nzbName) # make sure it is a string
|
|
||||||
|
|
||||||
imdbid = get_imdb(nzbName, dirName)
|
|
||||||
|
|
||||||
if ssl:
|
|
||||||
protocol = "https://"
|
|
||||||
else:
|
|
||||||
protocol = "http://"
|
|
||||||
# don't delay when we are calling this script manually.
|
|
||||||
if nzbName == "Manual Run":
|
|
||||||
delay = 0
|
|
||||||
|
|
||||||
baseURL = protocol + host + ":" + port + web_root + "/api/" + apikey + "/"
|
|
||||||
|
|
||||||
movie_id = get_movie_info(myOpener, baseURL, imdbid) # get the CPS database movie id this movie.
|
|
||||||
|
|
||||||
initial_status = get_status(myOpener, baseURL, movie_id)
|
|
||||||
|
|
||||||
process_all_exceptions(nzbName.lower(), dirName)
|
|
||||||
|
|
||||||
if status == 0:
|
|
||||||
if transcode == 1:
|
|
||||||
result = Transcoder.Transcode_directory(dirName)
|
|
||||||
if result == 0:
|
|
||||||
Logger.debug("Transcoding succeeded for files in %s", dirName)
|
|
||||||
else:
|
|
||||||
Logger.warning("Transcoding failed for files in %s", dirName)
|
|
||||||
|
|
||||||
if method == "manage":
|
|
||||||
command = "manage.update"
|
|
||||||
else:
|
|
||||||
command = "renamer.scan"
|
|
||||||
|
|
||||||
url = baseURL + command
|
|
||||||
|
|
||||||
Logger.info("Waiting for %s seconds to allow CPS to process newly extracted files", str(delay))
|
|
||||||
|
|
||||||
time.sleep(delay)
|
|
||||||
|
|
||||||
Logger.debug("Opening URL: %s", url)
|
|
||||||
|
|
||||||
try:
|
|
||||||
urlObj = myOpener.openit(url)
|
|
||||||
except IOError, e:
|
|
||||||
Logger.error("Unable to open URL: %s", str(e))
|
|
||||||
return 1 # failure
|
|
||||||
|
|
||||||
result = json.load(urlObj)
|
|
||||||
Logger.info("CouchPotatoServer returned %s", result)
|
|
||||||
if result['success']:
|
|
||||||
Logger.info("%s started on CouchPotatoServer for %s", command, nzbName)
|
|
||||||
else:
|
|
||||||
Logger.error("%s has NOT started on CouchPotatoServer for %s. Exiting", command, nzbName)
|
|
||||||
return 1 # failure
|
|
||||||
|
|
||||||
else:
|
|
||||||
Logger.info("Download of %s has failed.", nzbName)
|
|
||||||
Logger.info("Trying to re-cue the next highest ranked release")
|
|
||||||
|
|
||||||
if not movie_id:
|
|
||||||
Logger.warning("Cound not find a movie in the database for release %s", nzbName)
|
|
||||||
Logger.warning("Please manually ignore this release and refresh the wanted movie")
|
|
||||||
Logger.error("Exiting autoProcessMovie script")
|
|
||||||
return 1 # failure
|
|
||||||
|
|
||||||
url = baseURL + "searcher.try_next/?id=" + movie_id
|
|
||||||
|
|
||||||
Logger.debug("Opening URL: %s", url)
|
|
||||||
|
|
||||||
try:
|
|
||||||
urlObj = myOpener.openit(url)
|
|
||||||
except IOError, e:
|
|
||||||
Logger.error("Unable to open URL: %s", str(e))
|
|
||||||
return 1 # failure
|
|
||||||
|
|
||||||
result = urlObj.readlines()
|
|
||||||
for line in result:
|
|
||||||
Logger.info("%s", line)
|
|
||||||
|
|
||||||
Logger.info("Movie %s set to try the next best release on CouchPotatoServer", movie_id)
|
|
||||||
if delete_failed:
|
|
||||||
Logger.info("Deleting failed files and folder %s", dirName)
|
|
||||||
try:
|
|
||||||
shutil.rmtree(dirName)
|
|
||||||
except e:
|
|
||||||
Logger.error("Unable to delete folder %s due to: %s", dirName, str(e))
|
|
||||||
return 0 # success
|
|
||||||
|
|
||||||
if nzbName == "Manual Run":
|
|
||||||
return 0 # success
|
|
||||||
|
|
||||||
# we will now check to see if CPS has finished renaming before returning to TorrentToMedia and unpausing.
|
|
||||||
start = datetime.datetime.now() # set time for timeout
|
|
||||||
while (datetime.datetime.now() - start) < datetime.timedelta(minutes=2): # only wait 2 minutes, then return to TorrentToMedia
|
|
||||||
movie_status = get_status(myOpener, baseURL, movie_id) # get the current status fo this movie.
|
|
||||||
if movie_status != initial_status: # Something has changed. CPS must have processed this movie.
|
|
||||||
Logger.info("SUCCESS: This movie is now marked as status %s in CouchPotatoServer", movie_status)
|
|
||||||
return 0 # success
|
|
||||||
time.sleep(20) # Just stop this looping infinitely and hogging resources for 2 minutes ;)
|
|
||||||
else: # The status hasn't changed. we have waited 2 minutes which is more than enough. uTorrent can resule seeding now.
|
|
||||||
Logger.warning("The movie does not appear to have changed status after 2 minutes. Please check CouchPotato Logs")
|
|
||||||
return 1 # failure
|
|
|
@ -1,116 +0,0 @@
|
||||||
import sys
|
|
||||||
import urllib
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
import ConfigParser
|
|
||||||
import datetime
|
|
||||||
import time
|
|
||||||
import json
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from nzbToMediaEnv import *
|
|
||||||
|
|
||||||
Logger = logging.getLogger()
|
|
||||||
|
|
||||||
class AuthURLOpener(urllib.FancyURLopener):
|
|
||||||
def __init__(self, user, pw):
|
|
||||||
self.username = user
|
|
||||||
self.password = pw
|
|
||||||
self.numTries = 0
|
|
||||||
urllib.FancyURLopener.__init__(self)
|
|
||||||
|
|
||||||
def prompt_user_passwd(self, host, realm):
|
|
||||||
if self.numTries == 0:
|
|
||||||
self.numTries = 1
|
|
||||||
return (self.username, self.password)
|
|
||||||
else:
|
|
||||||
return ('', '')
|
|
||||||
|
|
||||||
def openit(self, url):
|
|
||||||
self.numTries = 0
|
|
||||||
return urllib.FancyURLopener.open(self, url)
|
|
||||||
|
|
||||||
def process(dirName, nzbName=None, status=0):
|
|
||||||
|
|
||||||
status = int(status)
|
|
||||||
config = ConfigParser.ConfigParser()
|
|
||||||
configFilename = os.path.join(os.path.dirname(sys.argv[0]), "autoProcessMedia.cfg")
|
|
||||||
Logger.info("Loading config from %s", configFilename)
|
|
||||||
|
|
||||||
if not os.path.isfile(configFilename):
|
|
||||||
Logger.error("You need an autoProcessMedia.cfg file - did you rename and edit the .sample?")
|
|
||||||
return 1 # failure
|
|
||||||
|
|
||||||
config.read(configFilename)
|
|
||||||
|
|
||||||
host = config.get("HeadPhones", "host")
|
|
||||||
port = config.get("HeadPhones", "port")
|
|
||||||
username = config.get("HeadPhones", "username")
|
|
||||||
password = config.get("HeadPhones", "password")
|
|
||||||
apikey = config.get("HeadPhones", "apikey")
|
|
||||||
delay = float(config.get("HeadPhones", "delay"))
|
|
||||||
|
|
||||||
try:
|
|
||||||
ssl = int(config.get("HeadPhones", "ssl"))
|
|
||||||
except (ConfigParser.NoOptionError, ValueError):
|
|
||||||
ssl = 0
|
|
||||||
|
|
||||||
try:
|
|
||||||
web_root = config.get("HeadPhones", "web_root")
|
|
||||||
except ConfigParser.NoOptionError:
|
|
||||||
web_root = ""
|
|
||||||
|
|
||||||
myOpener = AuthURLOpener(username, password)
|
|
||||||
|
|
||||||
if ssl:
|
|
||||||
protocol = "https://"
|
|
||||||
else:
|
|
||||||
protocol = "http://"
|
|
||||||
# don't delay when we are calling this script manually.
|
|
||||||
if nzbName == "Manual Run":
|
|
||||||
delay = 0
|
|
||||||
|
|
||||||
baseURL = protocol + host + ":" + port + web_root + "/api?apikey=" + apikey + "&cmd="
|
|
||||||
|
|
||||||
if status == 0:
|
|
||||||
command = "forceProcess"
|
|
||||||
|
|
||||||
url = baseURL + command
|
|
||||||
|
|
||||||
Logger.info("Waiting for %s seconds to allow HeadPhones to process newly extracted files", str(delay))
|
|
||||||
|
|
||||||
time.sleep(delay)
|
|
||||||
|
|
||||||
Logger.debug("Opening URL: %s", url)
|
|
||||||
|
|
||||||
try:
|
|
||||||
urlObj = myOpener.openit(url)
|
|
||||||
except IOError, e:
|
|
||||||
Logger.error("Unable to open URL: %s", str(e))
|
|
||||||
return 1 # failure
|
|
||||||
|
|
||||||
result = json.load(urlObj)
|
|
||||||
Logger.info("HeaPhones returned %s", result)
|
|
||||||
if result == "OK":
|
|
||||||
Logger.info("%s started on HeadPhones for %s", command, nzbName)
|
|
||||||
else:
|
|
||||||
Logger.error("%s has NOT started on HeadPhones for %s. Exiting", command, nzbName)
|
|
||||||
return 1 # failure
|
|
||||||
|
|
||||||
else:
|
|
||||||
Logger.info("The download failed. Nothing to process")
|
|
||||||
return 0 # Success (as far as this script is concerned)
|
|
||||||
|
|
||||||
if nzbName == "Manual Run":
|
|
||||||
return 0 # success
|
|
||||||
|
|
||||||
# we will now wait 1 minutes for this album to be processed before returning to TorrentToMedia and unpausing.
|
|
||||||
## Hopefully we can use a "getHistory" check in here to confirm processing complete...
|
|
||||||
start = datetime.datetime.now() # set time for timeout
|
|
||||||
while (datetime.datetime.now() - start) < datetime.timedelta(minutes=1): # only wait 2 minutes, then return to TorrentToMedia
|
|
||||||
time.sleep(20) # Just stop this looping infinitely and hogging resources for 2 minutes ;)
|
|
||||||
else: # The status hasn't changed. we have waited 2 minutes which is more than enough. uTorrent can resume seeding now.
|
|
||||||
Logger.info("This album should have completed processing. Please check HeadPhones Logs")
|
|
||||||
# Logger.warning("The album does not appear to have changed status after 2 minutes. Please check HeadPhones Logs")
|
|
||||||
# return 1 # failure
|
|
||||||
return 0 # success for now.
|
|
166
autoProcessTV.py
166
autoProcessTV.py
|
@ -1,166 +0,0 @@
|
||||||
# Author: Nic Wolfe <nic@wolfeden.ca>
|
|
||||||
# URL: http://code.google.com/p/sickbeard/
|
|
||||||
#
|
|
||||||
# This file is part of Sick Beard.
|
|
||||||
#
|
|
||||||
# Sick Beard is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Sick Beard is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with Sick Beard. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import urllib
|
|
||||||
import os
|
|
||||||
import ConfigParser
|
|
||||||
import logging
|
|
||||||
|
|
||||||
import Transcoder
|
|
||||||
from nzbToMediaEnv import *
|
|
||||||
from nzbToMediaSceneExceptions import process_all_exceptions
|
|
||||||
|
|
||||||
Logger = logging.getLogger()
|
|
||||||
|
|
||||||
|
|
||||||
class AuthURLOpener(urllib.FancyURLopener):
|
|
||||||
def __init__(self, user, pw):
|
|
||||||
self.username = user
|
|
||||||
self.password = pw
|
|
||||||
self.numTries = 0
|
|
||||||
urllib.FancyURLopener.__init__(self)
|
|
||||||
|
|
||||||
def prompt_user_passwd(self, host, realm):
|
|
||||||
if self.numTries == 0:
|
|
||||||
self.numTries = 1
|
|
||||||
return (self.username, self.password)
|
|
||||||
else:
|
|
||||||
return ('', '')
|
|
||||||
|
|
||||||
def openit(self, url):
|
|
||||||
self.numTries = 0
|
|
||||||
return urllib.FancyURLopener.open(self, url)
|
|
||||||
|
|
||||||
|
|
||||||
def processEpisode(dirName, nzbName=None, failed=False):
|
|
||||||
|
|
||||||
status = int(failed)
|
|
||||||
config = ConfigParser.ConfigParser()
|
|
||||||
configFilename = os.path.join(os.path.dirname(sys.argv[0]), "autoProcessMedia.cfg")
|
|
||||||
Logger.info("Loading config from %s", configFilename)
|
|
||||||
|
|
||||||
if not os.path.isfile(configFilename):
|
|
||||||
Logger.error("You need an autoProcessMedia.cfg file - did you rename and edit the .sample?")
|
|
||||||
return 1 # failure
|
|
||||||
|
|
||||||
try:
|
|
||||||
fp = open(configFilename, "r")
|
|
||||||
config.readfp(fp)
|
|
||||||
fp.close()
|
|
||||||
except IOError, e:
|
|
||||||
Logger.error("Could not read configuration file: %s", str(e))
|
|
||||||
return 1 # failure
|
|
||||||
|
|
||||||
watch_dir = ""
|
|
||||||
host = config.get("SickBeard", "host")
|
|
||||||
port = config.get("SickBeard", "port")
|
|
||||||
username = config.get("SickBeard", "username")
|
|
||||||
password = config.get("SickBeard", "password")
|
|
||||||
try:
|
|
||||||
ssl = int(config.get("SickBeard", "ssl"))
|
|
||||||
except (ConfigParser.NoOptionError, ValueError):
|
|
||||||
ssl = 0
|
|
||||||
|
|
||||||
try:
|
|
||||||
web_root = config.get("SickBeard", "web_root")
|
|
||||||
except ConfigParser.NoOptionError:
|
|
||||||
web_root = ""
|
|
||||||
|
|
||||||
try:
|
|
||||||
watch_dir = config.get("SickBeard", "watch_dir")
|
|
||||||
except ConfigParser.NoOptionError:
|
|
||||||
watch_dir = ""
|
|
||||||
|
|
||||||
try:
|
|
||||||
failed_fork = int(config.get("SickBeard", "failed_fork"))
|
|
||||||
except (ConfigParser.NoOptionError, ValueError):
|
|
||||||
failed_fork = 0
|
|
||||||
try:
|
|
||||||
transcode = int(config.get("Transcoder", "transcode"))
|
|
||||||
except (ConfigParser.NoOptionError, ValueError):
|
|
||||||
transcode = 0
|
|
||||||
|
|
||||||
process_all_exceptions(nzbName.lower(), dirName)
|
|
||||||
|
|
||||||
|
|
||||||
#allows manual call of postprocess script if we have specified a watch_dir. Check that here.
|
|
||||||
if nzbName == "Manual Run" and watch_dir == "":
|
|
||||||
Logger.error("In order to run this script manually you must specify a watch_dir in autoProcessTV.cfg")
|
|
||||||
return 1 # failure
|
|
||||||
#allows us to specify the default watch directory and call the postproecssing on another PC with different directory structure.
|
|
||||||
if watch_dir != "":
|
|
||||||
dirName = watch_dir
|
|
||||||
|
|
||||||
params = {}
|
|
||||||
|
|
||||||
params['quiet'] = 1
|
|
||||||
|
|
||||||
# if you have specified you are using development branch from fork https://github.com/Tolstyak/Sick-Beard.git
|
|
||||||
if failed_fork:
|
|
||||||
params['dirName'] = dirName
|
|
||||||
if nzbName != None:
|
|
||||||
params['nzbName'] = nzbName
|
|
||||||
params['failed'] = failed
|
|
||||||
if status == 0:
|
|
||||||
Logger.info("The download succeeded. Sending process request to SickBeard's failed branch")
|
|
||||||
else:
|
|
||||||
Logger.info("The download failed. Sending 'failed' process request to SickBeard's failed branch")
|
|
||||||
|
|
||||||
|
|
||||||
# this is our default behaviour to work with the standard Master branch of SickBeard
|
|
||||||
else:
|
|
||||||
params['dir'] = dirName
|
|
||||||
if nzbName != None:
|
|
||||||
params['nzbName'] = nzbName
|
|
||||||
# the standard Master bamch of SickBeard cannot process failed downloads. So Exit here.
|
|
||||||
if status == 0:
|
|
||||||
Logger.info("The download succeeded. Sending process request to SickBeard")
|
|
||||||
else:
|
|
||||||
Logger.info("The download failed. Nothing to process")
|
|
||||||
return 0 # Success (as far as this script is concerned)
|
|
||||||
|
|
||||||
if status == 0 and transcode == 1: # only transcode successful downlaods
|
|
||||||
result = Transcoder.Transcode_directory(dirName)
|
|
||||||
if result == 0:
|
|
||||||
Logger.debug("Transcoding succeeded for files in %s", dirName)
|
|
||||||
else:
|
|
||||||
Logger.warning("Transcoding failed for files in %s", dirName)
|
|
||||||
|
|
||||||
myOpener = AuthURLOpener(username, password)
|
|
||||||
|
|
||||||
if ssl:
|
|
||||||
protocol = "https://"
|
|
||||||
else:
|
|
||||||
protocol = "http://"
|
|
||||||
|
|
||||||
url = protocol + host + ":" + port + web_root + "/home/postprocess/processEpisode?" + urllib.urlencode(params)
|
|
||||||
|
|
||||||
Logger.debug("Opening URL: %s", url)
|
|
||||||
|
|
||||||
try:
|
|
||||||
urlObj = myOpener.openit(url)
|
|
||||||
except IOError, e:
|
|
||||||
Logger.error("Unable to open URL: %s", str(e))
|
|
||||||
return 1 # failure
|
|
||||||
|
|
||||||
result = urlObj.readlines()
|
|
||||||
for line in result:
|
|
||||||
Logger.info("%s", line)
|
|
||||||
return 0 # Success
|
|
191
migratecfg.py
191
migratecfg.py
|
@ -1,191 +0,0 @@
|
||||||
#System imports
|
|
||||||
import ConfigParser
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
|
|
||||||
def migrate():
|
|
||||||
confignew = ConfigParser.ConfigParser()
|
|
||||||
confignew.optionxform = str
|
|
||||||
configFilenamenew = os.path.join(os.path.dirname(sys.argv[0]), "autoProcessMedia.cfg.sample")
|
|
||||||
confignew.read(configFilenamenew)
|
|
||||||
|
|
||||||
configold = ConfigParser.ConfigParser()
|
|
||||||
confignew.optionxform = str
|
|
||||||
|
|
||||||
section = "CouchPotato"
|
|
||||||
original = []
|
|
||||||
configFilenameold = os.path.join(os.path.dirname(sys.argv[0]), "autoProcessMedia.cfg")
|
|
||||||
if not os.path.isfile(configFilenameold): # lets look back for an older version.
|
|
||||||
configFilenameold = os.path.join(os.path.dirname(sys.argv[0]), "autoProcessMovie.cfg")
|
|
||||||
if not os.path.isfile(configFilenameold): # no config available
|
|
||||||
configFilenameold = ""
|
|
||||||
if configFilenameold: # read our old config.
|
|
||||||
configold.read(configFilenameold)
|
|
||||||
try:
|
|
||||||
original = configold.items(section)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
for item in original:
|
|
||||||
option, value = item
|
|
||||||
if option == "category": # change this old format
|
|
||||||
option = "cpsCategory"
|
|
||||||
if option == "outputDirectory": # move this to new location format
|
|
||||||
value = os.path.split(os.path.normpath(outputdirectory))[0]
|
|
||||||
confignew.set("Torrent", option, value)
|
|
||||||
continue
|
|
||||||
confignew.set(section, option, value)
|
|
||||||
|
|
||||||
section = "SickBeard"
|
|
||||||
original = []
|
|
||||||
configFilenameold = os.path.join(os.path.dirname(sys.argv[0]), "autoProcessMedia.cfg")
|
|
||||||
if not os.path.isfile(configFilenameold): # lets look back for an older version.
|
|
||||||
configFilenameold = os.path.join(os.path.dirname(sys.argv[0]), "autoProcessTV.cfg")
|
|
||||||
if not os.path.isfile(configFilenameold): # no config available
|
|
||||||
configFilenameold = ""
|
|
||||||
if configFilenameold: # read our old config.
|
|
||||||
configold.read(configFilenameold)
|
|
||||||
try:
|
|
||||||
original = configold.items(section)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
for item in original:
|
|
||||||
option, value = item
|
|
||||||
if option == "category": # change this old format
|
|
||||||
option = "sbCategory"
|
|
||||||
if option == "outputDirectory": # move this to new location format
|
|
||||||
value = os.path.split(os.path.normpath(outputdirectory))[0]
|
|
||||||
confignew.set("Torrent", option, value)
|
|
||||||
continue
|
|
||||||
confignew.set(section, option, value)
|
|
||||||
|
|
||||||
section = "HeadPhones"
|
|
||||||
original = []
|
|
||||||
configFilenameold = os.path.join(os.path.dirname(sys.argv[0]), "autoProcessMedia.cfg")
|
|
||||||
if not os.path.isfile(configFilenameold):
|
|
||||||
configFilenameold = ""
|
|
||||||
if configFilenameold: # read our old config.
|
|
||||||
configold.read(configFilenameold)
|
|
||||||
try:
|
|
||||||
original = configold.items(section)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
for item in original:
|
|
||||||
option, value = item
|
|
||||||
confignew.set(section, option, value)
|
|
||||||
|
|
||||||
section = "Mylar"
|
|
||||||
original = []
|
|
||||||
try:
|
|
||||||
original = configold.items(section)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
for item in original:
|
|
||||||
option, value = item
|
|
||||||
confignew.set(section, option, value)
|
|
||||||
|
|
||||||
section = "Gamez"
|
|
||||||
original = []
|
|
||||||
try:
|
|
||||||
original = configold.items(section)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
for item in original:
|
|
||||||
option, value = item
|
|
||||||
confignew.set(section, option, value)
|
|
||||||
|
|
||||||
section = "Torrent"
|
|
||||||
original = []
|
|
||||||
try:
|
|
||||||
original = configold.items(section)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
for item in original:
|
|
||||||
option, value = item
|
|
||||||
if option in ["compressedExtensions", "mediaExtensions", "metaExtensions"]:
|
|
||||||
section = "Extensions" # these were moved
|
|
||||||
confignew.set(section, option, value)
|
|
||||||
section = "Torrent" # reset in case extensions out of order.
|
|
||||||
|
|
||||||
section = "Transcoder"
|
|
||||||
original = []
|
|
||||||
try:
|
|
||||||
original = configold.items(section)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
for item in original:
|
|
||||||
option, value = item
|
|
||||||
confignew.set(section, option, value)
|
|
||||||
|
|
||||||
section = "loggers"
|
|
||||||
original = []
|
|
||||||
try:
|
|
||||||
original = configold.items(section)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
for item in original:
|
|
||||||
option, value = item
|
|
||||||
confignew.set(section, option, value)
|
|
||||||
|
|
||||||
section = "handlers"
|
|
||||||
original = []
|
|
||||||
try:
|
|
||||||
original = configold.items(section)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
for item in original:
|
|
||||||
option, value = item
|
|
||||||
confignew.set(section, option, value)
|
|
||||||
|
|
||||||
section = "formatters"
|
|
||||||
original = []
|
|
||||||
try:
|
|
||||||
original = configold.items(section)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
for item in original:
|
|
||||||
option, value = item
|
|
||||||
confignew.set(section, option, value)
|
|
||||||
|
|
||||||
section = "logger_root"
|
|
||||||
original = []
|
|
||||||
try:
|
|
||||||
original = configold.items(section)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
for item in original:
|
|
||||||
option, value = item
|
|
||||||
confignew.set(section, option, value)
|
|
||||||
|
|
||||||
section = "handler_console"
|
|
||||||
original = []
|
|
||||||
try:
|
|
||||||
original = configold.items(section)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
for item in original:
|
|
||||||
option, value = item
|
|
||||||
confignew.set(section, option, value)
|
|
||||||
|
|
||||||
section = "formatter_generic"
|
|
||||||
original = []
|
|
||||||
try:
|
|
||||||
original = configold.items(section)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
for item in original:
|
|
||||||
option, value = item
|
|
||||||
confignew.set(section, option, value)
|
|
||||||
|
|
||||||
# writing our configuration file to 'autoProcessMedia.cfg.sample'
|
|
||||||
with open(configFilenamenew, 'wb') as configFile:
|
|
||||||
confignew.write(configFile)
|
|
||||||
|
|
||||||
# create a backup of our old config
|
|
||||||
backupname = os.path.join(os.path.dirname(sys.argv[0]), "autoProcessMedia.cfg.old")
|
|
||||||
if os.path.isfile(backupname): # remove older backups
|
|
||||||
os.unlink(backupname)
|
|
||||||
os.rename(configFilenameold, backupname)
|
|
||||||
|
|
||||||
# rename our newly edited autoProcessMedia.cfg.sample to autoProcessMedia.cfg
|
|
||||||
os.rename(configFilenamenew, configFilenameold)
|
|
||||||
return
|
|
|
@ -1,10 +0,0 @@
|
||||||
# Make things easy and less error prone by centralising all common values
|
|
||||||
|
|
||||||
# Global Constants
|
|
||||||
VERSION = 'V6.1'
|
|
||||||
|
|
||||||
# Constants pertinant to SabNzb
|
|
||||||
SABNZB_NO_OF_ARGUMENTS = 8
|
|
||||||
|
|
||||||
# Constants pertinant to NzbGet
|
|
||||||
NZBGET_NO_OF_ARGUMENTS = 5
|
|
|
@ -1,35 +0,0 @@
|
||||||
# System imports
|
|
||||||
import os
|
|
||||||
import logging
|
|
||||||
|
|
||||||
# Custom imports
|
|
||||||
from nzbToMediaUtil import iterate_media_files
|
|
||||||
|
|
||||||
|
|
||||||
Logger = logging.getLogger()
|
|
||||||
|
|
||||||
|
|
||||||
def process_all_exceptions(name, dirname):
|
|
||||||
for group, exception in __customgroups__.items():
|
|
||||||
if not (group in name or group in dirname):
|
|
||||||
continue
|
|
||||||
process_exception(exception, name, dirname)
|
|
||||||
|
|
||||||
|
|
||||||
def process_exception(exception, name, dirname):
|
|
||||||
for parentDir, filename in iterate_media_files(dirname):
|
|
||||||
exception(filename, parentDir)
|
|
||||||
|
|
||||||
|
|
||||||
def process_qoq(filename, dirname):
|
|
||||||
Logger.debug("Reversing the file name for a QoQ release %s", filename)
|
|
||||||
head, fileExtension = os.path.splitext(os.path.basename(filename))
|
|
||||||
newname = head[::-1]
|
|
||||||
newfile = newname + fileExtension
|
|
||||||
newfilePath = os.path.join(dirname, newfile)
|
|
||||||
os.rename(filename, newfilePath)
|
|
||||||
Logger.debug("New file name is %s", newfile)
|
|
||||||
|
|
||||||
# dict for custom groups
|
|
||||||
# we can add more to this list
|
|
||||||
__customgroups__ = {'Q o Q': process_qoq}
|
|
|
@ -1,262 +0,0 @@
|
||||||
import logging
|
|
||||||
import logging.config
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
import linktastic.linktastic as linktastic
|
|
||||||
|
|
||||||
Logger = logging.getLogger()
|
|
||||||
|
|
||||||
|
|
||||||
def safeName(name):
|
|
||||||
safename = re.sub(r"[\/\\\:\*\?\"\<\>\|]", "", name) #make this name safe for use in directories for windows etc.
|
|
||||||
return safename
|
|
||||||
|
|
||||||
|
|
||||||
def nzbtomedia_configure_logging(dirname):
|
|
||||||
logFile = os.path.join(dirname, "postprocess.log")
|
|
||||||
logging.config.fileConfig(os.path.join(dirname, "autoProcessMedia.cfg"))
|
|
||||||
fileHandler = logging.FileHandler(logFile, encoding='utf-8', delay=True)
|
|
||||||
fileHandler.formatter = logging.Formatter('%(asctime)s|%(levelname)-7.7s %(message)s', '%H:%M:%S')
|
|
||||||
fileHandler.level = logging.DEBUG
|
|
||||||
logging.getLogger().addHandler(fileHandler)
|
|
||||||
|
|
||||||
|
|
||||||
def create_destination(outputDestination):
|
|
||||||
if os.path.exists(outputDestination):
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
Logger.info("CREATE DESTINATION: Creating destination folder: %s", outputDestination)
|
|
||||||
os.makedirs(outputDestination)
|
|
||||||
except Exception, e:
|
|
||||||
Logger.error("CREATE DESTINATION: Not possible to create destination folder: %s. Exiting", e)
|
|
||||||
sys.exit(-1)
|
|
||||||
|
|
||||||
def category_search(inputDirectory, inputName, inputCategory, root, categories):
|
|
||||||
categorySearch = [os.path.normpath(inputDirectory), ""] # initializie
|
|
||||||
notfound = 0
|
|
||||||
for x in range(10): # loop up through 10 directories looking for category.
|
|
||||||
try:
|
|
||||||
categorySearch2 = os.path.split(os.path.normpath(categorySearch[0]))
|
|
||||||
except: # this might happen when we can't go higher.
|
|
||||||
if inputCategory and inputName: # if these exists, we are ok to proceed, but assume we are in a root/common directory.
|
|
||||||
Logger.info("SEARCH: Could not find a Torrent Name or category in the directory structure")
|
|
||||||
Logger.info("SEARCH: We assume the directory passed is the root directory for your downlaoder")
|
|
||||||
Logger.warn("SEARCH: You should change settings to download torrents to their own directory if possible")
|
|
||||||
Logger.info("SEARCH: We will try and determine which files to process, individually")
|
|
||||||
root = 1
|
|
||||||
break # we are done
|
|
||||||
elif inputCategory: # if this exists, we are ok to proceed, but assume we are in a root/common directory and we have to check file dates.
|
|
||||||
Logger.info("SEARCH: Could not find a Torrent Name or Category in the directory structure")
|
|
||||||
Logger.info("SEARCH: We assume the directory passed is the root directory for your downlaoder")
|
|
||||||
Logger.warn("SEARCH: You should change settings to download torrents to their own directory if possible")
|
|
||||||
Logger.info("SEARCH: We will try and determine which files to process, individually")
|
|
||||||
root = 2
|
|
||||||
break # we are done
|
|
||||||
else:
|
|
||||||
Logger.error("SEARCH: Could not identify Category of Torrent Name in the directory structure. Please check downloader settings. Exiting")
|
|
||||||
sys.exit(-1)
|
|
||||||
|
|
||||||
if categorySearch2[1] in categories:
|
|
||||||
Logger.debug("SEARCH: Found Category: %s in directory structure", categorySearch2[1])
|
|
||||||
if not inputCategory:
|
|
||||||
Logger.info("SEARCH: Determined Category to be: %s", categorySearch2[1])
|
|
||||||
inputCategory = categorySearch2[1]
|
|
||||||
if inputName and categorySearch[0] != os.path.normpath(inputDirectory): # if we are not in the root directory and we have inputName we can continue.
|
|
||||||
if ('.cp(tt' in categorySearch[1]) and (not '.cp(tt' in inputName): # if the directory was created by CouchPotato, and this tag is not in Torrent name, we want to add it.
|
|
||||||
Logger.info("SEARCH: Changing Torrent Name to %s to preserve imdb id.", categorySearch[1])
|
|
||||||
inputName = categorySearch[1]
|
|
||||||
Logger.info("SEARCH: Identified Category: %s and Torrent Name: %s. We are in a unique directory, so we can proceed.", inputCategory, inputName)
|
|
||||||
break # we are done
|
|
||||||
elif categorySearch[1] and not inputName: # assume the the next directory deep is the torrent name.
|
|
||||||
Logger.info("SEARCH: Found torrent directory %s in category directory %s", os.path.join(categorySearch[0], categorySearch[1]), categorySearch[0])
|
|
||||||
inputName = categorySearch[1]
|
|
||||||
break # we are done
|
|
||||||
elif ('.cp(tt' in categorySearch[1]) and (not '.cp(tt' in inputName): # if the directory was created by CouchPotato, and this tag is not in Torrent name, we want to add it.
|
|
||||||
Logger.info("SEARCH: Changing Torrent Name to %s to preserve imdb id.", categorySearch[1])
|
|
||||||
inputName = categorySearch[1]
|
|
||||||
break # we are done
|
|
||||||
elif os.path.isdir(os.path.join(categorySearch[0], inputName)) and inputName: # testing for torrent name in first sub directory
|
|
||||||
Logger.info("SEARCH: Found torrent directory %s in category directory %s", os.path.join(categorySearch[0], inputName), categorySearch[0])
|
|
||||||
if categorySearch[0] == os.path.normpath(inputDirectory): # only true on first pass, x =0
|
|
||||||
inputDirectory = os.path.join(categorySearch[0], inputName) # we only want to search this next dir up.
|
|
||||||
break # we are done
|
|
||||||
elif os.path.isdir(os.path.join(categorySearch[0], safeName(inputName))) and inputName: # testing for torrent name in first sub directory
|
|
||||||
Logger.info("SEARCH: Found torrent directory %s in category directory %s", os.path.join(categorySearch[0], safeName(inputName)), categorySearch[0])
|
|
||||||
if categorySearch[0] == os.path.normpath(inputDirectory): # only true on first pass, x =0
|
|
||||||
inputDirectory = os.path.join(categorySearch[0], safeName(inputName)) # we only want to search this next dir up.
|
|
||||||
break # we are done
|
|
||||||
elif inputName: # if these exists, we are ok to proceed, but we are in a root/common directory.
|
|
||||||
Logger.info("SEARCH: Could not find a unique torrent folder in the directory structure")
|
|
||||||
Logger.info("SEARCH: The directory passed is the root directory for category %s", categorySearch2[1])
|
|
||||||
Logger.warn("SEARCH: You should change settings to download torrents to their own directory if possible")
|
|
||||||
Logger.info("SEARCH: We will try and determine which files to process, individually")
|
|
||||||
root = 1
|
|
||||||
break # we are done
|
|
||||||
else: # this is a problem! if we don't have Torrent name and are in the root category dir, we can't proceed.
|
|
||||||
Logger.warn("SEARCH: Could not identify a torrent name and the directory passed is common to all downloads for category %s.", categorySearch[1])
|
|
||||||
Logger.warn("SEARCH: You should change settings to download torrents to their own directory if possible")
|
|
||||||
Logger.info("SEARCH: We will try and determine which files to process, individually")
|
|
||||||
root = 2
|
|
||||||
break
|
|
||||||
elif safeName(categorySearch2[1]) == safeName(inputName) and inputName: # we have identified a unique directory.
|
|
||||||
Logger.info("SEARCH: Files appear to be in their own directory")
|
|
||||||
if inputCategory: # we are ok to proceed.
|
|
||||||
break # we are done
|
|
||||||
else:
|
|
||||||
Logger.debug("SEARCH: Continuing scan to determin category.")
|
|
||||||
categorySearch = categorySearch2 # ready for next loop
|
|
||||||
continue # keep going
|
|
||||||
else:
|
|
||||||
if x == 9: # This is the last pass in the loop and we didn't find anything.
|
|
||||||
notfound = 1
|
|
||||||
break # we are done
|
|
||||||
else:
|
|
||||||
categorySearch = categorySearch2 # ready for next loop
|
|
||||||
continue # keep going
|
|
||||||
|
|
||||||
if notfound == 1:
|
|
||||||
if inputCategory and inputName: # if these exists, we are ok to proceed, but assume we are in a root/common directory.
|
|
||||||
Logger.info("SEARCH: Could not find a category in the directory structure")
|
|
||||||
Logger.info("SEARCH: We assume the directory passed is the root directory for your downlaoder")
|
|
||||||
Logger.warn("SEARCH: You should change settings to download torrents to their own directory if possible")
|
|
||||||
Logger.info("SEARCH: We will try and determine which files to process, individually")
|
|
||||||
root = 1
|
|
||||||
elif inputCategory: # if this exists, we are ok to proceed, but assume we are in a root/common directory and we have to check file dates.
|
|
||||||
Logger.info("SEARCH: Could not find a Torrent Name or Category in the directory structure")
|
|
||||||
Logger.info("SEARCH: We assume the directory passed is the root directory for your downlaoder")
|
|
||||||
Logger.warn("SEARCH: You should change settings to download torrents to their own directory if possible")
|
|
||||||
Logger.info("SEARCH: We will try and determine which files to process, individually")
|
|
||||||
root = 2
|
|
||||||
if not inputCategory: # we didn't find this after 10 loops. This is a problem.
|
|
||||||
Logger.error("SEARCH: Could not identify category and torrent name from the directory structure. Please check downloader settings. Exiting")
|
|
||||||
sys.exit(-1) # Oh yeah.... WE ARE DONE!
|
|
||||||
|
|
||||||
return inputDirectory, inputName, inputCategory, root
|
|
||||||
|
|
||||||
|
|
||||||
def is_sample(filePath, inputName, minSampleSize):
|
|
||||||
# 200 MB in bytes
|
|
||||||
SIZE_CUTOFF = minSampleSize * 1024 * 1024
|
|
||||||
# Ignore 'sample' in files unless 'sample' in Torrent Name
|
|
||||||
return ('sample' in filePath.lower()) and (not 'sample' in inputName) and (os.path.getsize(filePath) < SIZE_CUTOFF)
|
|
||||||
|
|
||||||
|
|
||||||
def copy_link(filePath, targetDirectory, useLink, outputDestination):
|
|
||||||
create_destination(outputDestination)
|
|
||||||
if useLink != 0:
|
|
||||||
try:
|
|
||||||
Logger.info("COPYLINK: Linking %s to %s", filePath, targetDirectory)
|
|
||||||
linktastic.link(filePath, targetDirectory)
|
|
||||||
except:
|
|
||||||
if os.path.isfile(targetDirectory):
|
|
||||||
Logger.info("COPYLINK: Something went wrong in linktastic.link, but the destination file was created")
|
|
||||||
else:
|
|
||||||
Logger.info("COPYLINK: Something went wrong in linktastic.link, copying instead")
|
|
||||||
Logger.debug("COPYLINK: Copying %s to %s", filePath, targetDirectory)
|
|
||||||
shutil.copy(filePath, targetDirectory)
|
|
||||||
else:
|
|
||||||
Logger.debug("Copying %s to %s", filePath, targetDirectory)
|
|
||||||
shutil.copy(filePath, targetDirectory)
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def flatten(outputDestination):
|
|
||||||
Logger.info("FLATTEN: Flattening directory: %s", outputDestination)
|
|
||||||
for dirpath, dirnames, filenames in os.walk(outputDestination): # Flatten out the directory to make postprocessing easier
|
|
||||||
if dirpath == outputDestination:
|
|
||||||
continue # No need to try and move files in the root destination directory
|
|
||||||
for filename in filenames:
|
|
||||||
source = os.path.join(dirpath, filename)
|
|
||||||
target = os.path.join(outputDestination, filename)
|
|
||||||
try:
|
|
||||||
shutil.move(source, target)
|
|
||||||
except OSError:
|
|
||||||
Logger.error("FLATTEN: Could not flatten %s", source)
|
|
||||||
removeEmptyFolders(outputDestination) # Cleanup empty directories
|
|
||||||
|
|
||||||
|
|
||||||
def removeEmptyFolders(path):
|
|
||||||
Logger.info("REMOVER: Removing empty folders in: %s", path)
|
|
||||||
if not os.path.isdir(path):
|
|
||||||
return
|
|
||||||
|
|
||||||
# Remove empty subfolders
|
|
||||||
files = os.listdir(path)
|
|
||||||
if len(files):
|
|
||||||
for f in files:
|
|
||||||
fullpath = os.path.join(path, f)
|
|
||||||
if os.path.isdir(fullpath):
|
|
||||||
removeEmptyFolders(fullpath)
|
|
||||||
|
|
||||||
# If folder empty, delete it
|
|
||||||
files = os.listdir(path)
|
|
||||||
if len(files) == 0:
|
|
||||||
Logger.debug("REMOVER: Removing empty folder: %s", path)
|
|
||||||
os.rmdir(path)
|
|
||||||
|
|
||||||
def iterate_media_files(dirname):
|
|
||||||
mediaContainer = [ '.mkv', '.avi', '.divx', '.xvid', '.mov', '.wmv',
|
|
||||||
'.mp4', '.mpg', '.mpeg', '.iso' ]
|
|
||||||
|
|
||||||
for dirpath, dirnames, filesnames in os.walk(dirname):
|
|
||||||
for filename in filesnames:
|
|
||||||
fileExtension = os.path.splitext(filename)[1]
|
|
||||||
if not (fileExtension in mediaContainer):
|
|
||||||
continue
|
|
||||||
yield dirpath, os.path.join(dirpath, filename)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_other(args):
|
|
||||||
return os.path.normpath(sys.argv[1]), '', '', ''
|
|
||||||
|
|
||||||
|
|
||||||
def parse_utorrent(args):
|
|
||||||
# uTorrent usage: call TorrentToMedia.py "%D" "%N" "%L" "%I"
|
|
||||||
inputDirectory = os.path.normpath(args[1])
|
|
||||||
inputName = args[2]
|
|
||||||
try:
|
|
||||||
inputCategory = args[3]
|
|
||||||
except:
|
|
||||||
inputCategory = ''
|
|
||||||
try:
|
|
||||||
inputHash = args[4]
|
|
||||||
except:
|
|
||||||
inputHash = ''
|
|
||||||
|
|
||||||
return inputDirectory, inputName, inputCategory, inputHash
|
|
||||||
|
|
||||||
|
|
||||||
def parse_deluge(args):
|
|
||||||
# Deluge usage: call TorrentToMedia.py TORRENT_ID TORRENT_NAME TORRENT_DIR
|
|
||||||
inputDirectory = os.path.normpath(sys.argv[3])
|
|
||||||
inputName = sys.argv[2]
|
|
||||||
inputCategory = '' # We dont have a category yet
|
|
||||||
inputHash = ''
|
|
||||||
return inputDirectory, inputName, inputCategory, inputHash
|
|
||||||
|
|
||||||
|
|
||||||
def parse_transmission(args):
|
|
||||||
# Transmission usage: call TorrenToMedia.py (%TR_TORRENT_DIR% %TR_TORRENT_NAME% is passed on as environmental variables)
|
|
||||||
inputDirectory = os.path.normpath(os.getenv('TR_TORRENT_DIR'))
|
|
||||||
inputName = os.getenv('TR_TORRENT_NAME')
|
|
||||||
inputCategory = '' # We dont have a category yet
|
|
||||||
inputHash = ''
|
|
||||||
return inputDirectory, inputName, inputCategory, inputHash
|
|
||||||
|
|
||||||
|
|
||||||
__ARG_PARSERS__ = {
|
|
||||||
'other': parse_other,
|
|
||||||
'utorrent': parse_utorrent,
|
|
||||||
'deluge': parse_deluge,
|
|
||||||
'transmission': parse_transmission,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def parse_args(clientAgent):
|
|
||||||
parseFunc = __ARG_PARSERS__.get(clientAgent, None)
|
|
||||||
if not parseFunc:
|
|
||||||
raise RuntimeError("Could not find client-agent")
|
|
||||||
return parseFunc(sys.argv)
|
|
Loading…
Add table
Add a link
Reference in a new issue