def move_movie(path, guess, move=True): required_keys = ('title', 'year', 'screen_size', 'container') if all(key in guess for key in required_keys): dir_name = '{0} ({1})'.format(guess['title'], guess['year']) movie_dir_path = os.path.join(movie_dir, dir_name) if not os.path.exists(movie_dir_path): os.mkdir(movie_dir_path) destination_path = os.path.join( movie_dir_path, '{title} ({year}) - {size}.{container}'.format( title=guess['title'], year=guess['year'], size=guess['screen_size'], container=guess['container'])) if move: shutil.move(path, destination_path) else: shutil.copyfile(path, destination_path) else: action = 'move' if move else 'copy' command = [ filebot_bin, '--action', action, '--db', 'TheMovieDB', '--format', '{n} ({y})/{n} ({y}) - {vf}', '-non-strict', '-unixfs', '-rename', path, '--output', movie_dir ] result = subprocess.run(command, stdout=subprocess.PIPE) if result.returncode != 0: pb_notify('Failed to rename {0} using filebot'.format(path)) elif b'Skipped' in result.stdout and b'already exists' in result.stdout: pb_notify('Filebot skipped {0}: already exists'.format(path))
def handle_finished_download(): torrent_id = os.environ['TR_TORRENT_ID'] syslog.syslog('Beginning processing of torrent {0}'.format(torrent_id)) transmission_client = transmissionrpc.Client( transmission_host, port=transmission_port, user=transmission_user, password=transmission_password) torrent = transmission_client.get_torrent(torrent_id) # Make sure transmission called us with a completed torrent if torrent.progress != 100.0: syslog.syslog(syslog.LOG_ERR, 'Called with an incomplete torrent') sys.exit(1) if couchpotato_category in torrent.downloadDir: if not ignore_couchpotato: handle_couchpotato(torrent) elif sonarr_category in torrent.downloadDir: if not ignore_sonarr: handle_sonarr(torrent) else: handle_manual(torrent) # Immediately remove torrents that are not whitelisted (by tracker) if not whitelisted(torrent): transmission_client.remove_torrent(torrent_id) pb_notify('Removed non-whitelisted torrent {0}'.format(torrent.name))
def handle_finished_download(): torrent_id = os.environ['TR_TORRENT_ID'] syslog.syslog('Beginning processing of torrent {0}'.format(torrent_id)) transmission_client = transmissionrpc.Client( transmission_host, port=transmission_port, user=transmission_user, password=transmission_password ) torrent = transmission_client.get_torrent(torrent_id) # Make sure transmission called us with a completed torrent if torrent.progress != 100.0: syslog.syslog(syslog.LOG_ERR, 'Called with an incomplete torrent') sys.exit(1) if couchpotato_category in torrent.downloadDir: if not ignore_couchpotato: handle_couchpotato(torrent) elif sonarr_category in torrent.downloadDir: if not ignore_sonarr: handle_sonarr(torrent) else: handle_manual(torrent) # Immediately remove torrents that are not whitelisted (by tracker) if not whitelisted(torrent): transmission_client.remove_torrent(torrent_id) pb_notify('Removed non-whitelisted torrent {0}'.format(torrent.name))
def handle_manual(torrent): auto_processed = False def handle_media(path, move): nonlocal auto_processed guess = guessit.guessit(path) if guess['type'] == 'episode': move_episode(path, guess, move) auto_processed = True elif guess['type'] == 'movie': move_movie(path, guess, move) auto_processed = True part_regex = re.compile('.*part(\d+).rar', re.IGNORECASE) for index, file in torrent.files().items(): file_path = os.path.join(torrent.downloadDir, file['name']) if check_extension(file_path) and 'sample' not in file_path.lower(): # Log and ignore mkv files of less than ~92MiB try: if os.path.getsize(file_path) >= 96811278: handle_media(file_path, False) else: syslog.syslog( syslog.LOG_ERR, 'Detected false media file, skipping' ) except FileNotFoundError: syslog.syslog(syslog.LOG_ERR, 'Torrent file missing, skipping') elif file_path.endswith('rar'): # Ignore parts beyond the first in a rar series match = part_regex.match(file_path) if match and int(match.group(1)) > 1: continue with tempfile.TemporaryDirectory() as temp_dir: paths = extract(file_path, temp_dir) if paths: for path in paths: shutil.chown(path, group=plex_group) os.chmod(path, 0o664) handle_media(path, True) if auto_processed: pb_notify( textwrap.dedent( ''' Manually added torrent {0} finished downloading and was auto-processed '''.format(torrent.name) ).strip() ) else: pb_notify( 'Manually added torrent {0} finished downloading'.format( torrent.name ) )
def move_episode(path, guess, move=True): required_keys = ('title', 'season', 'episode', 'episode_title', 'container') if all(key in guess for key in required_keys): tv_show_path = os.path.join(tv_dir, guess['title']) if not os.path.exists(tv_show_path): os.mkdir(tv_show_path) season = 'Season {0}'.format(guess['season']) season_path = os.path.join(tv_show_path, season) if not os.path.exists(season_path): os.mkdir(season_path) destination_path = os.path.join( season_path, '{title} - S{season}E{episode} - {episode_title}.{container}' .format( title=guess['title'], season=str(guess['season']).zfill(2), episode=str(guess['episode']).zfill(2), episode_title=guess['episode_title'], container=guess['container'] ) ) if move: shutil.move(path, destination_path) else: shutil.copyfile(path, destination_path) else: action = 'move' if move else 'copy' command = [ filebot_bin, '--action', action, '--db', 'TheTVDB', '--format', '{n}/Season {s}/{n} - {s00e00} - {t}', '-non-strict', '-unixfs', '-rename', path, '--output', tv_dir ] result = subprocess.run(command, stdout=subprocess.PIPE) if result.returncode != 0: pb_notify('Failed to rename {0} using filebot'.format(path)) elif b'Skipped' in result.stdout and b'already exists' in result.stdout: pb_notify('Filebot skipped {0}: already exists'.format(path))
def handle_manual(torrent): auto_processed = False def handle_media(path, move): nonlocal auto_processed guess = guessit.guessit(path) if guess['type'] == 'episode': move_episode(path, guess, move) auto_processed = True elif guess['type'] == 'movie': move_movie(path, guess, move) auto_processed = True part_regex = re.compile('.*part(\d+).rar', re.IGNORECASE) for index, file in torrent.files().items(): file_path = os.path.join(torrent.downloadDir, file['name']) if check_extension(file_path) and 'sample' not in file_path.lower(): # Log and ignore mkv files of less than ~92MiB try: if os.path.getsize(file_path) >= 96811278: handle_media(file_path, False) else: syslog.syslog(syslog.LOG_ERR, 'Detected false media file, skipping') except FileNotFoundError: syslog.syslog(syslog.LOG_ERR, 'Torrent file missing, skipping') elif file_path.endswith('rar'): # Ignore parts beyond the first in a rar series match = part_regex.match(file_path) if match and int(match.group(1)) > 1: continue with tempfile.TemporaryDirectory() as temp_dir: paths = extract(file_path, temp_dir) if paths: for path in paths: shutil.chown(path, group=plex_group) os.chmod(path, 0o664) handle_media(path, True) if auto_processed: pb_notify( textwrap.dedent(''' Manually added torrent {0} finished downloading and was auto-processed '''.format(torrent.name)).strip()) else: pb_notify('Manually added torrent {0} finished downloading'.format( torrent.name))
def move_movie(path, guess, move=True): required_keys = ('title', 'year', 'screen_size', 'container') if all(key in guess for key in required_keys): dir_name = '{0} ({1})'.format(guess['title'], guess['year']) movie_dir_path = os.path.join(movie_dir, dir_name) if not os.path.exists(movie_dir_path): os.mkdir(movie_dir_path) destination_path = os.path.join( movie_dir_path, '{title} ({year}) - {size}.{container}'.format( title=guess['title'], year=guess['year'], size=guess['screen_size'], container=guess['container'] ) ) if move: shutil.move(path, destination_path) else: shutil.copyfile(path, destination_path) else: action = 'move' if move else 'copy' command = [ filebot_bin, '--action', action, '--db', 'TheMovieDB', '--format', '{n} ({y})/{n} ({y}) - {vf}', '-non-strict', '-unixfs', '-rename', path, '--output', movie_dir ] result = subprocess.run(command, stdout=subprocess.PIPE) if result.returncode != 0: pb_notify('Failed to rename {0} using filebot'.format(path)) elif b'Skipped' in result.stdout and b'already exists' in result.stdout: pb_notify('Filebot skipped {0}: already exists'.format(path))
def clean(): transmission_client = transmissionrpc.Client( config['transmission']['host'], port=config['transmission']['port'], user=config['transmission']['user'], password=config['transmission']['password'] ) torrents = transmission_client.get_torrents() now = datetime.datetime.now() time_threshold = config['transmission']['time_threshold'] for torrent in torrents: if torrent.progress == 100.0 and \ torrent.status in ('seeding', 'stopped'): done = torrent.date_done diff = now - done if diff.days >= time_threshold: pb_notify( textwrap.dedent( ''' Torrent {torrent} older than {days} days: removing (with data) '''.format(torrent=torrent.name, days=time_threshold) ).strip() ) transmission_client.remove_torrent( torrent.id, delete_data=True ) elif torrent.ratio >= config['transmission']['ratio_threshold']: pb_notify( textwrap.dedent( ''' Torrent {0} reached threshold ratio or higher: removing (with data) '''.format(torrent.name) ).strip() ) transmission_client.remove_torrent( torrent.id, delete_data=True )
def move_episode(path, guess, move=True): required_keys = ('title', 'season', 'episode', 'episode_title', 'container') if all(key in guess for key in required_keys): tv_show_path = os.path.join(tv_dir, guess['title']) if not os.path.exists(tv_show_path): os.mkdir(tv_show_path) season = 'Season {0}'.format(guess['season']) season_path = os.path.join(tv_show_path, season) if not os.path.exists(season_path): os.mkdir(season_path) destination_path = os.path.join( season_path, '{title} - S{season}E{episode} - {episode_title}.{container}'. format(title=guess['title'], season=str(guess['season']).zfill(2), episode=str(guess['episode']).zfill(2), episode_title=guess['episode_title'], container=guess['container'])) if move: shutil.move(path, destination_path) else: shutil.copyfile(path, destination_path) else: action = 'move' if move else 'copy' command = [ filebot_bin, '--action', action, '--db', 'TheTVDB', '--format', '{n}/Season {s}/{n} - {s00e00} - {t}', '-non-strict', '-unixfs', '-rename', path, '--output', tv_dir ] result = subprocess.run(command, stdout=subprocess.PIPE) if result.returncode != 0: pb_notify('Failed to rename {0} using filebot'.format(path)) elif b'Skipped' in result.stdout and b'already exists' in result.stdout: pb_notify('Filebot skipped {0}: already exists'.format(path))
def extract(path, destination): if unrar.rarfile.is_rarfile(path): try: rar = unrar.rarfile.RarFile(path) if not rar.testrar(): # Use a set to prevent duplicates from infolist() paths = set() for member in rar.infolist(): if check_extension(member.filename): paths.add(rar.extract(member, path=destination)) pb_notify( 'Successfully unpacked rar archive: {0}'.format(file_path)) return paths else: pb_notify('{0} failed the rar integrity check'.format(path)) except unrar.unrarlib.UnrarException: pb_notify('Error while opening {0}'.format(path)) pb_notify('Failed to unpacked rar archive (not a rar): {0}'.format(path)) return False
def extract(path, destination): if unrar.rarfile.is_rarfile(path): try: rar = unrar.rarfile.RarFile(path) if not rar.testrar(): # Use a set to prevent duplicates from infolist() paths = set() for member in rar.infolist(): if check_extension(member.filename): paths.add(rar.extract(member, path=destination)) pb_notify( 'Successfully unpacked rar archive: {0}'.format(file_path) ) return paths else: pb_notify('{0} failed the rar integrity check'.format(path)) except unrar.unrarlib.UnrarException: pb_notify('Error while opening {0}'.format(path)) pb_notify('Failed to unpacked rar archive (not a rar): {0}'.format(path)) return False