diff --git a/couchpotato/core/downloaders/transmission/main.py b/couchpotato/core/downloaders/transmission/main.py index 46b5f3b4..b8b1f9df 100644 --- a/couchpotato/core/downloaders/transmission/main.py +++ b/couchpotato/core/downloaders/transmission/main.py @@ -103,15 +103,15 @@ class Transmission(Downloader): for torrent in queue['torrents']: if torrent['hashString'] in ids: - log.debug('name=%s / id=%s / downloadDir=%s / hashString=%s / percentDone=%s / status=%s / eta=%s / uploadRatio=%s / isFinished=%s', - (torrent['name'], torrent['id'], torrent['downloadDir'], torrent['hashString'], torrent['percentDone'], torrent['status'], torrent['eta'], torrent['uploadRatio'], torrent['isFinished'])) + log.debug('name=%s / id=%s / downloadDir=%s / hashString=%s / percentDone=%s / status=%s / isStalled=%s / eta=%s / uploadRatio=%s / isFinished=%s', + (torrent['name'], torrent['id'], torrent['downloadDir'], torrent['hashString'], torrent['percentDone'], torrent['status'], torrent.get('isStalled', 'N/A'), torrent['eta'], torrent['uploadRatio'], torrent['isFinished'])) torrent_files = [] for file_item in torrent['files']: torrent_files.append(sp(os.path.join(torrent['downloadDir'], file_item['name']))) status = 'busy' - if torrent.get('isStalled') and self.conf('stalled_as_failed'): + if torrent.get('isStalled') and not torrent['percentDone'] == 1 and self.conf('stalled_as_failed'): status = 'failed' elif torrent['status'] == 0 and torrent['percentDone'] == 1: status = 'completed' diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py index fd9037f9..cac612fc 100644 --- a/couchpotato/core/plugins/release/main.py +++ b/couchpotato/core/plugins/release/main.py @@ -211,22 +211,25 @@ class Release(Plugin): db = get_session() rel = db.query(Relea).filter_by(id = id).first() - if rel: - item = {} - for info in rel.info: - item[info.identifier] = info.value + if not rel: + log.error('Couldn\'t find release with id: %s', id) + return { + 'success': False + } - fireEvent('notify.frontend', type = 'release.manual_download', data = True, message = 'Snatching "%s"' % item['name']) + item = {} + for info in rel.info: + item[info.identifier] = info.value - # Get matching provider - provider = fireEvent('provider.belongs_to', item['url'], provider = item.get('provider'), single = True) + fireEvent('notify.frontend', type = 'release.manual_download', data = True, message = 'Snatching "%s"' % item['name']) - if not item.get('protocol'): - item['protocol'] = item['type'] - item['type'] = 'movie' + # Get matching provider + provider = fireEvent('provider.belongs_to', item['url'], provider = item.get('provider'), single = True) - if item.get('protocol') != 'torrent_magnet': - item['download'] = provider.loginDownload if provider.urls.get('login') else provider.download + # Backwards compatibility code + if not item.get('protocol'): + item['protocol'] = item['type'] + item['type'] = 'movie' success = self.download(data = item, media = rel.media.to_dict({ 'profile': {'types': {'quality': {}}}, @@ -234,96 +237,109 @@ class Release(Plugin): 'library': {'titles': {}, 'files':{}}, 'files': {} }), manual = True) + if item.get('protocol') != 'torrent_magnet': + item['download'] = provider.loginDownload if provider.urls.get('login') else provider.download - if success: - db.expunge_all() - rel = db.query(Relea).filter_by(id = id).first() # Get release again @RuudBurger why do we need to get it again?? + success = self.download(data = item, media = rel.movie.to_dict({ + 'profile': {'types': {'quality': {}}}, + 'releases': {'status': {}, 'quality': {}}, + 'library': {'titles': {}, 'files':{}}, + 'files': {} + }), manual = True) - fireEvent('notify.frontend', type = 'release.manual_download', data = True, message = 'Successfully snatched "%s"' % item['name']) - return { - 'success': success - } - else: - log.error('Couldn\'t find release with id: %s', id) + if success: + db.expunge_all() + rel = db.query(Relea).filter_by(id = id).first() # Get release again @RuudBurger why do we need to get it again?? + fireEvent('notify.frontend', type = 'release.manual_download', data = True, message = 'Successfully snatched "%s"' % item['name']) return { - 'success': False + 'success': success } def download(self, data, media, manual = False): + # Backwards compatibility code if not data.get('protocol'): data['protocol'] = data['type'] data['type'] = 'movie' # Test to see if any downloaders are enabled for this type downloader_enabled = fireEvent('download.enabled', manual, data, single = True) + if not downloader_enabled: + log.info('Tried to download, but none of the "%s" downloaders are enabled or gave an error', (data.get('protocol'))) + return False - if downloader_enabled: - snatched_status, done_status, active_status = fireEvent('status.get', ['snatched', 'done', 'active'], single = True) + # Download NZB or torrent file + filedata = None + if data.get('download') and (ismethod(data.get('download')) or isfunction(data.get('download'))): + filedata = data.get('download')(url = data.get('url'), nzb_id = data.get('id')) + if filedata == 'try_next': + return filedata - # Download release to temp - filedata = None - if data.get('download') and (ismethod(data.get('download')) or isfunction(data.get('download'))): - filedata = data.get('download')(url = data.get('url'), nzb_id = data.get('id')) - if filedata == 'try_next': - return filedata + # Send NZB or torrent file to downloader + download_result = fireEvent('download', data = data, media = media, manual = manual, filedata = filedata, single = True) + if not download_result: + log.info('Tried to download, but the "%s" downloader gave an error', (data.get('protocol'))) + return False + log.debug('Downloader result: %s', download_result) - download_result = fireEvent('download', data = data, media = media, manual = manual, filedata = filedata, single = True) - log.debug('Downloader result: %s', download_result) + snatched_status, done_status, downloaded_status, active_status = fireEvent('status.get', ['snatched', 'done', 'downloaded', 'active'], single = True) - if download_result: - try: - # Mark release as snatched - db = get_session() - rls = db.query(Relea).filter_by(identifier = md5(data['url'])).first() - if rls: - renamer_enabled = Env.setting('enabled', 'renamer') + try: + db = get_session() + rls = db.query(Relea).filter_by(identifier = md5(data['url'])).first() + if not rls: + log.error('No release found to store download information in') + return False - # Save download-id info if returned - if isinstance(download_result, dict): - for key in download_result: - rls_info = ReleaseInfo( - identifier = 'download_%s' % key, - value = toUnicode(download_result.get(key)) - ) - rls.info.append(rls_info) - db.commit() + renamer_enabled = Env.setting('enabled', 'renamer') - log_movie = '%s (%s) in %s' % (getTitle(media['library']), media['library']['year'], rls.quality.label) - snatch_message = 'Snatched "%s": %s' % (data.get('name'), log_movie) - log.info(snatch_message) - fireEvent('%s.snatched' % data['type'], message = snatch_message, data = rls.to_dict()) + # Save download-id info if returned + if isinstance(download_result, dict): + for key in download_result: + rls_info = ReleaseInfo( + identifier = 'download_%s' % key, + value = toUnicode(download_result.get(key)) + ) + rls.info.append(rls_info) + db.commit() - # If renamer isn't used, mark media done - if not renamer_enabled: - try: - if media['status_id'] == active_status.get('id'): - for profile_type in media['profile']['types']: - if profile_type['quality_id'] == rls.quality.id and profile_type['finish']: - log.info('Renamer disabled, marking media as finished: %s', log_movie) + log_movie = '%s (%s) in %s' % (getTitle(media['library']), media['library']['year'], rls.quality.label) + snatch_message = 'Snatched "%s": %s' % (data.get('name'), log_movie) + log.info(snatch_message) + fireEvent('%s.snatched' % data['type'], message = snatch_message, data = rls.to_dict()) - # Mark release done - self.updateStatus(rls.id, status = done_status) + # Mark release as snatched + if renamer_enabled: + self.updateStatus(rls.id, status = snatched_status) - # Mark media done - mdia = db.query(Media).filter_by(id = media['id']).first() - mdia.status_id = done_status.get('id') - mdia.last_edit = int(time.time()) - db.commit() - except: - log.error('Failed marking media finished, renamer disabled: %s', traceback.format_exc()) - else: - self.updateStatus(rls.id, status = snatched_status) + # If renamer isn't used, mark media done if finished or release downloaded + else: + if media['status_id'] == active_status.get('id'): + finished = next((True for profile_type in media['profile']['types'] if \ + profile_type['quality_id'] == rls.quality.id and profile_type['finish']), False) + if finished: + log.info('Renamer disabled, marking media as finished: %s', log_movie) - except: - log.error('Failed marking media finished: %s', traceback.format_exc()) + # Mark release done + self.updateStatus(rls.id, status = done_status) - return True + # Mark media done + mdia = db.query(Media).filter_by(id = media['id']).first() + mdia.status_id = done_status.get('id') + mdia.last_edit = int(time.time()) + db.commit() - log.info('Tried to download, but none of the "%s" downloaders are enabled or gave an error', (data.get('protocol'))) + return True - return False + # Assume release downloaded + self.updateStatus(rls.id, status = downloaded_status) + + except: + log.error('Failed storing download status: %s', traceback.format_exc()) + return False + + return True def tryDownloadResult(self, results, media, quality_type, manual = False): ignored_status, failed_status = fireEvent('status.get', ['ignored', 'failed'], single = True) diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index 71f67499..2c6df8ae 100755 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -30,10 +30,11 @@ class Renamer(Plugin): 'desc': 'For the renamer to check for new files to rename in a folder', 'params': { 'async': {'desc': 'Optional: Set to 1 if you dont want to fire the renamer.scan asynchronous.'}, - 'movie_folder': {'desc': 'Optional: The folder of the movie to scan. Keep empty for default renamer folder.'}, - 'files': {'desc': 'Optional: Provide the release files if more releases are in the same movie_folder, delimited with a \'|\'. Note that no dedicated release folder is expected for releases with one file.'}, + 'media_folder': {'desc': 'Optional: The folder of the media to scan. Keep empty for default renamer folder.'}, + 'files': {'desc': 'Optional: Provide the release files if more releases are in the same media_folder, delimited with a \'|\'. Note that no dedicated release folder is expected for releases with one file.'}, + 'base_folder': {'desc': 'Optional: The folder to find releases in. Leave empty for default folder.'}, 'downloader' : {'desc': 'Optional: The downloader the release has been downloaded with. \'download_id\' is required with this option.'}, - 'download_id': {'desc': 'Optional: The nzb/torrent ID of the release in movie_folder. \'downloader\' is required with this option.'}, + 'download_id': {'desc': 'Optional: The nzb/torrent ID of the release in media_folder. \'downloader\' is required with this option.'}, 'status': {'desc': 'Optional: The status of the release: \'completed\' (default) or \'seeding\''}, }, }) @@ -64,25 +65,32 @@ class Renamer(Plugin): def scanView(self, **kwargs): async = tryInt(kwargs.get('async', 0)) - movie_folder = sp(kwargs.get('movie_folder')) + base_folder = kwargs.get('base_folder') + media_folder = sp(kwargs.get('media_folder')) + + # Backwards compatibility, to be removed after a few versions :) + if not media_folder: + media_folder = sp(kwargs.get('movie_folder')) + downloader = kwargs.get('downloader') download_id = kwargs.get('download_id') files = '|'.join([sp(filename) for filename in splitString(kwargs.get('files'), '|')]) status = kwargs.get('status', 'completed') - release_download = {'folder': movie_folder} if movie_folder else None - if release_download: + release_download = None + if not base_folder and media_folder: + release_download = {'folder': media_folder} release_download.update({'id': download_id, 'downloader': downloader, 'status': status, 'files': files} if download_id else {}) fire_handle = fireEvent if not async else fireEventAsync - fire_handle('renamer.scan', release_download) + fire_handle('renamer.scan', base_folder = base_folder, release_download = release_download) return { 'success': True } - def scan(self, release_download = None): + def scan(self, base_folder = None, release_download = None): if not release_download: release_download = {} if self.isDisabled(): @@ -92,11 +100,14 @@ class Renamer(Plugin): log.info('Renamer is already running, if you see this often, check the logs above for errors.') return + if not base_folder: + base_folder = self.conf('from') + from_folder = sp(self.conf('from')) to_folder = sp(self.conf('to')) - # Get movie folder to process - movie_folder = release_download.get('folder') + # Get media folder to process + media_folder = release_download.get('folder') # Get all folders that should not be processed no_process = [to_folder] @@ -109,45 +120,45 @@ class Renamer(Plugin): pass # Check to see if the no_process folders are inside the "from" folder. - if not os.path.isdir(from_folder) or not os.path.isdir(to_folder): - log.error('Both the "To" and "From" have to exist.') + if not os.path.isdir(base_folder) or not os.path.isdir(to_folder): + log.error('Both the "To" and "From" folder have to exist.') return else: for item in no_process: - if '%s%s' % (from_folder, os.path.sep) in item: - log.error('To protect your data, the movie libraries can\'t be inside of or the same as the "from" folder.') + if '%s%s' % (base_folder, os.path.sep) in item: + log.error('To protect your data, the media libraries can\'t be inside of or the same as the "from" folder.') return - # Check to see if the no_process folders are inside the provided movie_folder - if movie_folder and not os.path.isdir(movie_folder): - log.debug('The provided movie folder %s does not exist. Trying to find it in the \'from\' folder.', movie_folder) + # Check to see if the no_process folders are inside the provided media_folder + if media_folder and not os.path.isdir(media_folder): + log.debug('The provided media folder %s does not exist. Trying to find it in the \'from\' folder.', media_folder) # Update to the from folder if len(splitString(release_download.get('files'), '|')) == 1: - new_movie_folder = from_folder + new_media_folder = from_folder else: - new_movie_folder = os.path.join(from_folder, os.path.basename(movie_folder)) + new_media_folder = os.path.join(from_folder, os.path.basename(media_folder)) - if not os.path.isdir(new_movie_folder): - log.error('The provided movie folder %s does not exist and could also not be found in the \'from\' folder.', movie_folder) + if not os.path.isdir(new_media_folder): + log.error('The provided media folder %s does not exist and could also not be found in the \'from\' folder.', media_folder) return # Update the files - new_files = [os.path.join(new_movie_folder, os.path.relpath(filename, movie_folder)) for filename in splitString(release_download.get('files'), '|')] + new_files = [os.path.join(new_media_folder, os.path.relpath(filename, media_folder)) for filename in splitString(release_download.get('files'), '|')] if new_files and not os.path.isfile(new_files[0]): - log.error('The provided movie folder %s does not exist and its files could also not be found in the \'from\' folder.', movie_folder) + log.error('The provided media folder %s does not exist and its files could also not be found in the \'from\' folder.', media_folder) return # Update release_download info to the from folder - log.debug('Release %s found in the \'from\' folder.', movie_folder) - release_download['folder'] = new_movie_folder + log.debug('Release %s found in the \'from\' folder.', media_folder) + release_download['folder'] = new_media_folder release_download['files'] = '|'.join(new_files) - movie_folder = new_movie_folder + media_folder = new_media_folder - if movie_folder: + if media_folder: for item in no_process: - if '%s%s' % (movie_folder, os.path.sep) in item: - log.error('To protect your data, the movie libraries can\'t be inside of or the same as the provided movie folder.') + if '%s%s' % (media_folder, os.path.sep) in item: + log.error('To protect your data, the media libraries can\'t be inside of or the same as the provided media folder.') return # Make sure a checkSnatched marked all downloads/seeds as such @@ -156,26 +167,26 @@ class Renamer(Plugin): self.renaming_started = True - # make sure the movie folder name is included in the search + # make sure the media folder name is included in the search folder = None files = [] - if movie_folder: - log.info('Scanning movie folder %s...', movie_folder) - folder = os.path.dirname(movie_folder) + if media_folder: + log.info('Scanning media folder %s...', media_folder) + folder = os.path.dirname(media_folder) if release_download.get('files', ''): files = splitString(release_download['files'], '|') # If there is only one file in the torrent, the downloader did not create a subfolder if len(files) == 1: - folder = movie_folder + folder = media_folder else: # Get all files from the specified folder try: - for root, folders, names in os.walk(movie_folder): + for root, folders, names in os.walk(media_folder): files.extend([sp(os.path.join(root, name)) for name in names]) except: - log.error('Failed getting files from %s: %s', (movie_folder, traceback.format_exc())) + log.error('Failed getting files from %s: %s', (media_folder, traceback.format_exc())) db = get_session() @@ -185,10 +196,10 @@ class Renamer(Plugin): # Unpack any archives extr_files = None if self.conf('unrar'): - folder, movie_folder, files, extr_files = self.extractFiles(folder = folder, movie_folder = movie_folder, files = files, + folder, media_folder, files, extr_files = self.extractFiles(folder = folder, media_folder = media_folder, files = files, cleanup = self.conf('cleanup') and not self.downloadIsTorrent(release_download)) - groups = fireEvent('scanner.scan', folder = folder if folder else from_folder, + groups = fireEvent('scanner.scan', folder = folder if folder else base_folder, files = files, release_download = release_download, return_ignored = False, single = True) or [] folder_name = self.conf('folder_name') @@ -229,7 +240,7 @@ class Renamer(Plugin): # Overwrite destination when set in category destination = to_folder category_label = '' - for movie in library_ent.media: + for movie in library_ent.movies: if movie.category and movie.category.label: category_label = movie.category.label @@ -403,13 +414,13 @@ class Renamer(Plugin): remove_leftovers = True # Add it to the wanted list before we continue - if len(library_ent.media) == 0: + if len(library_ent.movies) == 0: profile = db.query(Profile).filter_by(core = True, label = group['meta_data']['quality']['label']).first() fireEvent('movie.add', params = {'identifier': group['library']['identifier'], 'profile_id': profile.id}, search_after = False) db.expire_all() library_ent = db.query(Library).filter_by(identifier = group['library']['identifier']).first() - for movie in library_ent.media: + for movie in library_ent.movies: # Mark movie "done" once it's found the quality with the finish check try: @@ -497,7 +508,7 @@ class Renamer(Plugin): os.remove(src) parent_dir = os.path.dirname(src) - if delete_folders.count(parent_dir) == 0 and os.path.isdir(parent_dir) and not parent_dir in [destination, movie_folder] and not from_folder in parent_dir: + if delete_folders.count(parent_dir) == 0 and os.path.isdir(parent_dir) and not '%s%s' % (parent_dir, os.path.sep) in [destination, media_folder] and not '%s%s' % (base_folder, os.path.sep) in parent_dir: delete_folders.append(parent_dir) except: @@ -529,7 +540,7 @@ class Renamer(Plugin): self.tagRelease(group = group, tag = 'failed_rename') # Tag folder if it is in the 'from' folder and it will not be removed because it is a torrent - if self.movieInFromFolder(movie_folder) and self.downloadIsTorrent(release_download): + if self.movieInFromFolder(media_folder) and self.downloadIsTorrent(release_download): self.tagRelease(group = group, tag = 'renamed_already') # Remove matching releases @@ -541,12 +552,12 @@ class Renamer(Plugin): log.error('Failed removing %s: %s', (release.identifier, traceback.format_exc())) if group['dirname'] and group['parentdir'] and not self.downloadIsTorrent(release_download): - if movie_folder: + if media_folder: # Delete the movie folder - group_folder = movie_folder + group_folder = media_folder else: # Delete the first empty subfolder in the tree relative to the 'from' folder - group_folder = sp(os.path.join(from_folder, os.path.relpath(group['parentdir'], from_folder).split(os.path.sep)[0])) + group_folder = sp(os.path.join(base_folder, os.path.relpath(group['parentdir'], base_folder).split(os.path.sep)[0])) try: log.info('Deleting folder: %s', group_folder) @@ -614,6 +625,11 @@ Remove it if you want it to be renamed (again, or at least let it try again) tag_files.extend([os.path.join(root, name) for name in names]) for filename in tag_files: + + # Dont tag .ignore files + if os.path.splitext(filename)[1] == '.ignore': + continue + tag_filename = '%s.%s.ignore' % (os.path.splitext(filename)[0], tag) if not os.path.isfile(tag_filename): self.createFile(tag_filename, text) @@ -806,126 +822,159 @@ Remove it if you want it to be renamed (again, or at least let it try again) Release.status_id.in_([snatched_status.get('id'), seeding_status.get('id'), missing_status.get('id')]) ).all() + if not rels: + #No releases found that need status checking + self.checking_snatched = False + return True + + # Collect all download information with the download IDs from the releases + download_ids = [] + try: + for rel in rels: + rel_dict = rel.to_dict({'info': {}}) + if rel_dict['info'].get('download_id') and rel_dict['info'].get('download_downloader'): + download_ids.append({'id': rel_dict['info']['download_id'], 'downloader': rel_dict['info']['download_downloader']}) + except: + log.error('Error getting download IDs from database') + self.checking_snatched = False + return False + + release_downloads = fireEvent('download.status', download_ids, merge = True) + if not release_downloads: + log.debug('Download status functionality is not implemented for any active downloaders.') + fireEvent('renamer.scan') + + self.checking_snatched = False + return True + scan_releases = [] scan_required = False - if rels: - log.debug('Checking status snatched releases...') + log.debug('Checking status snatched releases...') - release_downloads = fireEvent('download.status', merge = True) - if not release_downloads: - log.debug('Download status functionality is not implemented for active downloaders.') - scan_required = True - else: - try: - for rel in rels: - rel_dict = rel.to_dict({'info': {}}) - movie_dict = fireEvent('media.get', media_id = rel.media_id, single = True) + try: + for rel in rels: + rel_dict = rel.to_dict({'info': {}}) + movie_dict = fireEvent('media.get', media_id = rel.movie_id, single = True) - if not isinstance(rel_dict['info'], (dict)): - log.error('Faulty release found without any info, ignoring.') + if not isinstance(rel_dict['info'], (dict)): + log.error('Faulty release found without any info, ignoring.') + fireEvent('release.update_status', rel.id, status = ignored_status, single = True) + continue + + # Check if download ID is available + if not rel_dict['info'].get('download_id') or not rel_dict['info'].get('download_downloader'): + log.debug('Download status functionality is not implemented for downloader (%s) of release %s.', (rel_dict['info'].get('download_downloader', 'unknown'), rel_dict['info']['name'])) + scan_required = True + + # Continue with next release + continue + + # Find release in downloaders + nzbname = self.createNzbName(rel_dict['info'], movie_dict) + + for release_download in release_downloads: + found_release = False + if rel_dict['info'].get('download_id'): + if release_download['id'] == rel_dict['info']['download_id'] and release_download['downloader'] == rel_dict['info']['download_downloader']: + log.debug('Found release by id: %s', release_download['id']) + found_release = True + break + else: + if release_download['name'] == nzbname or rel_dict['info']['name'] in release_download['name'] or getImdb(release_download['name']) == movie_dict['library']['identifier']: + log.debug('Found release by release name or imdb ID: %s', release_download['name']) + found_release = True + break + + if not found_release: + log.info('%s not found in downloaders', nzbname) + + #Check status if already missing and for how long, if > 1 week, set to ignored else to missing + if rel.status_id == missing_status.get('id'): + if rel.last_edit < int(time.time()) - 7 * 24 * 60 * 60: fireEvent('release.update_status', rel.id, status = ignored_status, single = True) - continue + else: + # Set the release to missing + fireEvent('release.update_status', rel.id, status = missing_status, single = True) - # check status - nzbname = self.createNzbName(rel_dict['info'], movie_dict) + # Continue with next release + continue - found = False - for release_download in release_downloads: - found_release = False - if rel_dict['info'].get('download_id'): - if release_download['id'] == rel_dict['info']['download_id'] and release_download['downloader'] == rel_dict['info']['download_downloader']: - log.debug('Found release by id: %s', release_download['id']) - found_release = True + # Log that we found the release + timeleft = 'N/A' if release_download['timeleft'] == -1 else release_download['timeleft'] + log.debug('Found %s: %s, time to go: %s', (release_download['name'], release_download['status'].upper(), timeleft)) + + # Check status of release + if release_download['status'] == 'busy': + # Set the release to snatched if it was missing before + fireEvent('release.update_status', rel.id, status = snatched_status, single = True) + + # Tag folder if it is in the 'from' folder and it will not be processed because it is still downloading + if self.movieInFromFolder(release_download['folder']): + self.tagRelease(release_download = release_download, tag = 'downloading') + + elif release_download['status'] == 'seeding': + #If linking setting is enabled, process release + if self.conf('file_action') != 'move' and not rel.status_id == seeding_status.get('id') and self.statusInfoComplete(release_download): + log.info('Download of %s completed! It is now being processed while leaving the original files alone for seeding. Current ratio: %s.', (release_download['name'], release_download['seed_ratio'])) + + # Remove the downloading tag + self.untagRelease(release_download = release_download, tag = 'downloading') + + # Scan and set the torrent to paused if required + release_download.update({'pause': True, 'scan': True, 'process_complete': False}) + scan_releases.append(release_download) + else: + #let it seed + log.debug('%s is seeding with ratio: %s', (release_download['name'], release_download['seed_ratio'])) + + # Set the release to seeding + fireEvent('release.update_status', rel.id, status = seeding_status, single = True) + + elif release_download['status'] == 'failed': + # Set the release to failed + fireEvent('release.update_status', rel.id, status = failed_status, single = True) + + fireEvent('download.remove_failed', release_download, single = True) + + if self.conf('next_on_failed'): + fireEvent('movie.searcher.try_next_release', media_id = rel.movie_id) + + elif release_download['status'] == 'completed': + log.info('Download of %s completed!', release_download['name']) + + #Make sure the downloader sent over a path to look in + if self.statusInfoComplete(release_download): + + # If the release has been seeding, process now the seeding is done + if rel.status_id == seeding_status.get('id'): + if self.conf('file_action') != 'move': + # Set the release to done as the movie has already been renamed + fireEvent('release.update_status', rel.id, status = downloaded_status, single = True) + + # Allow the downloader to clean-up + release_download.update({'pause': False, 'scan': False, 'process_complete': True}) + scan_releases.append(release_download) else: - if release_download['name'] == nzbname or rel_dict['info']['name'] in release_download['name'] or getImdb(release_download['name']) == movie_dict['library']['identifier']: - found_release = True + # Scan and Allow the downloader to clean-up + release_download.update({'pause': False, 'scan': True, 'process_complete': True}) + scan_releases.append(release_download) - if found_release: - timeleft = 'N/A' if release_download['timeleft'] == -1 else release_download['timeleft'] - log.debug('Found %s: %s, time to go: %s', (release_download['name'], release_download['status'].upper(), timeleft)) + else: + # Set the release to snatched if it was missing before + fireEvent('release.update_status', rel.id, status = snatched_status, single = True) - if release_download['status'] == 'busy': - # Set the release to snatched if it was missing before - fireEvent('release.update_status', rel.id, status = snatched_status, single = True) + # Remove the downloading tag + self.untagRelease(release_download = release_download, tag = 'downloading') - # Tag folder if it is in the 'from' folder and it will not be processed because it is still downloading - if self.movieInFromFolder(release_download['folder']): - self.tagRelease(release_download = release_download, tag = 'downloading') + # Scan and Allow the downloader to clean-up + release_download.update({'pause': False, 'scan': True, 'process_complete': True}) + scan_releases.append(release_download) + else: + scan_required = True - elif release_download['status'] == 'seeding': - #If linking setting is enabled, process release - if self.conf('file_action') != 'move' and not rel.status_id == seeding_status.get('id') and self.statusInfoComplete(release_download): - log.info('Download of %s completed! It is now being processed while leaving the original files alone for seeding. Current ratio: %s.', (release_download['name'], release_download['seed_ratio'])) - - # Remove the downloading tag - self.untagRelease(release_download = release_download, tag = 'downloading') - - # Scan and set the torrent to paused if required - release_download.update({'pause': True, 'scan': True, 'process_complete': False}) - scan_releases.append(release_download) - else: - #let it seed - log.debug('%s is seeding with ratio: %s', (release_download['name'], release_download['seed_ratio'])) - - # Set the release to seeding - fireEvent('release.update_status', rel.id, status = seeding_status, single = True) - - elif release_download['status'] == 'failed': - # Set the release to failed - fireEvent('release.update_status', rel.id, status = failed_status, single = True) - - fireEvent('download.remove_failed', release_download, single = True) - - if self.conf('next_on_failed'): - fireEvent('movie.searcher.try_next_release', media_id = rel.media_id) - elif release_download['status'] == 'completed': - log.info('Download of %s completed!', release_download['name']) - if self.statusInfoComplete(release_download): - - # If the release has been seeding, process now the seeding is done - if rel.status_id == seeding_status.get('id'): - if self.conf('file_action') != 'move': - # Set the release to done as the movie has already been renamed - fireEvent('release.update_status', rel.id, status = downloaded_status, single = True) - - # Allow the downloader to clean-up - release_download.update({'pause': False, 'scan': False, 'process_complete': True}) - scan_releases.append(release_download) - else: - # Scan and Allow the downloader to clean-up - release_download.update({'pause': False, 'scan': True, 'process_complete': True}) - scan_releases.append(release_download) - - else: - # Set the release to snatched if it was missing before - fireEvent('release.update_status', rel.id, status = snatched_status, single = True) - - # Remove the downloading tag - self.untagRelease(release_download = release_download, tag = 'downloading') - - # Scan and Allow the downloader to clean-up - release_download.update({'pause': False, 'scan': True, 'process_complete': True}) - scan_releases.append(release_download) - else: - scan_required = True - - found = True - break - - if not found: - log.info('%s not found in downloaders', nzbname) - - #Check status if already missing and for how long, if > 1 week, set to ignored else to missing - if rel.status_id == missing_status.get('id'): - if rel.last_edit < int(time.time()) - 7 * 24 * 60 * 60: - fireEvent('release.update_status', rel.id, status = ignored_status, single = True) - else: - # Set the release to missing - fireEvent('release.update_status', rel.id, status = missing_status, single = True) - - except: - log.error('Failed checking for release in downloader: %s', traceback.format_exc()) + except: + log.error('Failed checking for release in downloader: %s', traceback.format_exc()) # The following can either be done here, or inside the scanner if we pass it scan_items in one go for release_download in scan_releases: @@ -948,7 +997,6 @@ Remove it if you want it to be renamed (again, or at least let it try again) fireEvent('renamer.scan') self.checking_snatched = False - return True def extendReleaseDownload(self, release_download): @@ -995,10 +1043,10 @@ Remove it if you want it to be renamed (again, or at least let it try again) def statusInfoComplete(self, release_download): return release_download['id'] and release_download['downloader'] and release_download['folder'] - def movieInFromFolder(self, movie_folder): - return movie_folder and sp(self.conf('from')) in sp(movie_folder) or not movie_folder + def movieInFromFolder(self, media_folder): + return media_folder and '%s%s' % (sp(self.conf('from')), os.path.sep) in sp(media_folder) or not media_folder - def extractFiles(self, folder = None, movie_folder = None, files = None, cleanup = False): + def extractFiles(self, folder = None, media_folder = None, files = None, cleanup = False): if not files: files = [] # RegEx for finding rar files @@ -1013,7 +1061,7 @@ Remove it if you want it to be renamed (again, or at least let it try again) folder = from_folder check_file_date = True - if movie_folder: + if media_folder: check_file_date = False if not files: @@ -1109,18 +1157,18 @@ Remove it if you want it to be renamed (again, or at least let it try again) if cleanup: # Remove all left over folders - log.debug('Removing old movie folder %s...', movie_folder) - self.deleteEmptyFolder(movie_folder) + log.debug('Removing old movie folder %s...', media_folder) + self.deleteEmptyFolder(media_folder) - movie_folder = os.path.join(from_folder, os.path.relpath(movie_folder, folder)) + media_folder = os.path.join(from_folder, os.path.relpath(media_folder, folder)) folder = from_folder if extr_files: files.extend(extr_files) - # Cleanup files and folder if movie_folder was not provided - if not movie_folder: + # Cleanup files and folder if media_folder was not provided + if not media_folder: files = [] folder = None - return folder, movie_folder, files, extr_files + return folder, media_folder, files, extr_files diff --git a/couchpotato/static/scripts/page/wanted.js b/couchpotato/static/scripts/page/wanted.js index 98a676c8..6a3d4cbc 100644 --- a/couchpotato/static/scripts/page/wanted.js +++ b/couchpotato/static/scripts/page/wanted.js @@ -4,6 +4,7 @@ Page.Wanted = new Class({ name: 'wanted', title: 'Gimmy gimmy gimmy!', + folder_browser: null, indexAction: function(){ var self = this; @@ -18,13 +19,22 @@ Page.Wanted = new Class({ } }); + + self.scan_folder = new Element('a', { + 'title': 'Scan a folder and rename all movies in it', + 'text': 'Manual folder scan', + 'events':{ + 'click': self.scanFolder.bind(self) + } + }); + // Wanted movies self.wanted = new MovieList({ 'identifier': 'wanted', 'status': 'active', 'actions': [MA.IMDB, MA.Trailer, MA.Release, MA.Edit, MA.Refresh, MA.Readd, MA.Delete], 'add_new': true, - 'menu': [self.manual_search], + 'menu': [self.manual_search, self.scan_folder], 'on_empty_element': App.createUserscriptButtons().addClass('empty_wanted') }); $(self.wanted).inject(self.el); @@ -69,6 +79,45 @@ Page.Wanted = new Class({ }); }, 1000); - } + }, -}); \ No newline at end of file + scanFolder: function(e) { + (e).stop(); + + var self = this; + var options = { + 'name': 'Scan_folder' + } + + if(!self.folder_browser){ + self.folder_browser = new Option['Directory']("Scan", "folder", "", options); + + self.folder_browser.save = function() { + var folder = self.folder_browser.getValue(); + Api.request('renamer.scan', { + 'data': { + 'base_folder': folder, + }, + }); + }; + + self.folder_browser.inject(self.el, 'top'); + self.folder_browser.fireEvent('injected'); + + // Hide the settings box + self.folder_browser.directory_inlay.hide(); + self.folder_browser.el.removeChild(self.folder_browser.el.firstChild); + + self.folder_browser.showBrowser(); + + // Make adjustments to the browser + self.folder_browser.browser.getElements('.clear.button').hide(); + self.folder_browser.save_button.text = "Select"; + self.folder_browser.browser.style.zIndex=1000; + } + else{ + self.folder_browser.showBrowser(); + } + } + +}); diff --git a/couchpotato/static/style/settings.css b/couchpotato/static/style/settings.css index 82e51357..38997b6b 100644 --- a/couchpotato/static/style/settings.css +++ b/couchpotato/static/style/settings.css @@ -113,6 +113,8 @@ width: 20px; } + .Scan_folder { padding: 0 !important; } + .page .ctrlHolder { line-height: 25px; padding: 10px 10px 10px 30px; @@ -159,7 +161,7 @@ } .page .xsmall { width: 20px !important; text-align: center; } - + .page .enabler { display: block; }