diff --git a/autoProcessMedia.cfg.spec b/autoProcessMedia.cfg.spec index 8ebfa3b6..4ea12fb6 100644 --- a/autoProcessMedia.cfg.spec +++ b/autoProcessMedia.cfg.spec @@ -18,8 +18,10 @@ log_debug = 0 # Enable/Disable logging database messages to nzbtomedia.log log_db = 0 - # Enable/Disable logging environment variables to nzbtomedia.log (helpful to track down errors calling external tools.) + # Enable/Disable logging environment variables to debug nzbtomedia.log (helpful to track down errors calling external tools.) log_env = 0 + # Enable/Disable logging git output to debug nzbtomedia.log (helpful to track down update failures.) + log_git = 0 # Set to the directory where your ffmpeg/ffprobe executables are located ffmpeg_path = # Enable/Disable media file checking using ffprobe. @@ -282,7 +284,7 @@ generalOptions = # outputDefault. Loads default configs for the selected device. The remaining options below are ignored. # If you want to use your own profile, leave this blank and set the remaining options below. - # outputDefault profiles allowed: iPad, iPad-1080p, iPad-720p, Apple-TV2, iPod, iPhone, PS3, xbox, Roku-1080p, Roku-720p, Roku-480p + # outputDefault profiles allowed: iPad, iPad-1080p, iPad-720p, Apple-TV2, iPod, iPhone, PS3, xbox, Roku-1080p, Roku-720p, Roku-480p, mkv outputDefault = #### Define custom settings below. outputVideoExtension = .mp4 diff --git a/nzbToCouchPotato.py b/nzbToCouchPotato.py index 74bfb7cf..fea88360 100755 --- a/nzbToCouchPotato.py +++ b/nzbToCouchPotato.py @@ -189,7 +189,7 @@ # externalSubDir. set the directory where subs should be saved (if not the same directory as the video) #externalSubDir= -# outputDefault (None, iPad, iPad-1080p, iPad-720p, Apple-TV2, iPod, iPhone, PS3, xbox, Roku-1080p, Roku-720p, Roku-480p). +# outputDefault (None, iPad, iPad-1080p, iPad-720p, Apple-TV2, iPod, iPhone, PS3, xbox, Roku-1080p, Roku-720p, Roku-480p, mkv). # # outputDefault. Loads default configs for the selected device. The remaining options below are ignored. # If you want to use your own profile, set None and set the remaining options below. diff --git a/nzbToMedia.py b/nzbToMedia.py index d4034b36..1d11d9a6 100755 --- a/nzbToMedia.py +++ b/nzbToMedia.py @@ -385,7 +385,7 @@ # externalSubDir. set the directory where subs should be saved (if not the same directory as the video) #externalSubDir= -# outputDefault (None, iPad, iPad-1080p, iPad-720p, Apple-TV2, iPod, iPhone, PS3, xbox, Roku-1080p, Roku-720p, Roku-480p). +# outputDefault (None, iPad, iPad-1080p, iPad-720p, Apple-TV2, iPod, iPhone, PS3, xbox, Roku-1080p, Roku-720p, Roku-480p, mkv). # # outputDefault. Loads default configs for the selected device. The remaining options below are ignored. # If you want to use your own profile, set None and set the remaining options below. diff --git a/nzbToSickBeard.py b/nzbToSickBeard.py index d916739f..2d34ea89 100755 --- a/nzbToSickBeard.py +++ b/nzbToSickBeard.py @@ -197,7 +197,7 @@ # externalSubDir. set the directory where subs should be saved (if not the same directory as the video) #externalSubDir= -# outputDefault (None, iPad, iPad-1080p, iPad-720p, Apple-TV2, iPod, iPhone, PS3, xbox, Roku-1080p, Roku-720p, Roku-480p). +# outputDefault (None, iPad, iPad-1080p, iPad-720p, Apple-TV2, iPod, iPhone, PS3, xbox, Roku-1080p, Roku-720p, Roku-480p, mkv). # # outputDefault. Loads default configs for the selected device. The remaining options below are ignored. # If you want to use your own profile, set None and set the remaining options below. diff --git a/nzbtomedia/__init__.py b/nzbtomedia/__init__.py index 36903429..1614a52d 100644 --- a/nzbtomedia/__init__.py +++ b/nzbtomedia/__init__.py @@ -71,6 +71,7 @@ CFG = None LOG_DEBUG = None LOG_DB = None LOG_ENV = None +LOG_GIT = None SYS_ENCODING = None AUTO_UPDATE = None @@ -190,7 +191,7 @@ def initialize(section=None): SABNZB_NO_OF_ARGUMENTS, SABNZB_0717_NO_OF_ARGUMENTS, CATEGORIES, TORRENT_CLIENTAGENT, USELINK, OUTPUTDIRECTORY, \ NOFLATTEN, UTORRENTPWD, UTORRENTUSR, UTORRENTWEBUI, DELUGEHOST, DELUGEPORT, DELUGEUSR, DELUGEPWD, \ TRANSMISSIONHOST, TRANSMISSIONPORT, TRANSMISSIONPWD, TRANSMISSIONUSR, COMPRESSEDCONTAINER, MEDIACONTAINER, \ - METACONTAINER, SECTIONS, ALL_FORKS, TEST_FILE, GENERALOPTS, \ + METACONTAINER, SECTIONS, ALL_FORKS, TEST_FILE, GENERALOPTS, LOG_GIT, \ __INITIALIZED__, AUTO_UPDATE, APP_FILENAME, USER_DELAY, APP_NAME, TRANSCODE, DEFAULTS, GIT_PATH, GIT_USER, \ GIT_BRANCH, GIT_REPO, SYS_ENCODING, NZB_CLIENTAGENT, SABNZBDHOST, SABNZBDPORT, SABNZBDAPIKEY, \ DUPLICATE, IGNOREEXTENSIONS, VEXTENSION, OUTPUTVIDEOPATH, PROCESSOUTPUT, VCODEC, VCODEC_ALLOW, VPRESET, \ @@ -261,6 +262,7 @@ def initialize(section=None): LOG_DEBUG = int(CFG['General']['log_debug']) LOG_DB = int(CFG['General']['log_db']) LOG_ENV = int(CFG['General']['log_env']) + LOG_GIT = int(CFG['General']['log_git']) if LOG_ENV: for item in os.environ: @@ -533,6 +535,14 @@ def initialize(section=None): 'ACODEC2':'ac3','ACODEC2_ALLOW':['ac3'],'ABITRATE2':None, 'ACHANNELS2':6, 'ACODEC3':None,'ACODEC3_ALLOW':[],'ABITRATE3':None, 'ACHANNELS3':None, 'SCODEC':'mov_text' + }, + 'mkv':{ + 'VEXTENSION':'.mkv','VCODEC':'libx264','VPRESET':None,'VFRAMERATE':None,'VBITRATE':None, + 'VRESOLUTION':None,'VCODEC_ALLOW':['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4', 'mpeg2video'], + 'ACODEC':'dts','ACODEC_ALLOW':['libfaac', 'dts', 'ac3', 'mp2', 'mp3'],'ABITRATE':None, 'ACHANNELS':8, + 'ACODEC2':'ac3','ACODEC2_ALLOW':['libfaac', 'dts', 'ac3', 'mp2', 'mp3'],'ABITRATE2':None, 'ACHANNELS2':8, + 'ACODEC3':'ac3','ACODEC3_ALLOW':['libfaac', 'dts', 'ac3', 'mp2', 'mp3'],'ABITRATE3':None, 'ACHANNELS3':8, + 'SCODEC':'mov_text' } } if DEFAULTS and DEFAULTS in transcode_defaults: diff --git a/nzbtomedia/transcoder/transcoder.py b/nzbtomedia/transcoder/transcoder.py index 4070f81e..9fbb7c5a 100644 --- a/nzbtomedia/transcoder/transcoder.py +++ b/nzbtomedia/transcoder/transcoder.py @@ -7,6 +7,7 @@ import traceback import nzbtomedia import json import shutil +import re from subprocess import call from nzbtomedia import logger from nzbtomedia.nzbToMediaUtil import makeDir @@ -15,7 +16,7 @@ def isVideoGood(videofile, status): fileNameExt = os.path.basename(videofile) fileName, fileExt = os.path.splitext(fileNameExt) disable = False - if fileExt not in nzbtomedia.MEDIACONTAINER or not nzbtomedia.FFPROBE or not nzbtomedia.CHECK_MEDIA: + if fileExt not in nzbtomedia.MEDIACONTAINER or not nzbtomedia.FFPROBE or not nzbtomedia.CHECK_MEDIA or fileExt in ['.iso']: disable = True else: test_details, res = getVideoDetails(nzbtomedia.TEST_FILE) @@ -444,10 +445,7 @@ def extract_subs(file, newfilePath, bitbucket): command = nzbtomedia.NICENESS + command logger.info("Extracting %s subtitle from: %s" % (lan, file)) - cmd = "" - for item in command: - cmd = cmd + " " + str(item) - logger.debug("Calling command: %s" % (cmd)) + print_cmd(command) result = 1 # set result to failed in case call fails. try: result = call(command, stdout=bitbucket, stderr=bitbucket) @@ -460,16 +458,136 @@ def extract_subs(file, newfilePath, bitbucket): except: pass logger.info("Extracting %s subtitle from %s has succeeded" % (lan, file)) else: - logger.error("Extracting subtitles has failed") + logger.error("Extracting subtitles has failed") + +def processList(List, newDir, name, bitbucket): + remList = [] + newList = [] + delList = [] + vtsPath = None + success = True + for item in List: + newfile = None + if os.path.splitext(item)[1].lower() == '.iso' and not '.iso' in nzbtomedia.IGNOREEXTENSIONS: + logger.debug("Attempting to rip .iso image: %s" % (item), "TRANSCODER") + newList.extend(ripISO(item, newDir, name, bitbucket)) + remList.append(item) + elif re.match(".+VTS_[0-9][0-9]_[0-9].[Vv][Oo][Bb]", item) and not '.vob' in nzbtomedia.IGNOREEXTENSIONS: + logger.debug("Found VIDEO_TS image file: %s" % (item), "TRANSCODER") + if not vtsPath: + vtsPath = re.match(".+VIDEO_TS",item).group() + if not vtsPath: + vtsPath = os.path.split(item)[0] + remList.append(item) + elif re.match(".+VIDEO_TS.", item) or re.match(".+VTS_[0-9][0-9]_[0-9].", item): + remList.append(item) + else: continue + if vtsPath: + newList.extend(combineVTS(vtsPath, newDir, name, bitbucket)) + for file in newList: + if not os.path.isfile(file): + success = False + break + if success and newList: + List.extend(newList) + for item in remList: + List.remove(item) + logger.debug("Successfully extracted .vob file %s from disk image" % (newList[0]), "TRANSCODER") + else: + newList = [] + remList = [] + logger.error("Failed extracting .vob files from disk image. Stopping transcoding.", "TRANSCODER") + return List, remList, newList, success + +def ripISO(item, newDir, name, bitbucket): + newFiles = [] + failure_dir = '/this/is/not/real' + + # Mount the ISO in your OS and call combineVTS. + if platform.system() == 'Windows': + temp_iso = item # pfm mounts in place. + cmd = ['pfm', 'mount', item] + else: + temp_iso = os.path.join(newDir, 'tmp_iso') + os.makedirs(temp_iso) + cmd = ['mount', '-o', 'rw', 'loop', item, temp_iso] + try: + logger.debug("Attempting to mount .iso file %s to extract .vob" % (item), "TRANSCODER") + print_cmd(cmd) + result = call(cmd, stdout=bitbucket, stderr=bitbucket) + if os.path.isdir(os.path.join(temp_iso, 'VIDEO_TS')): + vtsPath = os.path.join(temp_iso, 'VIDEO_TS') + newFiles.extend(combineVTS(vtsPath, newDir, name)) + else: + logger.error("No VIDEO_TS folder found in .iso file %s" % (item), "TRANSCODER") + return [failure_dir] + except: + logger.error("Failed to mount .iso file %s" % (item), "TRANSCODER") + return [failure_dir] + # Unmount and delete. + if platform.system() == 'Windows': + cmd = ['pfm', 'unmount', item] + else: + cmd = ['umount', temp_iso] + try: + logger.debug("Attempting to unmount .iso file" % (item), "TRANSCODER") + print_cmd(cmd) + result = call(cmd, stdout=bitbucket, stderr=bitbucket) + if not platform.system() == 'Windows': + os.unlink(temp_iso) + except: + logger.error("Failed to unmount .iso file" % (item), "TRANSCODER") + return newFiles + +def combineVTS(vtsPath, newDir, name, bitbucket): + newFiles = [] + failure_dir = '/this/is/not/real' + for n in range(99): + if platform.system() == 'Windows': + cmd = ['copy', '/b'] + else: + cmd = ['cat'] + cmd2 = [] + m = 1 + while True: + if os.path.isfile(os.path.join(vtsPath, 'VTS_0%s_%s.VOB' % (str(n+1), str(m)))): + cmd.append(os.path.join(vtsPath, 'VTS_0%s_%s.VOB' % (str(n+1), str(m)))) + m += 1 + else: + break + if not cmd2: + break + elif platform.system() == 'Windows': + for e in cmd2: + cmd.append(e) + cmd.append('+') + cmd.pop() + else: + cmd.extend(cmd2) + logger.debug("Attempting to extract video track %s from disk image" % (str(n)), "TRANSCODER") + newfile = os.path.join(newDir, '%s.cd%s.vob' % (name, str(n+1))) + if platform.system() == 'Windows': + cmd.append(newfile) + else: + cmd.extend(['>', newfile]) + try: + print_cmd(cmd) + result = call(cmd, stdout=bitbucket, stderr=bitbucket) + newFiles.append(newfile) + except: + logger.debug("Failed to extract video track %s from disk image" % (str(n)), "TRANSCODER") + return [failure_dir] + return newFiles + +def print_cmd(command): + cmd = "" + for item in command: + cmd = cmd + " " + str(item) + logger.debug("calling command:%s" % (cmd)) def Transcode_directory(dirName): - if platform.system() == 'Windows': - bitbucket = open('NUL') - else: - bitbucket = open('/dev/null') - if not nzbtomedia.FFMPEG: - return 1 + return 1, dirName logger.info("Checking for files to be transcoded") final_result = 0 # initialize as successful @@ -478,7 +596,17 @@ def Transcode_directory(dirName): makeDir(newDir) else: newDir = dirName - for file in nzbtomedia.listMediaFiles(dirName, media=True, audio=False, meta=False, archives=False): + movieName = os.path.splitext(os.path.split(dirName)[1])[0] + List = nzbtomedia.listMediaFiles(dirName, media=True, audio=False, meta=False, archives=False) + List, remList, newList, success = processList(List, newDir, movieName, bitbucket) + if not success: + return final_result, dirName + + if platform.system() == 'Windows': + bitbucket = open('NUL') + else: + bitbucket = open('/dev/null') + for file in List: if os.path.splitext(file)[1] in nzbtomedia.IGNOREEXTENSIONS: continue command = buildCommands(file, newDir) @@ -497,10 +625,7 @@ def Transcode_directory(dirName): logger.debug("Error when removing transcoding target: %s" % (e)) logger.info("Transcoding video: %s" % (file)) - cmd = "" - for item in command: - cmd = cmd + " " + str(item) - logger.debug("calling command:%s" % (cmd)) + print_cmd(command) result = 1 # set result to failed in case call fails. try: result = call(command, stdout=bitbucket, stderr=bitbucket) @@ -521,13 +646,20 @@ def Transcode_directory(dirName): shutil.copymode(file, newfilePath) except: pass logger.info("Transcoding of video %s to %s succeeded" % (file, newfilePath)) - if not nzbtomedia.DUPLICATE and os.path.isfile(newfilePath): # we get rid of the original file - os.unlink(file) + if os.path.isfile(newfilePath) and (file in newList or not nzbtomedia.DUPLICATE): + try: + os.unlink(file) + except: pass else: logger.error("Transcoding of video %s to %s failed" % (file, newfilePath)) # this will be 0 (successful) it all are successful, else will return a positive integer for failure. final_result = final_result + result - + if final_result == 0 and not nzbtomedia.DUPLICATE: + for file in remList: + try: + os.unlink(file) + except: pass if not nzbtomedia.PROCESSOUTPUT and nzbtomedia.DUPLICATE: # We postprocess the original files to CP/SB newDir = dirName + bitbucket.close() return final_result, newDir diff --git a/nzbtomedia/versionCheck.py b/nzbtomedia/versionCheck.py index 6f4b51d7..71715673 100644 --- a/nzbtomedia/versionCheck.py +++ b/nzbtomedia/versionCheck.py @@ -171,7 +171,8 @@ class GitUpdateManager(UpdateManager): if output: output = output.strip() - logger.log(u"git output: " + output, logger.DEBUG) + if nzbtomedia.LOG_GIT: + logger.log(u"git output: " + output, logger.DEBUG) except OSError: logger.log(u"Command " + cmd + " didn't work") @@ -182,15 +183,18 @@ class GitUpdateManager(UpdateManager): exit_status = 0 elif exit_status == 1: - logger.log(cmd + u" returned : " + output, logger.DEBUG) + if nzbtomedia.LOG_GIT: + logger.log(cmd + u" returned : " + output, logger.DEBUG) exit_status = 1 elif exit_status == 128 or 'fatal:' in output or err: - logger.log(cmd + u" returned : " + output, logger.DEBUG) + if nzbtomedia.LOG_GIT: + logger.log(cmd + u" returned : " + output, logger.DEBUG) exit_status = 128 else: - logger.log(cmd + u" returned : " + output + u", treat as error for now", logger.DEBUG) + if nzbtomedia.LOG_GIT: + logger.log(cmd + u" returned : " + output + u", treat as error for now", logger.DEBUG) exit_status = 1 return (output, err, exit_status)