Merge branch 'develop_seed' of git://github.com/mano3m/CouchPotatoServer into mano3m-develop_seed

This commit is contained in:
Ruud committed 2013-07-07 11:37:53 +02:00
commit d3d3106fc9
30 files changed
+658 -205

No files matched your search

@@ -425,7 +425,9 @@
}
.movies .data .quality .available { background-color: #578bc3; }
.movies .data .quality .snatched { background-color: #369545; }
.movies .data .quality .failed { background-color: #a43d34; }
.movies .data .quality .snatched { background-color: #a2a232; }
.movies .data .quality .seeding { background-color: #0a6819; }
.movies .data .quality .done {
background-color: #369545;
opacity: 1;
+1 -1
View File
@@ -121,7 +121,7 @@ config = [{
'label': 'Torrent File Action',
'default': 'move',
'type': 'dropdown',
'values': [('Move', 'move'), ('Copy', 'copy'), ('Hard link', 'hardlink'), ('Sym link', 'symlink'), ('Move & Sym link', 'move_symlink')],
'values': [('Move', 'move'), ('Copy', 'copy'), ('Hard link', 'hardlink'), ('Move & Sym link', 'move_symlink')],
'description': 'Define which kind of file operation you want to use for torrents. Before you start using <a href="http://en.wikipedia.org/wiki/Hard_link">hard links</a> or <a href="http://en.wikipedia.org/wiki/Sym_link">sym links</a>, PLEASE read about their possible drawbacks.',
'advanced': True,
},
+132 -29
View File
@@ -10,6 +10,7 @@ from couchpotato.core.settings.model import Library, File, Profile, Release, \
ReleaseInfo
from couchpotato.environment import Env
import errno
import fnmatch
import os
import re
import shutil
@@ -38,7 +39,6 @@ class Renamer(Plugin):
addEvent('renamer.check_snatched', self.checkSnatched)
addEvent('app.load', self.scan)
addEvent('app.load', self.checkSnatched)
addEvent('app.load', self.setCrons)
# Enable / disable interval
@@ -65,18 +65,19 @@ class Renamer(Plugin):
downloader = kwargs.get('downloader', None)
download_id = kwargs.get('download_id', None)
download_info = {'folder': movie_folder} if movie_folder else None
if download_info:
download_info.update({'id': download_id, 'downloader': downloader} if download_id else {})
fire_handle = fireEvent if not async else fireEventAsync
fire_handle('renamer.scan',
movie_folder = movie_folder,
download_info = {'id': download_id, 'downloader': downloader} if download_id else None
)
fire_handle('renamer.scan', download_info)
return {
'success': True
}
def scan(self, movie_folder = None, download_info = None):
def scan(self, download_info = None):
if self.isDisabled():
return
@@ -85,6 +86,8 @@ class Renamer(Plugin):
log.info('Renamer is already running, if you see this often, check the logs above for errors.')
return
movie_folder = download_info and download_info.get('folder')
# Check to see if the "to" folder is inside the "from" folder.
if movie_folder and not os.path.isdir(movie_folder) or not os.path.isdir(self.conf('from')) or not os.path.isdir(self.conf('to')):
l = log.debug if movie_folder else log.error
@@ -97,6 +100,10 @@ class Renamer(Plugin):
log.error('The "to" and "from" folders can\'t be inside of or the same as the provided movie folder.')
return
# Make sure a checkSnatched marked all downloads/seeds as such
if not download_info and self.conf('run_every') > 0:
fireEvent('renamer.check_snatched')
self.renaming_started = True
# make sure the movie folder name is included in the search
@@ -144,7 +151,7 @@ class Renamer(Plugin):
# Add _UNKNOWN_ if no library item is connected
if not group['library'] or not movie_title:
self.tagDir(group, 'unknown')
self.tagDir(group['parentdir'], 'unknown')
continue
# Rename the files using the library data
else:
@@ -192,7 +199,7 @@ class Renamer(Plugin):
# Move nfo depending on settings
if file_type is 'nfo' and not self.conf('rename_nfo'):
log.debug('Skipping, renaming of %s disabled', file_type)
if self.conf('cleanup'):
if self.conf('cleanup') and not (self.conf('file_action') != 'move' and self.downloadIsTorrent(download_info)):
for current_file in group['files'][file_type]:
remove_files.append(current_file)
continue
@@ -354,7 +361,7 @@ class Renamer(Plugin):
log.info('Better quality release already exists for %s, with quality %s', (movie.library.titles[0].title, release.quality.label))
# Add exists tag to the .ignore file
self.tagDir(group, 'exists')
self.tagDir(group['parentdir'], 'exists')
# Notify on rename fail
download_message = 'Renaming of %s (%s) canceled, exists in %s already.' % (movie.library.titles[0].title, group['meta_data']['quality']['label'], release.quality.label)
@@ -405,7 +412,7 @@ class Renamer(Plugin):
except:
log.error('Failed removing %s: %s', (src, traceback.format_exc()))
self.tagDir(group, 'failed_remove')
self.tagDir(group['parentdir'], 'failed_remove')
# Delete leftover folder from older releases
for delete_folder in delete_folders:
@@ -425,14 +432,16 @@ class Renamer(Plugin):
self.makeDir(os.path.dirname(dst))
try:
self.moveFile(src, dst, forcemove = not self.downloadIsTorrent(download_info))
self.moveFile(src, dst, forcemove = not self.downloadIsTorrent(download_info) or self.fileIsAdded(src, group))
group['renamed_files'].append(dst)
except:
log.error('Failed moving the file "%s" : %s', (os.path.basename(src), traceback.format_exc()))
self.tagDir(group, 'failed_rename')
self.tagDir(group['parentdir'], 'failed_rename')
if self.conf('file_action') != 'move' and self.downloadIsTorrent(download_info):
self.tagDir(group, 'renamed already')
# Tag folder if it is in the 'from' folder and it will not be removed because it is a torrent
if (movie_folder and self.conf('from') in movie_folder or not movie_folder) and \
self.conf('file_action') != 'move' and self.downloadIsTorrent(download_info):
self.tagDir(group['parentdir'], 'renamed_already')
# Remove matching releases
for release in remove_releases:
@@ -480,12 +489,9 @@ class Renamer(Plugin):
return rename_files
# This adds a file to ignore / tag a release so it is ignored later
def tagDir(self, group, tag):
ignore_file = None
for movie_file in sorted(list(group['files']['movie'])):
ignore_file = '%s.ignore' % os.path.splitext(movie_file)[0]
break
def tagDir(self, folder, tag):
if not os.path.isdir(folder) or not tag:
return
text = """This file is from CouchPotato
It has marked this release as "%s"
@@ -493,9 +499,27 @@ This file hides the release from the renamer
Remove it if you want it to be renamed (again, or at least let it try again)
""" % tag
if ignore_file:
self.createFile(ignore_file, text)
self.createFile(os.path.join(folder, '%s.ignore' % tag), text)
def untagDir(self, folder, tag = None):
if not os.path.isdir(folder):
return
# Remove any .ignore files
for root, dirnames, filenames in os.walk(folder):
for filename in fnmatch.filter(filenames, '%s.ignore' % tag if tag else '*'):
os.remove((os.path.join(root, filename)))
def hastagDir(self, folder, tag = None):
if not os.path.isdir(folder):
return False
# Find any .ignore files
for root, dirnames, filenames in os.walk(folder):
if fnmatch.filter(filenames, '%s.ignore' % tag if tag else '*'):
return True
return False
def moveFile(self, old, dest, forcemove = False):
dest = ss(dest)
@@ -504,8 +528,6 @@ Remove it if you want it to be renamed (again, or at least let it try again)
shutil.move(old, dest)
elif self.conf('file_action') == 'hardlink':
link(old, dest)
elif self.conf('file_action') == 'symlink':
symlink(old, dest)
elif self.conf('file_action') == 'copy':
shutil.copy(old, dest)
elif self.conf('file_action') == 'move_symlink':
@@ -584,19 +606,21 @@ Remove it if you want it to be renamed (again, or at least let it try again)
if self.checking_snatched:
log.debug('Already checking snatched')
return False
self.checking_snatched = True
snatched_status, ignored_status, failed_status, done_status = \
fireEvent('status.get', ['snatched', 'ignored', 'failed', 'done'], single = True)
snatched_status, ignored_status, failed_status, done_status, seeding_status, downloaded_status = \
fireEvent('status.get', ['snatched', 'ignored', 'failed', 'done', 'seeding', 'downloaded'], single = True)
db = get_session()
rels = db.query(Release).filter_by(status_id = snatched_status.get('id')).all()
rels.extend(db.query(Release).filter_by(status_id = seeding_status.get('id')).all())
scan_items = []
scan_required = False
if rels:
self.checking_snatched = True
log.debug('Checking status snatched releases...')
statuses = fireEvent('download.status', merge = True)
@@ -612,7 +636,7 @@ Remove it if you want it to be renamed (again, or at least let it try again)
default_title = getTitle(rel.movie.library)
# Check if movie has already completed and is manage tab (legacy db correction)
if rel.movie.status_id == done_status.get('id'):
if rel.movie.status_id == done_status.get('id') and rel.status_id == snatched_status.get('id'):
log.debug('Found a completed movie with a snatched release : %s. Setting release status to ignored...' , default_title)
rel.status_id = ignored_status.get('id')
rel.last_edit = int(time.time())
@@ -640,7 +664,35 @@ Remove it if you want it to be renamed (again, or at least let it try again)
log.debug('Found %s: %s, time to go: %s', (item['name'], item['status'].upper(), timeleft))
if item['status'] == 'busy':
# Tag folder if it is in the 'from' folder and it will not be processed because it is still downloading
if item['folder'] and self.conf('from') in item['folder']:
self.tagDir(item['folder'], 'downloading')
pass
elif item['status'] == 'seeding':
#If linking setting is enabled, process release
if self.conf('file_action') != 'move' and not rel.movie.status_id == done_status.get('id') and item['id'] and item['downloader'] and item['folder']:
log.info('Download of %s completed! It is now being processed while leaving the original files alone for seeding. Current ratio: %s.', (item['name'], item['seed_ratio']))
# Remove the downloading tag
self.untagDir(item['folder'], 'downloading')
rel.status_id = seeding_status.get('id')
rel.last_edit = int(time.time())
db.commit()
# Scan and set the torrent to paused if required
item.update({'pause': True, 'scan': True, 'process_complete': False})
scan_items.append(item)
else:
if rel.status_id != seeding_status.get('id'):
rel.status_id = seeding_status.get('id')
rel.last_edit = int(time.time())
db.commit()
#let it seed
log.debug('%s is seeding with ratio: %s', (item['name'], item['seed_ratio']))
pass
elif item['status'] == 'failed':
fireEvent('download.remove_failed', item, single = True)
rel.status_id = failed_status.get('id')
@@ -652,7 +704,35 @@ Remove it if you want it to be renamed (again, or at least let it try again)
elif item['status'] == 'completed':
log.info('Download of %s completed!', item['name'])
if item['id'] and item['downloader'] and item['folder']:
fireEventAsync('renamer.scan', movie_folder = item['folder'], download_info = item)
# If the release has been seeding, process now the seeding is done
if rel.status_id == seeding_status.get('id'):
if rel.movie.status_id == done_status.get('id'): # and self.conf('file_action') != 'move':
# Set the release to done as the movie has already been renamed
rel.status_id = downloaded_status.get('id')
rel.last_edit = int(time.time())
db.commit()
# Allow the downloader to clean-up
item.update({'pause': False, 'scan': False, 'process_complete': True})
scan_items.append(item)
else:
# Set the release to snatched so that the renamer can process the release as if it was never seeding
rel.status_id = snatched_status.get('id')
rel.last_edit = int(time.time())
db.commit()
# Scan and Allow the downloader to clean-up
item.update({'pause': False, 'scan': True, 'process_complete': True})
scan_items.append(item)
else:
# Remove the downloading tag
self.untagDir(item['folder'], 'downloading')
# Scan and Allow the downloader to clean-up
item.update({'pause': False, 'scan': True, 'process_complete': True})
scan_items.append(item)
else:
scan_required = True
@@ -665,6 +745,23 @@ Remove it if you want it to be renamed (again, or at least let it try again)
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 item in scan_items:
# Ask the renamer to scan the item
if item['scan']:
if item['pause'] and self.conf('file_action') == 'move_symlink':
fireEvent('download.pause', item = item, pause = True, single = True)
fireEvent('renamer.scan', download_info = item)
if item['pause'] and self.conf('file_action') == 'move_symlink':
fireEvent('download.pause', item = item, pause = False, single = True)
if item['process_complete']:
#First make sure the files were succesfully processed
if not self.hastagDir(item['folder'], 'failed_rename'):
# Remove the seeding tag if it exists
self.untagDir(item['folder'], 'renamed_already')
# Ask the downloader to process the item
fireEvent('download.process_complete', item = item, single = True)
if scan_required:
fireEvent('renamer.scan')
@@ -706,3 +803,9 @@ Remove it if you want it to be renamed (again, or at least let it try again)
def downloadIsTorrent(self, download_info):
return download_info and download_info.get('type') in ['torrent', 'torrent_magnet']
def fileIsAdded(self, src, group):
if not group['files'].get('added'):
return False
return src in group['files']['added']
+8
View File
@@ -225,6 +225,10 @@ class Scanner(Plugin):
# Remove the found files from the leftover stack
leftovers = leftovers - set(found_files)
exts = [getExt(ff) for ff in found_files]
if 'ignore' in exts:
ignored_identifiers.append(identifier)
# Break if CP wants to shut down
if self.shuttingDown():
break
@@ -251,6 +255,10 @@ class Scanner(Plugin):
# Remove the found files from the leftover stack
leftovers = leftovers - set([ff])
ext = getExt(ff)
if ext == 'ignore':
ignored_identifiers.append(new_identifier)
# Break if CP wants to shut down
if self.shuttingDown():
break
+1
View File
@@ -23,6 +23,7 @@ class StatusPlugin(Plugin):
'ignored': 'Ignored',
'available': 'Available',
'suggest': 'Suggest',
'seeding': 'Seeding',
}
status_cached = {}
@@ -60,6 +60,7 @@ class Subtitle(Plugin):
for d_sub in downloaded:
log.info('Found subtitle (%s): %s', (d_sub.language.alpha2, files))
group['files']['subtitle'].append(d_sub.path)
group['files']['added'].append(d_sub.path)
group['subtitle_language'][d_sub.path] = [d_sub.language.alpha2]
return True