def process_torrent(input_directory, input_name, input_category, input_hash, input_id, client_agent): status = 1 # 1 = failed | 0 = success root = 0 found_file = 0 if client_agent != 'manual' and not core.DOWNLOADINFO: logger.debug('Adding TORRENT download info for directory {0} to database'.format(input_directory)) my_db = main_db.DBConnection() input_directory1 = input_directory input_name1 = input_name try: encoded, input_directory1 = char_replace(input_directory) encoded, input_name1 = char_replace(input_name) except Exception: pass control_value_dict = {'input_directory': text_type(input_directory1)} new_value_dict = { 'input_name': text_type(input_name1), 'input_hash': text_type(input_hash), 'input_id': text_type(input_id), 'client_agent': text_type(client_agent), 'status': 0, 'last_update': datetime.date.today().toordinal(), } my_db.upsert('downloads', new_value_dict, control_value_dict) logger.debug('Received Directory: {0} | Name: {1} | Category: {2}'.format(input_directory, input_name, input_category)) # Confirm the category by parsing directory structure input_directory, input_name, input_category, root = core.category_search(input_directory, input_name, input_category, root, core.CATEGORIES) if input_category == '': input_category = 'UNCAT' usercat = input_category try: input_name = input_name.encode(core.SYS_ENCODING) except UnicodeError: pass try: input_directory = input_directory.encode(core.SYS_ENCODING) except UnicodeError: pass logger.debug('Determined Directory: {0} | Name: {1} | Category: {2}'.format (input_directory, input_name, input_category)) # auto-detect section section = core.CFG.findsection(input_category).isenabled() if section is None: section = core.CFG.findsection('ALL').isenabled() if section is None: logger.error('Category:[{0}] is not defined or is not enabled. ' 'Please rename it or ensure it is enabled for the appropriate section ' 'in your autoProcessMedia.cfg and try again.'.format (input_category)) return [-1, ''] else: usercat = 'ALL' if len(section) > 1: logger.error('Category:[{0}] is not unique, {1} are using it. ' 'Please rename it or disable all other sections using the same category name ' 'in your autoProcessMedia.cfg and try again.'.format (usercat, section.keys())) return [-1, ''] if section: section_name = section.keys()[0] logger.info('Auto-detected SECTION:{0}'.format(section_name)) else: logger.error('Unable to locate a section with subsection:{0} ' 'enabled in your autoProcessMedia.cfg, exiting!'.format (input_category)) return [-1, ''] section = dict(section[section_name][usercat]) # Type cast to dict() to allow effective usage of .get() torrent_no_link = int(section.get('Torrent_NoLink', 0)) keep_archive = int(section.get('keep_archive', 0)) extract = int(section.get('extract', 0)) extensions = section.get('user_script_mediaExtensions', '').lower().split(',') unique_path = int(section.get('unique_path', 1)) if client_agent != 'manual': core.pause_torrent(client_agent, input_hash, input_id, input_name) # In case input is not directory, make sure to create one. # This way Processing is isolated. if not os.path.isdir(os.path.join(input_directory, input_name)): basename = os.path.basename(input_directory) basename = core.sanitize_name(input_name) \ if input_name == basename else os.path.splitext(core.sanitize_name(input_name))[0] output_destination = os.path.join(core.OUTPUTDIRECTORY, input_category, basename) elif unique_path: output_destination = os.path.normpath( core.os.path.join(core.OUTPUTDIRECTORY, input_category, core.sanitize_name(input_name).replace(' ', '.'))) else: output_destination = os.path.normpath( core.os.path.join(core.OUTPUTDIRECTORY, input_category)) try: output_destination = output_destination.encode(core.SYS_ENCODING) except UnicodeError: pass if output_destination in input_directory: output_destination = input_directory logger.info('Output directory set to: {0}'.format(output_destination)) if core.SAFE_MODE and output_destination == core.TORRENT_DEFAULTDIR: logger.error('The output directory:[{0}] is the Download Directory. ' 'Edit outputDirectory in autoProcessMedia.cfg. Exiting'.format (input_directory)) return [-1, ''] logger.debug('Scanning files in directory: {0}'.format(input_directory)) if section_name in ['HeadPhones', 'Lidarr']: core.NOFLATTEN.extend( input_category) # Make sure we preserve folder structure for HeadPhones. now = datetime.datetime.now() if extract == 1: input_files = core.list_media_files(input_directory, archives=False, other=True, otherext=extensions) else: input_files = core.list_media_files(input_directory, other=True, otherext=extensions) if len(input_files) == 0 and os.path.isfile(input_directory): input_files = [input_directory] logger.debug('Found 1 file to process: {0}'.format(input_directory)) else: logger.debug('Found {0} files in {1}'.format(len(input_files), input_directory)) for inputFile in input_files: file_path = os.path.dirname(inputFile) file_name, file_ext = os.path.splitext(os.path.basename(inputFile)) full_file_name = os.path.basename(inputFile) target_file = core.os.path.join(output_destination, full_file_name) if input_category in core.NOFLATTEN: if not os.path.basename(file_path) in output_destination: target_file = core.os.path.join( core.os.path.join(output_destination, os.path.basename(file_path)), full_file_name) logger.debug('Setting outputDestination to {0} to preserve folder structure'.format (os.path.dirname(target_file))) try: target_file = target_file.encode(core.SYS_ENCODING) except UnicodeError: pass if root == 1: if not found_file: logger.debug('Looking for {0} in: {1}'.format(input_name, inputFile)) if any([core.sanitize_name(input_name) in core.sanitize_name(inputFile), core.sanitize_name(file_name) in core.sanitize_name(input_name)]): found_file = True logger.debug('Found file {0} that matches Torrent Name {1}'.format (full_file_name, input_name)) else: continue if root == 2: mtime_lapse = now - datetime.datetime.fromtimestamp(os.path.getmtime(inputFile)) ctime_lapse = now - datetime.datetime.fromtimestamp(os.path.getctime(inputFile)) if not found_file: logger.debug('Looking for files with modified/created dates less than 5 minutes old.') if (mtime_lapse < datetime.timedelta(minutes=5)) or (ctime_lapse < datetime.timedelta(minutes=5)): found_file = True logger.debug('Found file {0} with date modified/created less than 5 minutes ago.'.format (full_file_name)) else: continue # This file has not been recently moved or created, skip it if torrent_no_link == 0: try: core.copy_link(inputFile, target_file, core.USELINK) core.remove_read_only(target_file) except Exception: logger.error('Failed to link: {0} to {1}'.format(inputFile, target_file)) input_name, output_destination = convert_to_ascii(input_name, output_destination) if extract == 1: logger.debug('Checking for archives to extract in directory: {0}'.format(input_directory)) core.extract_files(input_directory, output_destination, keep_archive) if input_category not in core.NOFLATTEN: # don't flatten hp in case multi cd albums, and we need to copy this back later. core.flatten(output_destination) # Now check if video files exist in destination: if section_name in ['SickBeard', 'NzbDrone', 'Sonarr', 'CouchPotato', 'Radarr']: num_videos = len( core.list_media_files(output_destination, media=True, audio=False, meta=False, archives=False)) if num_videos > 0: logger.info('Found {0} media files in {1}'.format(num_videos, output_destination)) status = 0 elif extract != 1: logger.info('Found no media files in {0}. Sending to {1} to process'.format(output_destination, section_name)) status = 0 else: logger.warning('Found no media files in {0}'.format(output_destination)) # Only these sections can handling failed downloads # so make sure everything else gets through without the check for failed if section_name not in ['CouchPotato', 'Radarr', 'SickBeard', 'NzbDrone', 'Sonarr']: status = 0 logger.info('Calling {0}:{1} to post-process:{2}'.format(section_name, usercat, input_name)) if core.TORRENT_CHMOD_DIRECTORY: core.rchmod(output_destination, core.TORRENT_CHMOD_DIRECTORY) result = ProcessResult( message='', status_code=0, ) if section_name == 'UserScript': result = external_script(output_destination, input_name, input_category, section) elif section_name in ['CouchPotato', 'Radarr']: result = movies.process(section_name, output_destination, input_name, status, client_agent, input_hash, input_category) elif section_name in ['SickBeard', 'NzbDrone', 'Sonarr']: if input_hash: input_hash = input_hash.upper() result = tv.process(section_name, output_destination, input_name, status, client_agent, input_hash, input_category) elif section_name in ['HeadPhones', 'Lidarr']: result = music.process(section_name, output_destination, input_name, status, client_agent, input_category) elif section_name == 'Mylar': result = comics.process(section_name, output_destination, input_name, status, client_agent, input_category) elif section_name == 'Gamez': result = games.process(section_name, output_destination, input_name, status, client_agent, input_category) plex_update(input_category) if result.status_code != 0: if not core.TORRENT_RESUME_ON_FAILURE: logger.error('A problem was reported in the autoProcess* script. ' 'Torrent won\'t resume seeding (settings)') elif client_agent != 'manual': logger.error('A problem was reported in the autoProcess* script. ' 'If torrent was paused we will resume seeding') core.resume_torrent(client_agent, input_hash, input_id, input_name) else: if client_agent != 'manual': # update download status in our DB core.update_download_info_status(input_name, 1) # remove torrent if core.USELINK == 'move-sym' and not core.DELETE_ORIGINAL == 1: logger.debug('Checking for sym-links to re-direct in: {0}'.format(input_directory)) for dirpath, dirs, files in os.walk(input_directory): for file in files: logger.debug('Checking symlink: {0}'.format(os.path.join(dirpath, file))) replace_links(os.path.join(dirpath, file)) core.remove_torrent(client_agent, input_hash, input_id, input_name) if not section_name == 'UserScript': # for user script, we assume this is cleaned by the script or option USER_SCRIPT_CLEAN # cleanup our processing folders of any misc unwanted files and empty directories core.clean_dir(output_destination, section_name, input_category) return result
def transcode_directory(dir_name): if not core.FFMPEG: return 1, dir_name logger.info('Checking for files to be transcoded') final_result = 0 # initialize as successful if core.OUTPUTVIDEOPATH: new_dir = core.OUTPUTVIDEOPATH make_dir(new_dir) name = os.path.splitext(os.path.split(dir_name)[1])[0] new_dir = os.path.join(new_dir, name) make_dir(new_dir) else: new_dir = dir_name if platform.system() == 'Windows': bitbucket = open('NUL') else: bitbucket = open('/dev/null') movie_name = os.path.splitext(os.path.split(dir_name)[1])[0] file_list = core.list_media_files(dir_name, media=True, audio=False, meta=False, archives=False) file_list, rem_list, new_list, success = process_list( file_list, new_dir, bitbucket) if not success: bitbucket.close() return 1, dir_name for file in file_list: if isinstance(file, string_types) and os.path.splitext( file)[1] in core.IGNOREEXTENSIONS: continue command, file = build_commands(file, new_dir, movie_name, bitbucket) newfile_path = command[-1] # transcoding files may remove the original file, so make sure to extract subtitles first if core.SEXTRACT and isinstance(file, string_types): extract_subs(file, newfile_path, bitbucket) try: # Try to remove the file that we're transcoding to just in case. (ffmpeg will return an error if it already exists for some reason) os.remove(newfile_path) except OSError as e: if e.errno != errno.ENOENT: # Ignore the error if it's just telling us that the file doesn't exist logger.debug( 'Error when removing transcoding target: {0}'.format(e)) except Exception as e: logger.debug( 'Error when removing transcoding target: {0}'.format(e)) logger.info('Transcoding video: {0}'.format(newfile_path)) print_cmd(command) result = 1 # set result to failed in case call fails. try: if isinstance(file, string_types): proc = subprocess.Popen(command, stdout=bitbucket, stderr=subprocess.PIPE) else: img, data = next(iteritems(file)) proc = subprocess.Popen(command, stdout=bitbucket, stderr=subprocess.PIPE, stdin=subprocess.PIPE) for vob in data['files']: procin = zip_out(vob, img, bitbucket) if procin: logger.debug( 'Feeding in file: {0} to Transcoder'.format(vob)) shutil.copyfileobj(procin.stdout, proc.stdin) procin.stdout.close() out, err = proc.communicate() if err: logger.error('Transcoder returned:{0} has failed'.format(err)) result = proc.returncode except Exception: logger.error( 'Transcoding of video {0} has failed'.format(newfile_path)) if core.SUBSDIR and result == 0 and isinstance(file, string_types): for sub in get_subs(file): name = os.path.splitext(os.path.split(file)[1])[0] subname = os.path.split(sub)[1] newname = os.path.splitext(os.path.split(newfile_path)[1])[0] newpath = os.path.join(core.SUBSDIR, subname.replace(name, newname)) if not os.path.isfile(newpath): os.rename(sub, newpath) if result == 0: try: shutil.copymode(file, newfile_path) except Exception: pass logger.info( 'Transcoding of video to {0} succeeded'.format(newfile_path)) if os.path.isfile(newfile_path) and (file in new_list or not core.DUPLICATE): try: os.unlink(file) except Exception: pass else: logger.error( 'Transcoding of video to {0} failed with result {1}'.format( newfile_path, result)) # this will be 0 (successful) it all are successful, else will return a positive integer for failure. final_result = final_result + result if core.MOUNTED: # In case we mounted an .iso file, unmount here. time.sleep(5) # play it safe and avoid failing to unmount. cmd = ['umount', '-l', core.MOUNTED] print_cmd(cmd) proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=bitbucket) out, err = proc.communicate() time.sleep(5) os.rmdir(core.MOUNTED) core.MOUNTED = None if final_result == 0 and not core.DUPLICATE: for file in rem_list: try: os.unlink(file) except Exception: pass if not os.listdir( text_type(new_dir) ): # this is an empty directory and we didn't transcode into it. os.rmdir(new_dir) new_dir = dir_name if not core.PROCESSOUTPUT and core.DUPLICATE: # We postprocess the original files to CP/SB new_dir = dir_name bitbucket.close() return final_result, new_dir
def transcode_directory(dir_name): if not core.FFMPEG: return 1, dir_name logger.info('Checking for files to be transcoded') final_result = 0 # initialize as successful if core.OUTPUTVIDEOPATH: new_dir = core.OUTPUTVIDEOPATH make_dir(new_dir) name = os.path.splitext(os.path.split(dir_name)[1])[0] new_dir = os.path.join(new_dir, name) make_dir(new_dir) else: new_dir = dir_name if platform.system() == 'Windows': bitbucket = open('NUL') else: bitbucket = open('/dev/null') movie_name = os.path.splitext(os.path.split(dir_name)[1])[0] file_list = core.list_media_files(dir_name, media=True, audio=False, meta=False, archives=False) file_list, rem_list, new_list, success = process_list(file_list, new_dir, bitbucket) if not success: bitbucket.close() return 1, dir_name for file in file_list: if isinstance(file, string_types) and os.path.splitext(file)[1] in core.IGNOREEXTENSIONS: continue command = build_commands(file, new_dir, movie_name, bitbucket) newfile_path = command[-1] # transcoding files may remove the original file, so make sure to extract subtitles first if core.SEXTRACT and isinstance(file, string_types): extract_subs(file, newfile_path, bitbucket) try: # Try to remove the file that we're transcoding to just in case. (ffmpeg will return an error if it already exists for some reason) os.remove(newfile_path) except OSError as e: if e.errno != errno.ENOENT: # Ignore the error if it's just telling us that the file doesn't exist logger.debug('Error when removing transcoding target: {0}'.format(e)) except Exception as e: logger.debug('Error when removing transcoding target: {0}'.format(e)) logger.info('Transcoding video: {0}'.format(newfile_path)) print_cmd(command) result = 1 # set result to failed in case call fails. try: if isinstance(file, string_types): proc = subprocess.Popen(command, stdout=bitbucket, stderr=bitbucket) else: img, data = next(iteritems(file)) proc = subprocess.Popen(command, stdout=bitbucket, stderr=bitbucket, stdin=subprocess.PIPE) for vob in data['files']: procin = zip_out(vob, img, bitbucket) if procin: shutil.copyfileobj(procin.stdout, proc.stdin) procin.stdout.close() proc.communicate() result = proc.returncode except Exception: logger.error('Transcoding of video {0} has failed'.format(newfile_path)) if core.SUBSDIR and result == 0 and isinstance(file, string_types): for sub in get_subs(file): name = os.path.splitext(os.path.split(file)[1])[0] subname = os.path.split(sub)[1] newname = os.path.splitext(os.path.split(newfile_path)[1])[0] newpath = os.path.join(core.SUBSDIR, subname.replace(name, newname)) if not os.path.isfile(newpath): os.rename(sub, newpath) if result == 0: try: shutil.copymode(file, newfile_path) except Exception: pass logger.info('Transcoding of video to {0} succeeded'.format(newfile_path)) if os.path.isfile(newfile_path) and (file in new_list or not core.DUPLICATE): try: os.unlink(file) except Exception: pass else: logger.error('Transcoding of video to {0} failed with result {1}'.format(newfile_path, result)) # 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 core.DUPLICATE: for file in rem_list: try: os.unlink(file) except Exception: pass if not os.listdir(text_type(new_dir)): # this is an empty directory and we didn't transcode into it. os.rmdir(new_dir) new_dir = dir_name if not core.PROCESSOUTPUT and core.DUPLICATE: # We postprocess the original files to CP/SB new_dir = dir_name bitbucket.close() return final_result, new_dir
def rename_subs(path): filepaths = [] sub_ext = ['.srt', '.sub', '.idx'] vidfiles = core.list_media_files(path, media=True, audio=False, meta=False, archives=False) if not vidfiles or len( vidfiles ) > 1: # If there is more than 1 video file, or no video files, we can't rename subs. return name = os.path.splitext(os.path.split(vidfiles[0])[1])[0] for directory, _, filenames in os.walk(path): for filename in filenames: filepaths.extend([os.path.join(directory, filename)]) subfiles = [ item for item in filepaths if os.path.splitext(item)[1] in sub_ext ] subfiles.sort( ) #This should sort subtitle names by language (alpha) and Number (where multiple) renamed = [] for sub in subfiles: subname, ext = os.path.splitext(os.path.basename(sub)) if name in subname: # The sub file name already includes the video name. continue words = re.findall('[a-zA-Z]+', str(subname)) # find whole words in string # parse the words for language descriptors. lan = None for word in words: try: if len(word) == 2: lan = Language.fromalpha2(word.lower()) elif len(word) == 3: lan = Language(word.lower()) elif len(word) > 3: lan = Language.fromname(word.lower()) if lan: break except: #if we didn't find a language, try next word. continue # rename the sub file as name.lan.ext if not lan: # could call ffprobe to parse the sub information and get language if lan unknown here. new_sub_name = name else: new_sub_name = '{name}.{lan}'.format(name=name, lan=str(lan)) new_sub = os.path.join(directory, new_sub_name) # full path and name less ext if '{new_sub}{ext}'.format( new_sub=new_sub, ext=ext ) in renamed: # If duplicate names, add unique number before ext. for i in range(1, len(renamed) + 1): if '{new_sub}.{i}{ext}'.format(new_sub=new_sub, i=i, ext=ext) in renamed: continue new_sub = '{new_sub}.{i}'.format(new_sub=new_sub, i=i) break new_sub = '{new_sub}{ext}'.format(new_sub=new_sub, ext=ext) # add extension now if os.path.isfile(new_sub): # Don't copy over existing - final check. logger.debug( 'Unable to rename sub file {old} as destination {new} already exists' .format(old=sub, new=new_sub)) continue logger.debug('Renaming sub file from {old} to {new}'.format( old=sub, new=new_sub)) renamed.append(new_sub) try: os.rename(sub, new_sub) except Exception as error: logger.error('Unable to rename sub file due to: {error}'.format( error=error)) return