Merge branches 'develop' and 'tv' of https://github.com/RuudBurger/CouchPotatoServer into tv

Conflicts:
	couchpotato/core/plugins/release/main.py
	couchpotato/core/plugins/renamer/main.py
This commit is contained in:
Joel Kåberg committed 2013-12-19 20:57:12 +01:00
commit 0a996857dd
5 files changed
+361 -246

No files matched your search

@@ -103,15 +103,15 @@ class Transmission(Downloader):
for torrent in queue['torrents']: for torrent in queue['torrents']:
if torrent['hashString'] in ids: 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', 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['eta'], torrent['uploadRatio'], torrent['isFinished'])) (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 = [] torrent_files = []
for file_item in torrent['files']: for file_item in torrent['files']:
torrent_files.append(sp(os.path.join(torrent['downloadDir'], file_item['name']))) torrent_files.append(sp(os.path.join(torrent['downloadDir'], file_item['name'])))
status = 'busy' 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' status = 'failed'
elif torrent['status'] == 0 and torrent['percentDone'] == 1: elif torrent['status'] == 0 and torrent['percentDone'] == 1:
status = 'completed' status = 'completed'
+91 -75
View File
@@ -211,22 +211,25 @@ class Release(Plugin):
db = get_session() db = get_session()
rel = db.query(Relea).filter_by(id = id).first() rel = db.query(Relea).filter_by(id = id).first()
if rel: if not rel:
item = {} log.error('Couldn\'t find release with id: %s', id)
for info in rel.info: return {
item[info.identifier] = info.value '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 fireEvent('notify.frontend', type = 'release.manual_download', data = True, message = 'Snatching "%s"' % item['name'])
provider = fireEvent('provider.belongs_to', item['url'], provider = item.get('provider'), single = True)
if not item.get('protocol'): # Get matching provider
item['protocol'] = item['type'] provider = fireEvent('provider.belongs_to', item['url'], provider = item.get('provider'), single = True)
item['type'] = 'movie'
if item.get('protocol') != 'torrent_magnet': # Backwards compatibility code
item['download'] = provider.loginDownload if provider.urls.get('login') else provider.download if not item.get('protocol'):
item['protocol'] = item['type']
item['type'] = 'movie'
success = self.download(data = item, media = rel.media.to_dict({ success = self.download(data = item, media = rel.media.to_dict({
'profile': {'types': {'quality': {}}}, 'profile': {'types': {'quality': {}}},
@@ -234,96 +237,109 @@ class Release(Plugin):
'library': {'titles': {}, 'files':{}}, 'library': {'titles': {}, 'files':{}},
'files': {} 'files': {}
}), manual = True) }), manual = True)
if item.get('protocol') != 'torrent_magnet':
item['download'] = provider.loginDownload if provider.urls.get('login') else provider.download
if success: success = self.download(data = item, media = rel.movie.to_dict({
db.expunge_all() 'profile': {'types': {'quality': {}}},
rel = db.query(Relea).filter_by(id = id).first() # Get release again @RuudBurger why do we need to get it again?? 'releases': {'status': {}, 'quality': {}},
'library': {'titles': {}, 'files':{}},
'files': {}
}), manual = True)
fireEvent('notify.frontend', type = 'release.manual_download', data = True, message = 'Successfully snatched "%s"' % item['name']) if success:
return { db.expunge_all()
'success': success rel = db.query(Relea).filter_by(id = id).first() # Get release again @RuudBurger why do we need to get it again??
}
else:
log.error('Couldn\'t find release with id: %s', id)
fireEvent('notify.frontend', type = 'release.manual_download', data = True, message = 'Successfully snatched "%s"' % item['name'])
return { return {
'success': False 'success': success
} }
def download(self, data, media, manual = False): def download(self, data, media, manual = False):
# Backwards compatibility code
if not data.get('protocol'): if not data.get('protocol'):
data['protocol'] = data['type'] data['protocol'] = data['type']
data['type'] = 'movie' data['type'] = 'movie'
# Test to see if any downloaders are enabled for this type # Test to see if any downloaders are enabled for this type
downloader_enabled = fireEvent('download.enabled', manual, data, single = True) 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: # Download NZB or torrent file
snatched_status, done_status, active_status = fireEvent('status.get', ['snatched', 'done', 'active'], single = True) 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 # Send NZB or torrent file to downloader
filedata = None download_result = fireEvent('download', data = data, media = media, manual = manual, filedata = filedata, single = True)
if data.get('download') and (ismethod(data.get('download')) or isfunction(data.get('download'))): if not download_result:
filedata = data.get('download')(url = data.get('url'), nzb_id = data.get('id')) log.info('Tried to download, but the "%s" downloader gave an error', (data.get('protocol')))
if filedata == 'try_next': return False
return filedata log.debug('Downloader result: %s', download_result)
download_result = fireEvent('download', data = data, media = media, manual = manual, filedata = filedata, single = True) snatched_status, done_status, downloaded_status, active_status = fireEvent('status.get', ['snatched', 'done', 'downloaded', 'active'], single = True)
log.debug('Downloader result: %s', download_result)
if download_result: try:
try: db = get_session()
# Mark release as snatched rls = db.query(Relea).filter_by(identifier = md5(data['url'])).first()
db = get_session() if not rls:
rls = db.query(Relea).filter_by(identifier = md5(data['url'])).first() log.error('No release found to store download information in')
if rls: return False
renamer_enabled = Env.setting('enabled', 'renamer')
# Save download-id info if returned renamer_enabled = Env.setting('enabled', 'renamer')
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()
log_movie = '%s (%s) in %s' % (getTitle(media['library']), media['library']['year'], rls.quality.label) # Save download-id info if returned
snatch_message = 'Snatched "%s": %s' % (data.get('name'), log_movie) if isinstance(download_result, dict):
log.info(snatch_message) for key in download_result:
fireEvent('%s.snatched' % data['type'], message = snatch_message, data = rls.to_dict()) 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 log_movie = '%s (%s) in %s' % (getTitle(media['library']), media['library']['year'], rls.quality.label)
if not renamer_enabled: snatch_message = 'Snatched "%s": %s' % (data.get('name'), log_movie)
try: log.info(snatch_message)
if media['status_id'] == active_status.get('id'): fireEvent('%s.snatched' % data['type'], message = snatch_message, data = rls.to_dict())
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)
# Mark release done # Mark release as snatched
self.updateStatus(rls.id, status = done_status) if renamer_enabled:
self.updateStatus(rls.id, status = snatched_status)
# Mark media done # If renamer isn't used, mark media done if finished or release downloaded
mdia = db.query(Media).filter_by(id = media['id']).first() else:
mdia.status_id = done_status.get('id') if media['status_id'] == active_status.get('id'):
mdia.last_edit = int(time.time()) finished = next((True for profile_type in media['profile']['types'] if \
db.commit() profile_type['quality_id'] == rls.quality.id and profile_type['finish']), False)
except: if finished:
log.error('Failed marking media finished, renamer disabled: %s', traceback.format_exc()) log.info('Renamer disabled, marking media as finished: %s', log_movie)
else:
self.updateStatus(rls.id, status = snatched_status)
except: # Mark release done
log.error('Failed marking media finished: %s', traceback.format_exc()) 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): def tryDownloadResult(self, results, media, quality_type, manual = False):
ignored_status, failed_status = fireEvent('status.get', ['ignored', 'failed'], single = True) ignored_status, failed_status = fireEvent('status.get', ['ignored', 'failed'], single = True)
+212 -164
View File
@@ -30,10 +30,11 @@ class Renamer(Plugin):
'desc': 'For the renamer to check for new files to rename in a folder', 'desc': 'For the renamer to check for new files to rename in a folder',
'params': { 'params': {
'async': {'desc': 'Optional: Set to 1 if you dont want to fire the renamer.scan asynchronous.'}, '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.'}, '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 movie_folder, delimited with a \'|\'. Note that no dedicated release folder is expected for releases with one file.'}, '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.'}, '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\''}, 'status': {'desc': 'Optional: The status of the release: \'completed\' (default) or \'seeding\''},
}, },
}) })
@@ -64,25 +65,32 @@ class Renamer(Plugin):
def scanView(self, **kwargs): def scanView(self, **kwargs):
async = tryInt(kwargs.get('async', 0)) 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') downloader = kwargs.get('downloader')
download_id = kwargs.get('download_id') download_id = kwargs.get('download_id')
files = '|'.join([sp(filename) for filename in splitString(kwargs.get('files'), '|')]) files = '|'.join([sp(filename) for filename in splitString(kwargs.get('files'), '|')])
status = kwargs.get('status', 'completed') status = kwargs.get('status', 'completed')
release_download = {'folder': movie_folder} if movie_folder else None release_download = None
if release_download: 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 {}) 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 = 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 { return {
'success': True 'success': True
} }
def scan(self, release_download = None): def scan(self, base_folder = None, release_download = None):
if not release_download: release_download = {} if not release_download: release_download = {}
if self.isDisabled(): 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.') log.info('Renamer is already running, if you see this often, check the logs above for errors.')
return return
if not base_folder:
base_folder = self.conf('from')
from_folder = sp(self.conf('from')) from_folder = sp(self.conf('from'))
to_folder = sp(self.conf('to')) to_folder = sp(self.conf('to'))
# Get movie folder to process # Get media folder to process
movie_folder = release_download.get('folder') media_folder = release_download.get('folder')
# Get all folders that should not be processed # Get all folders that should not be processed
no_process = [to_folder] no_process = [to_folder]
@@ -109,45 +120,45 @@ class Renamer(Plugin):
pass pass
# Check to see if the no_process folders are inside the "from" folder. # 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): if not os.path.isdir(base_folder) or not os.path.isdir(to_folder):
log.error('Both the "To" and "From" have to exist.') log.error('Both the "To" and "From" folder have to exist.')
return return
else: else:
for item in no_process: for item in no_process:
if '%s%s' % (from_folder, os.path.sep) in item: if '%s%s' % (base_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.') log.error('To protect your data, the media libraries can\'t be inside of or the same as the "from" folder.')
return return
# Check to see if the no_process folders are inside the provided movie_folder # Check to see if the no_process folders are inside the provided media_folder
if movie_folder and not os.path.isdir(movie_folder): if media_folder and not os.path.isdir(media_folder):
log.debug('The provided movie folder %s does not exist. Trying to find it in the \'from\' folder.', movie_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 # Update to the from folder
if len(splitString(release_download.get('files'), '|')) == 1: if len(splitString(release_download.get('files'), '|')) == 1:
new_movie_folder = from_folder new_media_folder = from_folder
else: 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): if not os.path.isdir(new_media_folder):
log.error('The provided movie folder %s does not exist and could also not be found in the \'from\' folder.', movie_folder) log.error('The provided media folder %s does not exist and could also not be found in the \'from\' folder.', media_folder)
return return
# Update the files # 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]): 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 return
# Update release_download info to the from folder # Update release_download info to the from folder
log.debug('Release %s found in the \'from\' folder.', movie_folder) log.debug('Release %s found in the \'from\' folder.', media_folder)
release_download['folder'] = new_movie_folder release_download['folder'] = new_media_folder
release_download['files'] = '|'.join(new_files) 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: for item in no_process:
if '%s%s' % (movie_folder, os.path.sep) in item: if '%s%s' % (media_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.') log.error('To protect your data, the media libraries can\'t be inside of or the same as the provided media folder.')
return return
# Make sure a checkSnatched marked all downloads/seeds as such # Make sure a checkSnatched marked all downloads/seeds as such
@@ -156,26 +167,26 @@ class Renamer(Plugin):
self.renaming_started = True 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 folder = None
files = [] files = []
if movie_folder: if media_folder:
log.info('Scanning movie folder %s...', movie_folder) log.info('Scanning media folder %s...', media_folder)
folder = os.path.dirname(movie_folder) folder = os.path.dirname(media_folder)
if release_download.get('files', ''): if release_download.get('files', ''):
files = splitString(release_download['files'], '|') files = splitString(release_download['files'], '|')
# If there is only one file in the torrent, the downloader did not create a subfolder # If there is only one file in the torrent, the downloader did not create a subfolder
if len(files) == 1: if len(files) == 1:
folder = movie_folder folder = media_folder
else: else:
# Get all files from the specified folder # Get all files from the specified folder
try: 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]) files.extend([sp(os.path.join(root, name)) for name in names])
except: 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() db = get_session()
@@ -185,10 +196,10 @@ class Renamer(Plugin):
# Unpack any archives # Unpack any archives
extr_files = None extr_files = None
if self.conf('unrar'): 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)) 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 [] files = files, release_download = release_download, return_ignored = False, single = True) or []
folder_name = self.conf('folder_name') folder_name = self.conf('folder_name')
@@ -229,7 +240,7 @@ class Renamer(Plugin):
# Overwrite destination when set in category # Overwrite destination when set in category
destination = to_folder destination = to_folder
category_label = '' category_label = ''
for movie in library_ent.media: for movie in library_ent.movies:
if movie.category and movie.category.label: if movie.category and movie.category.label:
category_label = movie.category.label category_label = movie.category.label
@@ -403,13 +414,13 @@ class Renamer(Plugin):
remove_leftovers = True remove_leftovers = True
# Add it to the wanted list before we continue # 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() 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) fireEvent('movie.add', params = {'identifier': group['library']['identifier'], 'profile_id': profile.id}, search_after = False)
db.expire_all() db.expire_all()
library_ent = db.query(Library).filter_by(identifier = group['library']['identifier']).first() 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 # Mark movie "done" once it's found the quality with the finish check
try: try:
@@ -497,7 +508,7 @@ class Renamer(Plugin):
os.remove(src) os.remove(src)
parent_dir = os.path.dirname(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) delete_folders.append(parent_dir)
except: except:
@@ -529,7 +540,7 @@ class Renamer(Plugin):
self.tagRelease(group = group, tag = 'failed_rename') 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 # 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') self.tagRelease(group = group, tag = 'renamed_already')
# Remove matching releases # Remove matching releases
@@ -541,12 +552,12 @@ class Renamer(Plugin):
log.error('Failed removing %s: %s', (release.identifier, traceback.format_exc())) log.error('Failed removing %s: %s', (release.identifier, traceback.format_exc()))
if group['dirname'] and group['parentdir'] and not self.downloadIsTorrent(release_download): if group['dirname'] and group['parentdir'] and not self.downloadIsTorrent(release_download):
if movie_folder: if media_folder:
# Delete the movie folder # Delete the movie folder
group_folder = movie_folder group_folder = media_folder
else: else:
# Delete the first empty subfolder in the tree relative to the 'from' folder # 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: try:
log.info('Deleting folder: %s', group_folder) 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]) tag_files.extend([os.path.join(root, name) for name in names])
for filename in tag_files: 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) tag_filename = '%s.%s.ignore' % (os.path.splitext(filename)[0], tag)
if not os.path.isfile(tag_filename): if not os.path.isfile(tag_filename):
self.createFile(tag_filename, text) 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')]) Release.status_id.in_([snatched_status.get('id'), seeding_status.get('id'), missing_status.get('id')])
).all() ).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_releases = []
scan_required = False scan_required = False
if rels: log.debug('Checking status snatched releases...')
log.debug('Checking status snatched releases...')
release_downloads = fireEvent('download.status', merge = True) try:
if not release_downloads: for rel in rels:
log.debug('Download status functionality is not implemented for active downloaders.') rel_dict = rel.to_dict({'info': {}})
scan_required = True movie_dict = fireEvent('media.get', media_id = rel.movie_id, single = 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)
if not isinstance(rel_dict['info'], (dict)): if not isinstance(rel_dict['info'], (dict)):
log.error('Faulty release found without any info, ignoring.') 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) 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 # Continue with next release
nzbname = self.createNzbName(rel_dict['info'], movie_dict) continue
found = False # Log that we found the release
for release_download in release_downloads: timeleft = 'N/A' if release_download['timeleft'] == -1 else release_download['timeleft']
found_release = False log.debug('Found %s: %s, time to go: %s', (release_download['name'], release_download['status'].upper(), timeleft))
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']: # Check status of release
log.debug('Found release by id: %s', release_download['id']) if release_download['status'] == 'busy':
found_release = True # 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: else:
if release_download['name'] == nzbname or rel_dict['info']['name'] in release_download['name'] or getImdb(release_download['name']) == movie_dict['library']['identifier']: # Scan and Allow the downloader to clean-up
found_release = True release_download.update({'pause': False, 'scan': True, 'process_complete': True})
scan_releases.append(release_download)
if found_release: else:
timeleft = 'N/A' if release_download['timeleft'] == -1 else release_download['timeleft'] # Set the release to snatched if it was missing before
log.debug('Found %s: %s, time to go: %s', (release_download['name'], release_download['status'].upper(), timeleft)) fireEvent('release.update_status', rel.id, status = snatched_status, single = True)
if release_download['status'] == 'busy': # Remove the downloading tag
# Set the release to snatched if it was missing before self.untagRelease(release_download = release_download, tag = 'downloading')
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 # Scan and Allow the downloader to clean-up
if self.movieInFromFolder(release_download['folder']): release_download.update({'pause': False, 'scan': True, 'process_complete': True})
self.tagRelease(release_download = release_download, tag = 'downloading') scan_releases.append(release_download)
else:
scan_required = True
elif release_download['status'] == 'seeding': except:
#If linking setting is enabled, process release log.error('Failed checking for release in downloader: %s', traceback.format_exc())
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())
# The following can either be done here, or inside the scanner if we pass it scan_items in one go # 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: 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') fireEvent('renamer.scan')
self.checking_snatched = False self.checking_snatched = False
return True return True
def extendReleaseDownload(self, release_download): 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): def statusInfoComplete(self, release_download):
return release_download['id'] and release_download['downloader'] and release_download['folder'] return release_download['id'] and release_download['downloader'] and release_download['folder']
def movieInFromFolder(self, movie_folder): def movieInFromFolder(self, media_folder):
return movie_folder and sp(self.conf('from')) in sp(movie_folder) or not movie_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 = [] if not files: files = []
# RegEx for finding rar 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 folder = from_folder
check_file_date = True check_file_date = True
if movie_folder: if media_folder:
check_file_date = False check_file_date = False
if not files: 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: if cleanup:
# Remove all left over folders # Remove all left over folders
log.debug('Removing old movie folder %s...', movie_folder) log.debug('Removing old movie folder %s...', media_folder)
self.deleteEmptyFolder(movie_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 folder = from_folder
if extr_files: if extr_files:
files.extend(extr_files) files.extend(extr_files)
# Cleanup files and folder if movie_folder was not provided # Cleanup files and folder if media_folder was not provided
if not movie_folder: if not media_folder:
files = [] files = []
folder = None folder = None
return folder, movie_folder, files, extr_files return folder, media_folder, files, extr_files
+52 -3
View File
@@ -4,6 +4,7 @@ Page.Wanted = new Class({
name: 'wanted', name: 'wanted',
title: 'Gimmy gimmy gimmy!', title: 'Gimmy gimmy gimmy!',
folder_browser: null,
indexAction: function(){ indexAction: function(){
var self = this; 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 // Wanted movies
self.wanted = new MovieList({ self.wanted = new MovieList({
'identifier': 'wanted', 'identifier': 'wanted',
'status': 'active', 'status': 'active',
'actions': [MA.IMDB, MA.Trailer, MA.Release, MA.Edit, MA.Refresh, MA.Readd, MA.Delete], 'actions': [MA.IMDB, MA.Trailer, MA.Release, MA.Edit, MA.Refresh, MA.Readd, MA.Delete],
'add_new': true, 'add_new': true,
'menu': [self.manual_search], 'menu': [self.manual_search, self.scan_folder],
'on_empty_element': App.createUserscriptButtons().addClass('empty_wanted') 'on_empty_element': App.createUserscriptButtons().addClass('empty_wanted')
}); });
$(self.wanted).inject(self.el); $(self.wanted).inject(self.el);
@@ -69,6 +79,45 @@ Page.Wanted = new Class({
}); });
}, 1000); }, 1000);
} },
}); 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();
}
}
});
+3 -1
View File
@@ -113,6 +113,8 @@
width: 20px; width: 20px;
} }
.Scan_folder { padding: 0 !important; }
.page .ctrlHolder { .page .ctrlHolder {
line-height: 25px; line-height: 25px;
padding: 10px 10px 10px 30px; padding: 10px 10px 10px 30px;
@@ -159,7 +161,7 @@
} }
.page .xsmall { width: 20px !important; text-align: center; } .page .xsmall { width: 20px !important; text-align: center; }
.page .enabler { .page .enabler {
display: block; display: block;
} }