Browse Source

Cleanup variable naming

Use release_download variable for all item/status/download_info
variables (which are by now all the same thing)
pull/2269/head
mano3m 12 years ago
parent
commit
bc877df513
  1. 34
      couchpotato/core/downloaders/base.py
  2. 62
      couchpotato/core/downloaders/deluge/main.py
  3. 60
      couchpotato/core/downloaders/nzbget/main.py
  4. 30
      couchpotato/core/downloaders/nzbvortex/main.py
  5. 48
      couchpotato/core/downloaders/rtorrent/main.py
  6. 50
      couchpotato/core/downloaders/sabnzbd/main.py
  7. 53
      couchpotato/core/downloaders/transmission/main.py
  8. 66
      couchpotato/core/downloaders/utorrent/main.py
  9. 140
      couchpotato/core/plugins/renamer/main.py

34
couchpotato/core/downloaders/base.py

@ -66,36 +66,36 @@ class Downloader(Provider):
def getAllDownloadStatus(self):
return
def _removeFailed(self, item):
def _removeFailed(self, release_download):
if self.isDisabled(manual = True, data = {}):
return
if item and item.get('downloader') == self.getName():
if release_download and release_download.get('downloader') == self.getName():
if self.conf('delete_failed'):
return self.removeFailed(item)
return self.removeFailed(release_download)
return False
return
def removeFailed(self, item):
def removeFailed(self, release_download):
return
def _processComplete(self, item):
def _processComplete(self, release_download):
if self.isDisabled(manual = True, data = {}):
return
if item and item.get('downloader') == self.getName():
if release_download and release_download.get('downloader') == self.getName():
if self.conf('remove_complete', default = False):
return self.processComplete(item = item, delete_files = self.conf('delete_files', default = False))
return self.processComplete(release_download = release_download, delete_files = self.conf('delete_files', default = False))
return False
return
def processComplete(self, item, delete_files):
def processComplete(self, release_download, delete_files):
return
def isCorrectProtocol(self, item_protocol):
is_correct = item_protocol in self.protocol
def isCorrectProtocol(self, protocol):
is_correct = protocol in self.protocol
if not is_correct:
log.debug("Downloader doesn't support this protocol")
@ -151,20 +151,20 @@ class Downloader(Provider):
(d_manual and manual or d_manual is False) and \
(not data or self.isCorrectProtocol(data.get('protocol')))
def _pause(self, item, pause = True):
def _pause(self, release_download, pause = True):
if self.isDisabled(manual = True, data = {}):
return
if item and item.get('downloader') == self.getName():
self.pause(item, pause)
if release_download and release_download.get('downloader') == self.getName():
self.pause(release_download, pause)
return True
return False
def pause(self, item, pause):
def pause(self, release_download, pause):
return
class StatusList(list):
class ReleaseDownloadList(list):
provider = None
@ -173,7 +173,7 @@ class StatusList(list):
self.provider = provider
self.kwargs = kwargs
super(StatusList, self).__init__()
super(ReleaseDownloadList, self).__init__()
def extend(self, results):
for r in results:
@ -181,7 +181,7 @@ class StatusList(list):
def append(self, result):
new_result = self.fillResult(result)
super(StatusList, self).append(new_result)
super(ReleaseDownloadList, self).append(new_result)
def fillResult(self, result):

62
couchpotato/core/downloaders/deluge/main.py

@ -1,5 +1,5 @@
from base64 import b64encode
from couchpotato.core.downloaders.base import Downloader, StatusList
from couchpotato.core.downloaders.base import Downloader, ReleaseDownloadList
from couchpotato.core.helpers.encoding import isInt, ss
from couchpotato.core.helpers.variable import tryFloat
from couchpotato.core.logger import CPLog
@ -85,14 +85,10 @@ class Deluge(Downloader):
log.debug('Checking Deluge download status.')
if not os.path.isdir(Env.setting('from', 'renamer')):
log.error('Renamer "from" folder doesn\'t to exist.')
return
if not self.connect():
return False
statuses = StatusList(self)
release_downloads = ReleaseDownloadList(self)
queue = self.drpc.get_alltorrents()
@ -101,55 +97,55 @@ class Deluge(Downloader):
return False
for torrent_id in queue:
item = queue[torrent_id]
log.debug('name=%s / id=%s / save_path=%s / move_completed_path=%s / hash=%s / progress=%s / state=%s / eta=%s / ratio=%s / stop_ratio=%s / is_seed=%s / is_finished=%s / paused=%s', (item['name'], item['hash'], item['save_path'], item['move_completed_path'], item['hash'], item['progress'], item['state'], item['eta'], item['ratio'], item['stop_ratio'], item['is_seed'], item['is_finished'], item['paused']))
torrent = queue[torrent_id]
log.debug('name=%s / id=%s / save_path=%s / move_completed_path=%s / hash=%s / progress=%s / state=%s / eta=%s / ratio=%s / stop_ratio=%s / is_seed=%s / is_finished=%s / paused=%s', (torrent['name'], torrent['hash'], torrent['save_path'], torrent['move_completed_path'], torrent['hash'], torrent['progress'], torrent['state'], torrent['eta'], torrent['ratio'], torrent['stop_ratio'], torrent['is_seed'], torrent['is_finished'], torrent['paused']))
# Deluge has no easy way to work out if a torrent is stalled or failing.
#status = 'failed'
status = 'busy'
if item['is_seed'] and tryFloat(item['ratio']) < tryFloat(item['stop_ratio']):
# We have item['seeding_time'] to work out what the seeding time is, but we do not
if torrent['is_seed'] and tryFloat(torrent['ratio']) < tryFloat(torrent['stop_ratio']):
# We have torrent['seeding_time'] to work out what the seeding time is, but we do not
# have access to the downloader seed_time, as with deluge we have no way to pass it
# when the torrent is added. So Deluge will only look at the ratio.
# See above comment in download().
status = 'seeding'
elif item['is_seed'] and item['is_finished'] and item['paused'] and item['state'] == 'Paused':
elif torrent['is_seed'] and torrent['is_finished'] and torrent['paused'] and torrent['state'] == 'Paused':
status = 'completed'
download_dir = item['save_path']
if item['move_on_completed']:
download_dir = item['move_completed_path']
download_dir = torrent['save_path']
if torrent['move_on_completed']:
download_dir = torrent['move_completed_path']
torrent_files = []
for file_item in item['files']:
torrent_files.append(os.path.join(download_dir, file_item['path']))
for file_item in torrent['files']:
torrent_files.append(os.path.join(download_dir, file_item['path']))
statuses.append({
'id': item['hash'],
'name': item['name'],
release_downloads.append({
'id': torrent['hash'],
'name': torrent['name'],
'status': status,
'original_status': item['state'],
'seed_ratio': item['ratio'],
'timeleft': str(timedelta(seconds = item['eta'])),
'folder': ss(download_dir) if len(torrent_files) == 1 else ss(os.path.join(download_dir, item['name'])),
'original_status': torrent['state'],
'seed_ratio': torrent['ratio'],
'timeleft': str(timedelta(seconds = torrent['eta'])),
'folder': ss(download_dir) if len(torrent_files) == 1 else ss(os.path.join(download_dir, torrent['name'])),
'files': ss('|'.join(torrent_files)),
})
return statuses
return release_downloads
def pause(self, item, pause = True):
def pause(self, release_download, pause = True):
if pause:
return self.drpc.pause_torrent([item['id']])
return self.drpc.pause_torrent([release_download['id']])
else:
return self.drpc.resume_torrent([item['id']])
return self.drpc.resume_torrent([release_download['id']])
def removeFailed(self, item):
log.info('%s failed downloading, deleting...', item['name'])
return self.drpc.remove_torrent(item['id'], True)
def removeFailed(self, release_download):
log.info('%s failed downloading, deleting...', release_download['name'])
return self.drpc.remove_torrent(release_download['id'], True)
def processComplete(self, item, delete_files = False):
log.debug('Requesting Deluge to remove the torrent %s%s.', (item['name'], ' and cleanup the downloaded files' if delete_files else ''))
return self.drpc.remove_torrent(item['id'], remove_local_data = delete_files)
def processComplete(self, release_download, delete_files = False):
log.debug('Requesting Deluge to remove the torrent %s%s.', (release_download['name'], ' and cleanup the downloaded files' if delete_files else ''))
return self.drpc.remove_torrent(release_download['id'], remove_local_data = delete_files)
class DelugeRPC(object):

60
couchpotato/core/downloaders/nzbget/main.py

@ -1,5 +1,5 @@
from base64 import standard_b64encode
from couchpotato.core.downloaders.base import Downloader, StatusList
from couchpotato.core.downloaders.base import Downloader, ReleaseDownloadList
from couchpotato.core.helpers.encoding import ss
from couchpotato.core.helpers.variable import tryInt, md5
from couchpotato.core.logger import CPLog
@ -99,60 +99,60 @@ class NZBGet(Downloader):
log.error('Failed getting data: %s', traceback.format_exc(1))
return False
statuses = StatusList(self)
release_downloads = ReleaseDownloadList(self)
for item in groups:
log.debug('Found %s in NZBGet download queue', item['NZBFilename'])
for nzb in groups:
log.debug('Found %s in NZBGet download queue', nzb['NZBFilename'])
try:
nzb_id = [param['Value'] for param in item['Parameters'] if param['Name'] == 'couchpotato'][0]
nzb_id = [param['Value'] for param in nzb['Parameters'] if param['Name'] == 'couchpotato'][0]
except:
nzb_id = item['NZBID']
nzb_id = nzb['NZBID']
timeleft = -1
try:
if item['ActiveDownloads'] > 0 and item['DownloadRate'] > 0 and not (status['DownloadPaused'] or status['Download2Paused']):
timeleft = str(timedelta(seconds = item['RemainingSizeMB'] / status['DownloadRate'] * 2 ^ 20))
if nzb['ActiveDownloads'] > 0 and nzb['DownloadRate'] > 0 and not (status['DownloadPaused'] or status['Download2Paused']):
timeleft = str(timedelta(seconds = nzb['RemainingSizeMB'] / status['DownloadRate'] * 2 ^ 20))
except:
pass
statuses.append({
release_downloads.append({
'id': nzb_id,
'name': item['NZBFilename'],
'original_status': 'DOWNLOADING' if item['ActiveDownloads'] > 0 else 'QUEUED',
'name': nzb['NZBFilename'],
'original_status': 'DOWNLOADING' if nzb['ActiveDownloads'] > 0 else 'QUEUED',
# Seems to have no native API function for time left. This will return the time left after NZBGet started downloading this item
'timeleft': timeleft,
})
for item in queue: # 'Parameters' is not passed in rpc.postqueue
log.debug('Found %s in NZBGet postprocessing queue', item['NZBFilename'])
statuses.append({
'id': item['NZBID'],
'name': item['NZBFilename'],
'original_status': item['Stage'],
for nzb in queue: # 'Parameters' is not passed in rpc.postqueue
log.debug('Found %s in NZBGet postprocessing queue', nzb['NZBFilename'])
release_downloads.append({
'id': nzb['NZBID'],
'name': nzb['NZBFilename'],
'original_status': nzb['Stage'],
'timeleft': str(timedelta(seconds = 0)) if not status['PostPaused'] else -1,
})
for item in history:
log.debug('Found %s in NZBGet history. ParStatus: %s, ScriptStatus: %s, Log: %s', (item['NZBFilename'] , item['ParStatus'], item['ScriptStatus'] , item['Log']))
for nzb in history:
log.debug('Found %s in NZBGet history. ParStatus: %s, ScriptStatus: %s, Log: %s', (nzb['NZBFilename'] , nzb['ParStatus'], nzb['ScriptStatus'] , nzb['Log']))
try:
nzb_id = [param['Value'] for param in item['Parameters'] if param['Name'] == 'couchpotato'][0]
nzb_id = [param['Value'] for param in nzb['Parameters'] if param['Name'] == 'couchpotato'][0]
except:
nzb_id = item['NZBID']
statuses.append({
nzb_id = nzb['NZBID']
release_downloads.append({
'id': nzb_id,
'name': item['NZBFilename'],
'status': 'completed' if item['ParStatus'] in ['SUCCESS','NONE'] and item['ScriptStatus'] in ['SUCCESS','NONE'] else 'failed',
'original_status': item['ParStatus'] + ', ' + item['ScriptStatus'],
'name': nzb['NZBFilename'],
'status': 'completed' if nzb['ParStatus'] in ['SUCCESS','NONE'] and nzb['ScriptStatus'] in ['SUCCESS','NONE'] else 'failed',
'original_status': nzb['ParStatus'] + ', ' + nzb['ScriptStatus'],
'timeleft': str(timedelta(seconds = 0)),
'folder': ss(item['DestDir'])
'folder': ss(nzb['DestDir'])
})
return statuses
return release_downloads
def removeFailed(self, item):
def removeFailed(self, release_download):
log.info('%s failed downloading, deleting...', item['name'])
log.info('%s failed downloading, deleting...', release_download['name'])
url = self.url % {'host': self.conf('host'), 'username': self.conf('username'), 'password': self.conf('password')}
@ -179,7 +179,7 @@ class NZBGet(Downloader):
for hist in history:
for param in hist['Parameters']:
if param['Name'] == 'couchpotato' and param['Value'] == item['id']:
if param['Name'] == 'couchpotato' and param['Value'] == release_download['id']:
nzb_id = hist['ID']
path = hist['DestDir']

30
couchpotato/core/downloaders/nzbvortex/main.py

@ -1,5 +1,5 @@
from base64 import b64encode
from couchpotato.core.downloaders.base import Downloader, StatusList
from couchpotato.core.downloaders.base import Downloader, ReleaseDownloadList
from couchpotato.core.helpers.encoding import tryUrlencode, ss
from couchpotato.core.helpers.variable import cleanHost
from couchpotato.core.logger import CPLog
@ -33,7 +33,7 @@ class NZBVortex(Downloader):
self.call('nzb/add', params = {'file': (ss(nzb_filename), filedata)}, multipart = True)
raw_statuses = self.call('nzb')
nzb_id = [item['id'] for item in raw_statuses.get('nzbs', []) if item['name'] == nzb_filename][0]
nzb_id = [nzb['id'] for nzb in raw_statuses.get('nzbs', []) if nzb['name'] == nzb_filename][0]
return self.downloadReturnId(nzb_id)
except:
log.error('Something went wrong sending the NZB file: %s', traceback.format_exc())
@ -43,33 +43,33 @@ class NZBVortex(Downloader):
raw_statuses = self.call('nzb')
statuses = StatusList(self)
for item in raw_statuses.get('nzbs', []):
release_downloads = ReleaseDownloadList(self)
for nzb in raw_statuses.get('nzbs', []):
# Check status
status = 'busy'
if item['state'] == 20:
if nzb['state'] == 20:
status = 'completed'
elif item['state'] in [21, 22, 24]:
elif nzb['state'] in [21, 22, 24]:
status = 'failed'
statuses.append({
'id': item['id'],
'name': item['uiTitle'],
release_downloads.append({
'id': nzb['id'],
'name': nzb['uiTitle'],
'status': status,
'original_status': item['state'],
'original_status': nzb['state'],
'timeleft':-1,
'folder': ss(item['destinationPath']),
'folder': ss(nzb['destinationPath']),
})
return statuses
return release_downloads
def removeFailed(self, item):
def removeFailed(self, release_download):
log.info('%s failed downloading, deleting...', item['name'])
log.info('%s failed downloading, deleting...', release_download['name'])
try:
self.call('nzb/%s/cancel' % item['id'])
self.call('nzb/%s/cancel' % release_download['id'])
except:
log.error('Failed deleting: %s', traceback.format_exc(0))
return False

48
couchpotato/core/downloaders/rtorrent/main.py

@ -1,6 +1,6 @@
from base64 import b16encode, b32decode
from bencode import bencode, bdecode
from couchpotato.core.downloaders.base import Downloader, StatusList
from couchpotato.core.downloaders.base import Downloader, ReleaseDownloadList
from couchpotato.core.helpers.encoding import ss
from couchpotato.core.logger import CPLog
from datetime import timedelta
@ -151,42 +151,42 @@ class rTorrent(Downloader):
try:
torrents = self.rt.get_torrents()
statuses = StatusList(self)
release_downloads = ReleaseDownloadList(self)
for item in torrents:
for torrent in torrents:
torrent_files = []
for file_item in item.get_files():
torrent_files.append(os.path.join(item.directory, file_item.path))
for file_item in torrent.get_files():
torrent_files.append(os.path.join(torrent.directory, file_item.path))
status = 'busy'
if item.complete:
if item.active:
if torrent.complete:
if torrent.active:
status = 'seeding'
else:
status = 'completed'
statuses.append({
'id': item.info_hash,
'name': item.name,
release_downloads.append({
'id': torrent.info_hash,
'name': torrent.name,
'status': status,
'seed_ratio': item.ratio,
'original_status': item.state,
'timeleft': str(timedelta(seconds = float(item.left_bytes) / item.down_rate)) if item.down_rate > 0 else -1,
'folder': ss(item.directory),
'seed_ratio': torrent.ratio,
'original_status': torrent.state,
'timeleft': str(timedelta(seconds = float(torrent.left_bytes) / torrent.down_rate)) if torrent.down_rate > 0 else -1,
'folder': ss(torrent.directory),
'files': ss('|'.join(torrent_files))
})
return statuses
return release_downloads
except Exception, err:
log.error('Failed to get status from rTorrent: %s', err)
return False
def pause(self, download_info, pause = True):
def pause(self, release_download, pause = True):
if not self.connect():
return False
torrent = self.rt.find_torrent(download_info['id'])
torrent = self.rt.find_torrent(release_download['id'])
if torrent is None:
return False
@ -194,23 +194,23 @@ class rTorrent(Downloader):
return torrent.pause()
return torrent.resume()
def removeFailed(self, item):
log.info('%s failed downloading, deleting...', item['name'])
return self.processComplete(item, delete_files = True)
def removeFailed(self, release_download):
log.info('%s failed downloading, deleting...', release_download['name'])
return self.processComplete(release_download, delete_files = True)
def processComplete(self, item, delete_files):
def processComplete(self, release_download, delete_files):
log.debug('Requesting rTorrent to remove the torrent %s%s.',
(item['name'], ' and cleanup the downloaded files' if delete_files else ''))
(release_download['name'], ' and cleanup the downloaded files' if delete_files else ''))
if not self.connect():
return False
torrent = self.rt.find_torrent(item['id'])
torrent = self.rt.find_torrent(release_download['id'])
if torrent is None:
return False
torrent.erase() # just removes the torrent, doesn't delete data
if delete_files:
shutil.rmtree(item['folder'], True)
shutil.rmtree(release_download['folder'], True)
return True

50
couchpotato/core/downloaders/sabnzbd/main.py

@ -1,4 +1,4 @@
from couchpotato.core.downloaders.base import Downloader, StatusList
from couchpotato.core.downloaders.base import Downloader, ReleaseDownloadList
from couchpotato.core.helpers.encoding import tryUrlencode, ss
from couchpotato.core.helpers.variable import cleanHost, mergeDicts
from couchpotato.core.logger import CPLog
@ -86,58 +86,58 @@ class Sabnzbd(Downloader):
log.error('Failed getting history json: %s', traceback.format_exc(1))
return False
statuses = StatusList(self)
release_downloads = ReleaseDownloadList(self)
# Get busy releases
for item in queue.get('slots', []):
for nzb in queue.get('slots', []):
status = 'busy'
if 'ENCRYPTED / ' in item['filename']:
if 'ENCRYPTED / ' in nzb['filename']:
status = 'failed'
statuses.append({
'id': item['nzo_id'],
'name': item['filename'],
release_downloads.append({
'id': nzb['nzo_id'],
'name': nzb['filename'],
'status': status,
'original_status': item['status'],
'timeleft': item['timeleft'] if not queue['paused'] else -1,
'original_status': nzb['status'],
'timeleft': nzb['timeleft'] if not queue['paused'] else -1,
})
# Get old releases
for item in history.get('slots', []):
for nzb in history.get('slots', []):
status = 'busy'
if item['status'] == 'Failed' or (item['status'] == 'Completed' and item['fail_message'].strip()):
if nzb['status'] == 'Failed' or (nzb['status'] == 'Completed' and nzb['fail_message'].strip()):
status = 'failed'
elif item['status'] == 'Completed':
elif nzb['status'] == 'Completed':
status = 'completed'
statuses.append({
'id': item['nzo_id'],
'name': item['name'],
release_downloads.append({
'id': nzb['nzo_id'],
'name': nzb['name'],
'status': status,
'original_status': item['status'],
'original_status': nzb['status'],
'timeleft': str(timedelta(seconds = 0)),
'folder': ss(item['storage']),
'folder': ss(nzb['storage']),
})
return statuses
return release_downloads
def removeFailed(self, item):
def removeFailed(self, release_download):
log.info('%s failed downloading, deleting...', item['name'])
log.info('%s failed downloading, deleting...', release_download['name'])
try:
self.call({
'mode': 'queue',
'name': 'delete',
'del_files': '1',
'value': item['id']
'value': release_download['id']
}, use_json = False)
self.call({
'mode': 'history',
'name': 'delete',
'del_files': '1',
'value': item['id']
'value': release_download['id']
}, use_json = False)
except:
log.error('Failed deleting: %s', traceback.format_exc(0))
@ -145,15 +145,15 @@ class Sabnzbd(Downloader):
return True
def processComplete(self, item, delete_files = False):
log.debug('Requesting SabNZBd to remove the NZB %s.', item['name'])
def processComplete(self, release_download, delete_files = False):
log.debug('Requesting SabNZBd to remove the NZB %s.', release_download['name'])
try:
self.call({
'mode': 'history',
'name': 'delete',
'del_files': '0',
'value': item['id']
'value': release_download['id']
}, use_json = False)
except:
log.error('Failed removing: %s', traceback.format_exc(0))

53
couchpotato/core/downloaders/transmission/main.py

@ -1,9 +1,8 @@
from base64 import b64encode
from couchpotato.core.downloaders.base import Downloader, StatusList
from couchpotato.core.downloaders.base import Downloader, ReleaseDownloadList
from couchpotato.core.helpers.encoding import isInt, ss
from couchpotato.core.helpers.variable import tryInt, tryFloat
from couchpotato.core.logger import CPLog
from couchpotato.environment import Env
from datetime import timedelta
import httplib
import json
@ -89,7 +88,7 @@ class Transmission(Downloader):
if not self.connect():
return False
statuses = StatusList(self)
release_downloads = ReleaseDownloadList(self)
return_params = {
'fields': ['id', 'name', 'hashString', 'percentDone', 'status', 'eta', 'isStalled', 'isFinished', 'downloadDir', 'uploadRatio', 'secondsSeeding', 'seedIdleLimit', 'files']
@ -100,48 +99,48 @@ class Transmission(Downloader):
log.debug('Nothing in queue or error')
return False
for item in queue['torrents']:
for torrent in queue['torrents']:
log.debug('name=%s / id=%s / downloadDir=%s / hashString=%s / percentDone=%s / status=%s / eta=%s / uploadRatio=%s / isFinished=%s',
(item['name'], item['id'], item['downloadDir'], item['hashString'], item['percentDone'], item['status'], item['eta'], item['uploadRatio'], item['isFinished']))
(torrent['name'], torrent['id'], torrent['downloadDir'], torrent['hashString'], torrent['percentDone'], torrent['status'], torrent['eta'], torrent['uploadRatio'], torrent['isFinished']))
torrent_files = []
for file_item in item['files']:
torrent_files.append(os.path.join(item['downloadDir'], file_item['name']))
for file_item in torrent['files']:
torrent_files.append(os.path.join(torrent['downloadDir'], file_item['name']))
status = 'busy'
if item['isStalled'] and self.conf('stalled_as_failed'):
if torrent['isStalled'] and self.conf('stalled_as_failed'):
status = 'failed'
elif item['status'] == 0 and item['percentDone'] == 1:
elif torrent['status'] == 0 and torrent['percentDone'] == 1:
status = 'completed'
elif item['status'] in [5, 6]:
elif torrent['status'] in [5, 6]:
status = 'seeding'
statuses.append({
'id': item['hashString'],
'name': item['name'],
release_downloads.append({
'id': torrent['hashString'],
'name': torrent['name'],
'status': status,
'original_status': item['status'],
'seed_ratio': item['uploadRatio'],
'timeleft': str(timedelta(seconds = item['eta'])),
'folder': ss(item['downloadDir']) if len(torrent_files) == 1 else ss(os.path.join(item['downloadDir'], item['name'])),
'original_status': torrent['status'],
'seed_ratio': torrent['uploadRatio'],
'timeleft': str(timedelta(seconds = torrent['eta'])),
'folder': ss(torrent['downloadDir']) if len(torrent_files) == 1 else ss(os.path.join(torrent['downloadDir'], torrent['name'])),
'files': ss('|'.join(torrent_files))
})
return statuses
return release_downloads
def pause(self, item, pause = True):
def pause(self, release_download, pause = True):
if pause:
return self.trpc.stop_torrent(item['id'])
return self.trpc.stop_torrent(release_download['id'])
else:
return self.trpc.start_torrent(item['id'])
return self.trpc.start_torrent(release_download['id'])
def removeFailed(self, item):
log.info('%s failed downloading, deleting...', item['name'])
return self.trpc.remove_torrent(item['id'], True)
def removeFailed(self, release_download):
log.info('%s failed downloading, deleting...', release_download['name'])
return self.trpc.remove_torrent(release_download['id'], True)
def processComplete(self, item, delete_files = False):
log.debug('Requesting Transmission to remove the torrent %s%s.', (item['name'], ' and cleanup the downloaded files' if delete_files else ''))
return self.trpc.remove_torrent(item['id'], delete_files)
def processComplete(self, release_download, delete_files = False):
log.debug('Requesting Transmission to remove the torrent %s%s.', (release_download['name'], ' and cleanup the downloaded files' if delete_files else ''))
return self.trpc.remove_torrent(release_download['id'], delete_files)
class TransmissionRPC(object):

66
couchpotato/core/downloaders/utorrent/main.py

@ -1,6 +1,6 @@
from base64 import b16encode, b32decode
from bencode import bencode as benc, bdecode
from couchpotato.core.downloaders.base import Downloader, StatusList
from couchpotato.core.downloaders.base import Downloader, ReleaseDownloadList
from couchpotato.core.helpers.encoding import isInt, ss
from couchpotato.core.helpers.variable import tryInt, tryFloat
from couchpotato.core.logger import CPLog
@ -111,7 +111,7 @@ class uTorrent(Downloader):
if not self.connect():
return False
statuses = StatusList(self)
release_downloads = ReleaseDownloadList(self)
data = self.utorrent_api.get_status()
if not data:
@ -128,57 +128,57 @@ class uTorrent(Downloader):
return False
# Get torrents
for item in queue['torrents']:
for torrent in queue['torrents']:
#Get files of the torrent
torrent_files = []
try:
torrent_files = json.loads(self.utorrent_api.get_files(item[0]))
torrent_files = [os.path.join(item[26], torrent_file[0]) for torrent_file in torrent_files['files'][1]]
torrent_files = json.loads(self.utorrent_api.get_files(torrent[0]))
torrent_files = [os.path.join(torrent[26], torrent_file[0]) for torrent_file in torrent_files['files'][1]]
except:
log.debug('Failed getting files from torrent: %s', item[2])
log.debug('Failed getting files from torrent: %s', torrent[2])
# item[21] = Paused | Downloading | Seeding | Finished
# torrent[21] = Paused | Downloading | Seeding | Finished
status = 'busy'
if 'Finished' in item[21]:
if 'Finished' in torrent[21]:
status = 'completed'
self.removeReadOnly(torrent_files)
elif 'Seeding' in item[21]:
elif 'Seeding' in torrent[21]:
status = 'seeding'
self.removeReadOnly(torrent_files)
statuses.append({
'id': item[0],
'name': item[2],
release_downloads.append({
'id': torrent[0],
'name': torrent[2],
'status': status,
'seed_ratio': float(item[7]) / 1000,
'original_status': item[1],
'timeleft': str(timedelta(seconds = item[10])),
'folder': ss(item[26]),
'seed_ratio': float(torrent[7]) / 1000,
'original_status': torrent[1],
'timeleft': str(timedelta(seconds = torrent[10])),
'folder': ss(torrent[26]),
'files': ss('|'.join(torrent_files))
})
return statuses
return release_downloads
def pause(self, item, pause = True):
def pause(self, release_download, pause = True):
if not self.connect():
return False
return self.utorrent_api.pause_torrent(item['id'], pause)
return self.utorrent_api.pause_torrent(release_download['id'], pause)
def removeFailed(self, item):
log.info('%s failed downloading, deleting...', item['name'])
def removeFailed(self, release_download):
log.info('%s failed downloading, deleting...', release_download['name'])
if not self.connect():
return False
return self.utorrent_api.remove_torrent(item['id'], remove_data = True)
return self.utorrent_api.remove_torrent(release_download['id'], remove_data = True)
def processComplete(self, item, delete_files = False):
log.debug('Requesting uTorrent to remove the torrent %s%s.', (item['name'], ' and cleanup the downloaded files' if delete_files else ''))
def processComplete(self, release_download, delete_files = False):
log.debug('Requesting uTorrent to remove the torrent %s%s.', (release_download['name'], ' and cleanup the downloaded files' if delete_files else ''))
if not self.connect():
return False
return self.utorrent_api.remove_torrent(item['id'], remove_data = delete_files)
return self.utorrent_api.remove_torrent(release_download['id'], remove_data = delete_files)
def removeReadOnly(self, files):
#Removes all read-only flags in a for all files
#Removes all read-on ly flags in a for all files
for filepath in files:
if os.path.isfile(filepath):
#Windows only needs S_IWRITE, but we bitwise-or with current perms to preserve other permission bits on Linux
@ -280,13 +280,13 @@ class uTorrentAPI(object):
utorrent_settings = json.loads(self._request(action))
# Create settings dict
for item in utorrent_settings['settings']:
if item[1] == 0: # int
settings_dict[item[0]] = int(item[2] if not item[2].strip() == '' else '0')
elif item[1] == 1: # bool
settings_dict[item[0]] = True if item[2] == 'true' else False
elif item[1] == 2: # string
settings_dict[item[0]] = item[2]
for setting in utorrent_settings['settings']:
if setting[1] == 0: # int
settings_dict[setting[0]] = int(setting[2] if not setting[2].strip() == '' else '0')
elif setting[1] == 1: # bool
settings_dict[setting[0]] = True if setting[2] == 'true' else False
elif setting[1] == 2: # string
settings_dict[setting[0]] = setting[2]
#log.debug('uTorrent settings: %s', settings_dict)

140
couchpotato/core/plugins/renamer/main.py

@ -66,19 +66,19 @@ class Renamer(Plugin):
downloader = kwargs.get('downloader')
download_id = kwargs.get('download_id')
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 {})
release_download = {'folder': movie_folder} if movie_folder else None
if release_download:
release_download.update({'id': download_id, 'downloader': downloader} if download_id else {})
fire_handle = fireEvent if not async else fireEventAsync
fire_handle('renamer.scan', download_info)
fire_handle('renamer.scan', release_download)
return {
'success': True
}
def scan(self, download_info = None):
def scan(self, release_download = None):
if self.isDisabled():
return
@ -87,7 +87,7 @@ 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')
movie_folder = release_download and release_download.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')):
@ -102,7 +102,7 @@ class Renamer(Plugin):
return
# Make sure a checkSnatched marked all downloads/seeds as such
if not download_info and self.conf('run_every') > 0:
if not release_download and self.conf('run_every') > 0:
fireEvent('renamer.check_snatched')
self.renaming_started = True
@ -115,8 +115,8 @@ class Renamer(Plugin):
movie_folder = movie_folder.rstrip(os.path.sep)
folder = os.path.dirname(movie_folder)
if download_info['files']:
files = download_info['files'].split('|')
if release_download['files']:
files = release_download['files'].split('|')
# If there is only one file in the torrent, the downloader did not create a subfolder
if len(files) == 1:
@ -132,16 +132,16 @@ class Renamer(Plugin):
db = get_session()
# Extend the download info with info stored in the downloaded release
download_info = self.extendDownloadInfo(download_info)
release_download = self.extendReleaseDownload(release_download)
# 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,
cleanup = self.conf('cleanup') and not self.downloadIsTorrent(download_info))
cleanup = self.conf('cleanup') and not self.downloadIsTorrent(release_download))
groups = fireEvent('scanner.scan', folder = folder if folder else self.conf('from'),
files = files, download_info = download_info, return_ignored = False, single = True) or []
files = files, release_download = release_download, return_ignored = False, single = True) or []
folder_name = self.conf('folder_name')
file_name = self.conf('file_name')
@ -238,7 +238,7 @@ class Renamer(Plugin):
if file_type is 'nfo' and not self.conf('rename_nfo'):
log.debug('Skipping, renaming of %s disabled', file_type)
for current_file in group['files'][file_type]:
if self.conf('cleanup') and (not self.downloadIsTorrent(download_info) or self.fileIsAdded(current_file, group)):
if self.conf('cleanup') and (not self.downloadIsTorrent(release_download) or self.fileIsAdded(current_file, group)):
remove_files.append(current_file)
continue
@ -418,7 +418,7 @@ class Renamer(Plugin):
log.debug('Removing leftover files')
for current_file in group['files']['leftover']:
if self.conf('cleanup') and not self.conf('move_leftover') and \
(not self.downloadIsTorrent(download_info) or self.fileIsAdded(current_file, group)):
(not self.downloadIsTorrent(release_download) or self.fileIsAdded(current_file, group)):
remove_files.append(current_file)
# Remove files
@ -464,14 +464,14 @@ class Renamer(Plugin):
self.makeDir(os.path.dirname(dst))
try:
self.moveFile(src, dst, forcemove = not self.downloadIsTorrent(download_info) or self.fileIsAdded(src, group))
self.moveFile(src, dst, forcemove = not self.downloadIsTorrent(release_download) 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')
# 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(download_info):
if self.movieInFromFolder(movie_folder) and self.downloadIsTorrent(release_download):
self.tagDir(group, 'renamed_already')
# Remove matching releases
@ -482,7 +482,7 @@ class Renamer(Plugin):
except:
log.error('Failed removing %s: %s', (release.identifier, traceback.format_exc()))
if group['dirname'] and group['parentdir'] and not self.downloadIsTorrent(download_info):
if group['dirname'] and group['parentdir'] and not self.downloadIsTorrent(release_download):
if movie_folder:
# Delete the movie folder
group_folder = movie_folder
@ -678,14 +678,14 @@ 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()
scan_items = []
scan_releases = []
scan_required = False
if rels:
log.debug('Checking status snatched releases...')
statuses = fireEvent('download.status', merge = True)
if not statuses:
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:
@ -698,57 +698,57 @@ Remove it if you want it to be renamed (again, or at least let it try again)
nzbname = self.createNzbName(rel_dict['info'], movie_dict)
found = False
for item in statuses:
for release_download in release_downloads:
found_release = False
if rel_dict['info'].get('download_id'):
if item['id'] == rel_dict['info']['download_id'] and item['downloader'] == rel_dict['info']['download_downloader']:
log.debug('Found release by id: %s', item['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
else:
if item['name'] == nzbname or rel_dict['info']['name'] in item['name'] or getImdb(item['name']) == movie_dict['library']['identifier']:
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
if found_release:
timeleft = 'N/A' if item['timeleft'] == -1 else item['timeleft']
log.debug('Found %s: %s, time to go: %s', (item['name'], item['status'].upper(), timeleft))
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))
if item['status'] == 'busy':
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 item['folder'] and self.conf('from') in item['folder']:
self.tagDir(item['folder'], 'downloading')
if release_download['folder'] and self.conf('from') in release_download['folder']:
self.tagDir(release_download['folder'], 'downloading')
elif item['status'] == 'seeding':
elif release_download['status'] == 'seeding':
# Set the release to seeding
fireEvent('release.update_status', rel.id, status = seeding_status, single = True)
#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(item):
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']))
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.untagDir(item['folder'], 'downloading')
self.untagDir(release_download['folder'], 'downloading')
# Scan and set the torrent to paused if required
item.update({'pause': True, 'scan': True, 'process_complete': False})
scan_items.append(item)
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', (item['name'], item['seed_ratio']))
log.debug('%s is seeding with ratio: %s', (release_download['name'], release_download['seed_ratio']))
elif item['status'] == 'failed':
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', item, single = True)
fireEvent('download.remove_failed', release_download, single = True)
if self.conf('next_on_failed'):
fireEvent('movie.searcher.try_next_release', movie_id = rel.movie_id)
elif item['status'] == 'completed':
log.info('Download of %s completed!', item['name'])
if self.statusInfoComplete(item):
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'):
@ -757,26 +757,26 @@ Remove it if you want it to be renamed (again, or at least let it try again)
fireEvent('release.update_status', rel.id, status = downloaded_status, single = True)
# Allow the downloader to clean-up
item.update({'pause': False, 'scan': False, 'process_complete': True})
scan_items.append(item)
release_download.update({'pause': False, 'scan': False, 'process_complete': True})
scan_releases.append(release_download)
else:
# Set the release to snatched so that the renamer can process the release as if it was never seeding
fireEvent('release.update_status', rel.id, status = snatched_status, single = True)
# Scan and Allow the downloader to clean-up
item.update({'pause': False, 'scan': True, 'process_complete': True})
scan_items.append(item)
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.untagDir(item['folder'], 'downloading')
self.untagDir(release_download['folder'], 'downloading')
# Scan and Allow the downloader to clean-up
item.update({'pause': False, 'scan': True, 'process_complete': True})
scan_items.append(item)
release_download.update({'pause': False, 'scan': True, 'process_complete': True})
scan_releases.append(release_download)
else:
scan_required = True
@ -798,21 +798,21 @@ Remove it if you want it to be renamed (again, or at least let it try again)
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:
for release_download in scan_releases:
# Ask the renamer to scan the item
if item['scan']:
if item['pause'] and self.conf('file_action') == 'link':
fireEvent('download.pause', item = item, pause = True, single = True)
fireEvent('renamer.scan', download_info = item)
if item['pause'] and self.conf('file_action') == 'link':
fireEvent('download.pause', item = item, pause = False, single = True)
if item['process_complete']:
if release_download['scan']:
if release_download['pause'] and self.conf('file_action') == 'link':
fireEvent('download.pause', release_download = release_download, pause = True, single = True)
fireEvent('renamer.scan', release_download = release_download)
if release_download['pause'] and self.conf('file_action') == 'link':
fireEvent('download.pause', release_download = release_download, pause = False, single = True)
if release_download['process_complete']:
#First make sure the files were succesfully processed
if not self.hastagDir(item['folder'], 'failed_rename'):
if not self.hastagDir(release_download['folder'], 'failed_rename'):
# Remove the seeding tag if it exists
self.untagDir(item['folder'], 'renamed_already')
self.untagDir(release_download['folder'], 'renamed_already')
# Ask the downloader to process the item
fireEvent('download.process_complete', item = item, single = True)
fireEvent('download.process_complete', release_download = release_download, single = True)
if scan_required:
fireEvent('renamer.scan')
@ -821,16 +821,16 @@ Remove it if you want it to be renamed (again, or at least let it try again)
return True
def extendDownloadInfo(self, download_info):
def extendReleaseDownload(self, release_download):
rls = None
if download_info and download_info.get('id') and download_info.get('downloader'):
if release_download and release_download.get('id') and release_download.get('downloader'):
db = get_session()
rlsnfo_dwnlds = db.query(ReleaseInfo).filter_by(identifier = 'download_downloader', value = download_info.get('downloader')).all()
rlsnfo_ids = db.query(ReleaseInfo).filter_by(identifier = 'download_id', value = download_info.get('id')).all()
rlsnfo_dwnlds = db.query(ReleaseInfo).filter_by(identifier = 'download_downloader', value = release_download.get('downloader')).all()
rlsnfo_ids = db.query(ReleaseInfo).filter_by(identifier = 'download_id', value = release_download.get('id')).all()
for rlsnfo_dwnld in rlsnfo_dwnlds:
for rlsnfo_id in rlsnfo_ids:
@ -840,29 +840,29 @@ Remove it if you want it to be renamed (again, or at least let it try again)
if rls: break
if not rls:
log.error('Download ID %s from downloader %s not found in releases', (download_info.get('id'), download_info.get('downloader')))
log.error('Download ID %s from downloader %s not found in releases', (release_download.get('id'), release_download.get('downloader')))
if rls:
rls_dict = rls.to_dict({'info':{}})
download_info.update({
release_download.update({
'imdb_id': rls.movie.library.identifier,
'quality': rls.quality.identifier,
'protocol': rls_dict.get('info', {}).get('protocol') or rls_dict.get('info', {}).get('type'),
})
return download_info
return release_download
def downloadIsTorrent(self, download_info):
return download_info and download_info.get('protocol') in ['torrent', 'torrent_magnet']
def downloadIsTorrent(self, release_download):
return release_download and release_download.get('protocol') in ['torrent', 'torrent_magnet']
def fileIsAdded(self, src, group):
if not group or not group.get('before_rename'):
return False
return src in group['before_rename']
def statusInfoComplete(self, item):
return item['id'] and item['downloader'] and item['folder']
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 self.conf('from') in movie_folder or not movie_folder

Loading…
Cancel
Save