diff --git a/couchpotato/core/downloaders/deluge/main.py b/couchpotato/core/downloaders/deluge/main.py index 6c55d1a..4d0bf59 100644 --- a/couchpotato/core/downloaders/deluge/main.py +++ b/couchpotato/core/downloaders/deluge/main.py @@ -1,6 +1,6 @@ from base64 import b64encode from couchpotato.core.downloaders.base import Downloader, ReleaseDownloadList -from couchpotato.core.helpers.encoding import isInt, ss +from couchpotato.core.helpers.encoding import isInt, sp from couchpotato.core.helpers.variable import tryFloat from couchpotato.core.logger import CPLog from datetime import timedelta @@ -111,13 +111,13 @@ class Deluge(Downloader): elif torrent['is_seed'] and torrent['is_finished'] and torrent['paused'] and torrent['state'] == 'Paused': status = 'completed' - download_dir = torrent['save_path'] + download_dir = sp(torrent['save_path']) if torrent['move_on_completed']: download_dir = torrent['move_completed_path'] torrent_files = [] for file_item in torrent['files']: - torrent_files.append(os.path.join(download_dir, file_item['path'])) + torrent_files.append(os.path.join(download_dir), sp(file_item['path'])) release_downloads.append({ 'id': torrent['hash'], @@ -126,8 +126,8 @@ class Deluge(Downloader): '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)), + 'folder': sp(download_dir) if len(torrent_files) == 1 else os.path.join(sp(download_dir), torrent['name']), + 'files': '|'.join(torrent_files), }) return release_downloads diff --git a/couchpotato/core/downloaders/nzbget/main.py b/couchpotato/core/downloaders/nzbget/main.py index 7d5aafd..f850613 100644 --- a/couchpotato/core/downloaders/nzbget/main.py +++ b/couchpotato/core/downloaders/nzbget/main.py @@ -1,6 +1,6 @@ from base64 import standard_b64encode from couchpotato.core.downloaders.base import Downloader, ReleaseDownloadList -from couchpotato.core.helpers.encoding import ss +from couchpotato.core.helpers.encoding import ss, sp from couchpotato.core.helpers.variable import tryInt, md5 from couchpotato.core.logger import CPLog from datetime import timedelta @@ -145,7 +145,7 @@ class NZBGet(Downloader): '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(nzb['DestDir']) + 'folder': sp(nzb['DestDir']) }) return release_downloads diff --git a/couchpotato/core/downloaders/nzbvortex/main.py b/couchpotato/core/downloaders/nzbvortex/main.py index 983a8fd..4ec4586 100644 --- a/couchpotato/core/downloaders/nzbvortex/main.py +++ b/couchpotato/core/downloaders/nzbvortex/main.py @@ -1,6 +1,6 @@ from base64 import b64encode from couchpotato.core.downloaders.base import Downloader, ReleaseDownloadList -from couchpotato.core.helpers.encoding import tryUrlencode, ss +from couchpotato.core.helpers.encoding import tryUrlencode, sp from couchpotato.core.helpers.variable import cleanHost from couchpotato.core.logger import CPLog from urllib2 import URLError @@ -30,7 +30,7 @@ class NZBVortex(Downloader): # Send the nzb try: nzb_filename = self.createFileName(data, filedata, movie) - self.call('nzb/add', params = {'file': (ss(nzb_filename), filedata)}, multipart = True) + self.call('nzb/add', params = {'file': (sp(nzb_filename), filedata)}, multipart = True) raw_statuses = self.call('nzb') nzb_id = [nzb['id'] for nzb in raw_statuses.get('nzbs', []) if nzb['name'] == nzb_filename][0] @@ -59,7 +59,7 @@ class NZBVortex(Downloader): 'status': status, 'original_status': nzb['state'], 'timeleft':-1, - 'folder': ss(nzb['destinationPath']), + 'folder': sp(nzb['destinationPath']), }) return release_downloads diff --git a/couchpotato/core/downloaders/rtorrent/main.py b/couchpotato/core/downloaders/rtorrent/main.py index 67df20a..5cceee6 100755 --- a/couchpotato/core/downloaders/rtorrent/main.py +++ b/couchpotato/core/downloaders/rtorrent/main.py @@ -1,7 +1,7 @@ from base64 import b16encode, b32decode from bencode import bencode, bdecode from couchpotato.core.downloaders.base import Downloader, ReleaseDownloadList -from couchpotato.core.helpers.encoding import ss +from couchpotato.core.helpers.encoding import sp from couchpotato.core.logger import CPLog from datetime import timedelta from hashlib import sha1 @@ -157,7 +157,7 @@ class rTorrent(Downloader): for torrent in torrents: torrent_files = [] for file_item in torrent.get_files(): - torrent_files.append(os.path.join(torrent.directory, file_item.path)) + torrent_files.append(os.path.join(sp(torrent.directory), sp(file_item.path))) status = 'busy' if torrent.complete: @@ -173,8 +173,8 @@ class rTorrent(Downloader): '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)) + 'folder': sp(torrent.directory), + 'files': '|'.join(torrent_files) }) return release_downloads diff --git a/couchpotato/core/downloaders/sabnzbd/main.py b/couchpotato/core/downloaders/sabnzbd/main.py index dcbe245..de8ecef 100644 --- a/couchpotato/core/downloaders/sabnzbd/main.py +++ b/couchpotato/core/downloaders/sabnzbd/main.py @@ -1,5 +1,5 @@ from couchpotato.core.downloaders.base import Downloader, ReleaseDownloadList -from couchpotato.core.helpers.encoding import tryUrlencode, ss +from couchpotato.core.helpers.encoding import tryUrlencode, ss, sp from couchpotato.core.helpers.variable import cleanHost, mergeDicts from couchpotato.core.logger import CPLog from couchpotato.environment import Env @@ -118,7 +118,7 @@ class Sabnzbd(Downloader): 'status': status, 'original_status': nzb['status'], 'timeleft': str(timedelta(seconds = 0)), - 'folder': os.path.dirname(ss(nzb['storage'])) if os.path.isfile(ss(nzb['storage'])) else ss(nzb['storage']), + 'folder': os.path.dirname(sp(nzb['storage'])) if os.path.isfile(sp(nzb['storage'])) else sp(nzb['storage']), }) return release_downloads diff --git a/couchpotato/core/downloaders/transmission/main.py b/couchpotato/core/downloaders/transmission/main.py index 9464616..a2295a0 100644 --- a/couchpotato/core/downloaders/transmission/main.py +++ b/couchpotato/core/downloaders/transmission/main.py @@ -1,6 +1,6 @@ from base64 import b64encode from couchpotato.core.downloaders.base import Downloader, ReleaseDownloadList -from couchpotato.core.helpers.encoding import isInt, ss +from couchpotato.core.helpers.encoding import isInt, sp from couchpotato.core.helpers.variable import tryInt, tryFloat from couchpotato.core.logger import CPLog from datetime import timedelta @@ -105,7 +105,7 @@ class Transmission(Downloader): torrent_files = [] for file_item in torrent['files']: - torrent_files.append(os.path.normpath(os.path.join(ss(torrent['downloadDir']), ss(file_item['name'])))) + torrent_files.append(os.path.join(sp(torrent['downloadDir']), sp(file_item['name']))) status = 'busy' if torrent.get('isStalled') and self.conf('stalled_as_failed'): @@ -122,8 +122,8 @@ class Transmission(Downloader): 'original_status': torrent['status'], 'seed_ratio': torrent['uploadRatio'], 'timeleft': str(timedelta(seconds = torrent['eta'])), - 'folder': os.path.normpath(ss(torrent['downloadDir'])) if len(torrent_files) == 1 else os.path.normpath(os.path.join(ss(torrent['downloadDir']), ss(torrent['name']))), - 'files': ss('|'.join(torrent_files)) + 'folder': sp(torrent['downloadDir']) if len(torrent_files) == 1 else os.path.join(sp(torrent['downloadDir']), sp(torrent['name'])), + 'files': '|'.join(torrent_files) }) return release_downloads diff --git a/couchpotato/core/downloaders/utorrent/main.py b/couchpotato/core/downloaders/utorrent/main.py index b0b9c89..5486263 100644 --- a/couchpotato/core/downloaders/utorrent/main.py +++ b/couchpotato/core/downloaders/utorrent/main.py @@ -1,7 +1,7 @@ from base64 import b16encode, b32decode from bencode import bencode as benc, bdecode from couchpotato.core.downloaders.base import Downloader, ReleaseDownloadList -from couchpotato.core.helpers.encoding import isInt, ss +from couchpotato.core.helpers.encoding import isInt, ss, sp from couchpotato.core.helpers.variable import tryInt, tryFloat from couchpotato.core.logger import CPLog from datetime import timedelta @@ -134,7 +134,7 @@ class uTorrent(Downloader): torrent_files = [] try: 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]] + torrent_files = [os.path.join(sp(torrent[26]), sp(torrent_file[0])) for torrent_file in torrent_files['files'][1]] except: log.debug('Failed getting files from torrent: %s', torrent[2]) @@ -167,8 +167,8 @@ class uTorrent(Downloader): '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)) + 'folder': sp(torrent[26]), + 'files': '|'.join(torrent_files) }) return release_downloads diff --git a/couchpotato/core/helpers/encoding.py b/couchpotato/core/helpers/encoding.py index 5fa2e2a..bfebcc1 100644 --- a/couchpotato/core/helpers/encoding.py +++ b/couchpotato/core/helpers/encoding.py @@ -1,6 +1,7 @@ from couchpotato.core.logger import CPLog from string import ascii_letters, digits from urllib import quote_plus +import os import re import traceback import unicodedata @@ -47,6 +48,10 @@ def ss(original, *args): log.debug('Failed ss encoding char, force UTF8: %s', e) return u_original.encode('UTF-8') +def sp(path, *args): + # Standardise encoding, normalise case, path and strip trailing '/' or '\' + return os.path.normcase(os.path.normpath(ss(path, *args))).rstrip(os.path.sep) + def ek(original, *args): if isinstance(original, (str, unicode)): try: diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index 4aa0f20..5562909 100755 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -1,7 +1,7 @@ from couchpotato import get_session from couchpotato.api import addApiView from couchpotato.core.event import addEvent, fireEvent, fireEventAsync -from couchpotato.core.helpers.encoding import toUnicode, ss +from couchpotato.core.helpers.encoding import toUnicode, ss, sp from couchpotato.core.helpers.variable import getExt, mergeDicts, getTitle, \ getImdb, link, symlink, tryInt, splitString from couchpotato.core.logger import CPLog @@ -63,7 +63,7 @@ class Renamer(Plugin): def scanView(self, **kwargs): async = tryInt(kwargs.get('async', 0)) - movie_folder = kwargs.get('movie_folder') + movie_folder = sp(kwargs.get('movie_folder')) downloader = kwargs.get('downloader') download_id = kwargs.get('download_id') status = kwargs.get('status', 'completed') @@ -93,7 +93,7 @@ class Renamer(Plugin): movie_folder = release_download and release_download.get('folder') # Get all folders that should not be processed - no_process = [self.conf('to')] + no_process = [sp(self.conf('to'))] cat_list = fireEvent('category.all', single = True) or [] no_process.extend([item['destination'] for item in cat_list]) try: @@ -103,12 +103,12 @@ class Renamer(Plugin): pass # Check to see if the no_process folders are inside the "from" folder. - if not os.path.isdir(self.conf('from')) or not os.path.isdir(self.conf('to')): + if not os.path.isdir(sp(self.conf('from'))) or not os.path.isdir(sp(self.conf('to'))): log.error('Both the "To" and "From" have to exist.') return else: for item in no_process: - if self.conf('from') in item: + if sp(self.conf('from')) in item: log.error('To protect your data, the movie libraries can\'t be inside of or the same as the "from" folder.') return @@ -133,7 +133,6 @@ class Renamer(Plugin): files = [] if movie_folder: log.info('Scanning movie folder %s...', movie_folder) - movie_folder = movie_folder.rstrip(os.path.sep) folder = os.path.dirname(movie_folder) if release_download.get('files', ''): @@ -161,7 +160,7 @@ class Renamer(Plugin): folder, movie_folder, files, extr_files = self.extractFiles(folder = folder, movie_folder = movie_folder, files = files, cleanup = self.conf('cleanup') and not self.downloadIsTorrent(release_download)) - groups = fireEvent('scanner.scan', folder = folder if folder else self.conf('from'), + groups = fireEvent('scanner.scan', folder = folder if folder else sp(self.conf('from')), files = files, release_download = release_download, return_ignored = False, single = True) or [] folder_name = self.conf('folder_name') @@ -200,7 +199,7 @@ class Renamer(Plugin): movie_title = getTitle(library) # Overwrite destination when set in category - destination = self.conf('to') + destination = sp(self.conf('to')) category_label = '' for movie in library_ent.movies: @@ -465,12 +464,12 @@ class Renamer(Plugin): log.info('Removing "%s"', src) try: - src = ss(src) + src = sp(src) if os.path.isfile(src): os.remove(src) - parent_dir = os.path.normpath(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 self.conf('from') in parent_dir: + 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 sp(self.conf('from')) in parent_dir: delete_folders.append(parent_dir) except: @@ -519,7 +518,7 @@ class Renamer(Plugin): group_folder = movie_folder else: # Delete the first empty subfolder in the tree relative to the 'from' folder - group_folder = os.path.join(self.conf('from'), os.path.relpath(group['parentdir'], self.conf('from')).split(os.path.sep)[0]) + group_folder = os.path.join(sp(self.conf('from')), os.path.relpath(group['parentdir'], sp(self.conf('from'))).split(os.path.sep)[0]) try: log.info('Deleting folder: %s', group_folder) @@ -802,7 +801,7 @@ Remove it if you want it to be renamed (again, or at least let it try again) 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 release_download['folder'] and self.conf('from') in release_download['folder']: + if self.movieInFromFolder(release_download['folder']): self.tagRelease(release_download = release_download, tag = 'downloading') elif release_download['status'] == 'seeding': @@ -948,7 +947,7 @@ Remove it if you want it to be renamed (again, or at least let it try again) 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 + return movie_folder and sp(self.conf('from')) in movie_folder or not movie_folder def extractFiles(self, folder = None, movie_folder = None, files = None, cleanup = False): if not files: files = [] @@ -960,7 +959,7 @@ Remove it if you want it to be renamed (again, or at least let it try again) # Check input variables if not folder: - folder = self.conf('from') + folder = sp(self.conf('from')) check_file_date = True if movie_folder: @@ -1014,7 +1013,7 @@ Remove it if you want it to be renamed (again, or at least let it try again) log.info('Archive %s found. Extracting...', os.path.basename(archive['file'])) try: rar_handle = RarFile(archive['file']) - extr_path = os.path.join(self.conf('from'), os.path.relpath(os.path.dirname(archive['file']), folder)) + extr_path = os.path.join(sp(self.conf('from')), os.path.relpath(os.path.dirname(archive['file']), folder)) self.makeDir(extr_path) for packedinfo in rar_handle.infolist(): if not packedinfo.isdir and not os.path.isfile(os.path.join(extr_path, os.path.basename(packedinfo.filename))): @@ -1037,9 +1036,9 @@ Remove it if you want it to be renamed (again, or at least let it try again) files.remove(filename) # Move the rest of the files and folders if any files are extracted to the from folder (only if folder was provided) - if extr_files and os.path.normpath(os.path.normcase(folder)) != os.path.normpath(os.path.normcase(self.conf('from'))): + if extr_files and folder != sp(self.conf('from')): for leftoverfile in list(files): - move_to = os.path.join(self.conf('from'), os.path.relpath(leftoverfile, folder)) + move_to = os.path.join(sp(self.conf('from')), os.path.relpath(leftoverfile, folder)) try: self.makeDir(os.path.dirname(move_to)) @@ -1062,8 +1061,8 @@ Remove it if you want it to be renamed (again, or at least let it try again) log.debug('Removing old movie folder %s...', movie_folder) self.deleteEmptyFolder(movie_folder) - movie_folder = os.path.join(self.conf('from'), os.path.relpath(movie_folder, folder)) - folder = self.conf('from') + movie_folder = os.path.join(sp(self.conf('from')), os.path.relpath(movie_folder, folder)) + folder = sp(self.conf('from')) if extr_files: files.extend(extr_files) diff --git a/couchpotato/core/plugins/scanner/main.py b/couchpotato/core/plugins/scanner/main.py index 6346269..832cfa3 100644 --- a/couchpotato/core/plugins/scanner/main.py +++ b/couchpotato/core/plugins/scanner/main.py @@ -1,6 +1,6 @@ from couchpotato import get_session from couchpotato.core.event import fireEvent, addEvent -from couchpotato.core.helpers.encoding import toUnicode, simplifyString, ss +from couchpotato.core.helpers.encoding import toUnicode, simplifyString, ss, sp from couchpotato.core.helpers.variable import getExt, getImdb, tryInt, \ splitString from couchpotato.core.logger import CPLog @@ -106,7 +106,7 @@ class Scanner(Plugin): def scan(self, folder = None, files = None, release_download = None, simple = False, newer_than = 0, return_ignored = True, on_found = None): - folder = ss(os.path.normpath(folder)) + folder = sp(folder) if not folder or not os.path.isdir(folder): log.error('Folder doesn\'t exists: %s', folder) @@ -122,7 +122,7 @@ class Scanner(Plugin): try: files = [] for root, dirs, walk_files in os.walk(folder): - files.extend(os.path.join(root, filename) for filename in walk_files) + files.extend([os.path.join(root, filename) for filename in walk_files]) # Break if CP wants to shut down if self.shuttingDown():