Browse Source

Merge branch 'refs/heads/develop'

pull/3560/head
Ruud 11 years ago
parent
commit
0210859155
  1. 44
      couchpotato/core/helpers/variable.py
  2. 3
      couchpotato/core/media/_base/media/main.py
  3. 34
      couchpotato/core/plugins/file.py
  4. 30
      couchpotato/core/plugins/manage.py
  5. 8
      couchpotato/core/plugins/profile/static/profile.js
  6. 4
      couchpotato/core/plugins/quality/main.py
  7. 4
      couchpotato/core/plugins/scanner.py
  8. 2
      couchpotato/core/plugins/trailer.py
  9. 11
      couchpotato/runner.py

44
couchpotato/core/helpers/variable.py

@ -1,4 +1,5 @@
import collections import collections
import ctypes
import hashlib import hashlib
import os import os
import platform import platform
@ -291,9 +292,14 @@ def dictIsSubset(a, b):
return all([k in b and b[k] == v for k, v in a.items()]) return all([k in b and b[k] == v for k, v in a.items()])
# Returns True if sub_folder is the same as or inside base_folder
def isSubFolder(sub_folder, base_folder): def isSubFolder(sub_folder, base_folder):
# Returns True if sub_folder is the same as or inside base_folder if base_folder and sub_folder:
return base_folder and sub_folder and ss(os.path.normpath(base_folder).rstrip(os.path.sep) + os.path.sep) in ss(os.path.normpath(sub_folder).rstrip(os.path.sep) + os.path.sep) base = sp(os.path.realpath(base_folder)) + os.path.sep
subfolder = sp(os.path.realpath(sub_folder)) + os.path.sep
return os.path.commonprefix([subfolder, base]) == base
return False
# From SABNZBD # From SABNZBD
@ -341,3 +347,37 @@ def removePyc(folder, only_excess = True, show_logs = True):
os.rmdir(full_path) os.rmdir(full_path)
except: except:
log.error('Couldn\'t remove empty directory %s: %s', (full_path, traceback.format_exc())) log.error('Couldn\'t remove empty directory %s: %s', (full_path, traceback.format_exc()))
def getFreeSpace(directories):
single = not isinstance(directories, (tuple, list))
if single:
directories = [directories]
free_space = {}
for folder in directories:
size = None
if os.path.isdir(folder):
if os.name == 'nt':
_, total, free = ctypes.c_ulonglong(), ctypes.c_ulonglong(), \
ctypes.c_ulonglong()
if sys.version_info >= (3,) or isinstance(folder, unicode):
fun = ctypes.windll.kernel32.GetDiskFreeSpaceExW #@UndefinedVariable
else:
fun = ctypes.windll.kernel32.GetDiskFreeSpaceExA #@UndefinedVariable
ret = fun(folder, ctypes.byref(_), ctypes.byref(total), ctypes.byref(free))
if ret == 0:
raise ctypes.WinError()
used = total.value - free.value
return [total.value, used, free.value]
else:
s = os.statvfs(folder)
size = [s.f_blocks * s.f_frsize / (1024 * 1024), (s.f_bavail * s.f_frsize) / (1024 * 1024)]
if single: return size
free_space[folder] = size
return free_space

3
couchpotato/core/media/_base/media/main.py

@ -477,7 +477,8 @@ class MediaPlugin(MediaBase):
if fireEvent('quality.isfinish', {'identifier': release['quality'], 'is_3d': release.get('is_3d', False)}, profile, timedelta(seconds = time.time() - release['last_edit']).days, single = True): if fireEvent('quality.isfinish', {'identifier': release['quality'], 'is_3d': release.get('is_3d', False)}, profile, timedelta(seconds = time.time() - release['last_edit']).days, single = True):
m['status'] = 'done' m['status'] = 'done'
except RecordNotFound: except RecordNotFound:
log.debug('Failed restatus: %s', traceback.format_exc()) log.debug('Failed restatus, keeping previous: %s', traceback.format_exc())
m['status'] = previous_status
# Only update when status has changed # Only update when status has changed
if previous_status != m['status']: if previous_status != m['status']:

34
couchpotato/core/plugins/file.py

@ -5,7 +5,7 @@ from couchpotato import get_db
from couchpotato.api import addApiView from couchpotato.api import addApiView
from couchpotato.core.event import addEvent, fireEvent from couchpotato.core.event import addEvent, fireEvent
from couchpotato.core.helpers.encoding import toUnicode from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.helpers.variable import md5, getExt from couchpotato.core.helpers.variable import md5, getExt, isSubFolder
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin from couchpotato.core.plugins.base import Plugin
from couchpotato.environment import Env from couchpotato.environment import Env
@ -32,6 +32,8 @@ class FileManager(Plugin):
fireEvent('schedule.interval', 'file.cleanup', self.cleanup, hours = 24) fireEvent('schedule.interval', 'file.cleanup', self.cleanup, hours = 24)
addEvent('app.test', self.doSubfolderTest)
def cleanup(self): def cleanup(self):
# Wait a bit after starting before cleanup # Wait a bit after starting before cleanup
@ -76,3 +78,33 @@ class FileManager(Plugin):
self.createFile(dest, filedata, binary = True) self.createFile(dest, filedata, binary = True)
return dest return dest
def doSubfolderTest(self):
tests = {
('/test/subfolder', '/test/sub'): False,
('/test/sub/folder', '/test/sub'): True,
('/test/sub/folder', '/test/sub2'): False,
('/sub/fold', '/test/sub/fold'): False,
('/sub/fold', '/test/sub/folder'): False,
('/opt/couchpotato', '/var/opt/couchpotato'): False,
('/var/opt', '/var/opt/couchpotato'): False,
('/CapItaLs/Are/OK', '/CapItaLs/Are/OK'): True,
('/CapItaLs/Are/OK', '/CapItaLs/Are/OK2'): False,
('/capitals/are/not/OK', '/capitals/are/NOT'): False,
('\\\\Mounted\\Volume\\Test', '\\\\Mounted\\Volume'): True,
('C:\\\\test\\path', 'C:\\\\test2'): False
}
failed = 0
for x in tests:
if isSubFolder(x[0], x[1]) is not tests[x]:
log.error('Failed subfolder test %s %s', x)
failed += 1
if failed > 0:
log.error('Subfolder test failed %s tests', failed)
else:
log.info('Subfolder test succeeded')
return failed == 0

30
couchpotato/core/plugins/manage.py

@ -1,6 +1,4 @@
import ctypes
import os import os
import sys
import time import time
import traceback import traceback
@ -8,7 +6,7 @@ from couchpotato import get_db
from couchpotato.api import addApiView from couchpotato.api import addApiView
from couchpotato.core.event import fireEvent, addEvent, fireEventAsync from couchpotato.core.event import fireEvent, addEvent, fireEventAsync
from couchpotato.core.helpers.encoding import sp from couchpotato.core.helpers.encoding import sp
from couchpotato.core.helpers.variable import splitString, getTitle, tryInt, getIdentifier from couchpotato.core.helpers.variable import splitString, getTitle, tryInt, getIdentifier, getFreeSpace
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin from couchpotato.core.plugins.base import Plugin
from couchpotato.environment import Env from couchpotato.environment import Env
@ -273,31 +271,7 @@ class Manage(Plugin):
fireEvent('release.add', group = group) fireEvent('release.add', group = group)
def getDiskSpace(self): def getDiskSpace(self):
return getFreeSpace(self.directories())
free_space = {}
for folder in self.directories():
size = None
if os.path.isdir(folder):
if os.name == 'nt':
_, total, free = ctypes.c_ulonglong(), ctypes.c_ulonglong(), \
ctypes.c_ulonglong()
if sys.version_info >= (3,) or isinstance(folder, unicode):
fun = ctypes.windll.kernel32.GetDiskFreeSpaceExW #@UndefinedVariable
else:
fun = ctypes.windll.kernel32.GetDiskFreeSpaceExA #@UndefinedVariable
ret = fun(folder, ctypes.byref(_), ctypes.byref(total), ctypes.byref(free))
if ret == 0:
raise ctypes.WinError()
used = total.value - free.value
return [total.value, used, free.value]
else:
s = os.statvfs(folder)
size = [s.f_blocks * s.f_frsize / (1024 * 1024), (s.f_bavail * s.f_frsize) / (1024 * 1024)]
free_space[folder] = size
return free_space
config = [{ config = [{

8
couchpotato/core/plugins/profile/static/profile.js

@ -47,14 +47,14 @@ var Profile = new Class({
new Element('div.wait_for.ctrlHolder').adopt( new Element('div.wait_for.ctrlHolder').adopt(
// "Wait the entered number of days for a checked quality, before downloading a lower quality release." // "Wait the entered number of days for a checked quality, before downloading a lower quality release."
new Element('span', {'text':'Wait'}), new Element('span', {'text':'Wait'}),
new Element('input.inlay.xsmall', { new Element('input.inlay.wait_for_input.xsmall', {
'type':'text', 'type':'text',
'value': data.wait_for && data.wait_for.length > 0 ? data.wait_for[0] : 0 'value': data.wait_for && data.wait_for.length > 0 ? data.wait_for[0] : 0
}), }),
new Element('span', {'text':'day(s) for a better quality '}), new Element('span', {'text':'day(s) for a better quality '}),
new Element('span.advanced', {'text':'and keep searching'}), new Element('span.advanced', {'text':'and keep searching'}),
// "After a checked quality is found and downloaded, continue searching for even better quality releases for the entered number of days." // "After a checked quality is found and downloaded, continue searching for even better quality releases for the entered number of days."
new Element('input.inlay.xsmall.advanced', { new Element('input.inlay.xsmall.stop_after_input.advanced', {
'type':'text', 'type':'text',
'value': data.stop_after && data.stop_after.length > 0 ? data.stop_after[0] : 0 'value': data.stop_after && data.stop_after.length > 0 ? data.stop_after[0] : 0
}), }),
@ -124,8 +124,8 @@ var Profile = new Class({
var data = { var data = {
'id' : self.data._id, 'id' : self.data._id,
'label' : self.el.getElement('.quality_label input').get('value'), 'label' : self.el.getElement('.quality_label input').get('value'),
'wait_for' : self.el.getElement('.wait_for input').get('value'), 'wait_for' : self.el.getElement('.wait_for_input').get('value'),
'stop_after' : self.el.getElement('.stop_after input').get('value'), 'stop_after' : self.el.getElement('.stop_after_input').get('value'),
'types': [] 'types': []
}; };

4
couchpotato/core/plugins/quality/main.py

@ -387,8 +387,8 @@ class QualityPlugin(Plugin):
try: try:
index = [i for i, identifier in enumerate(profile['qualities']) if identifier == quality['identifier'] and bool(profile['3d'][i] if profile.get('3d') else False) == bool(quality.get('is_3d', False))][0] index = [i for i, identifier in enumerate(profile['qualities']) if identifier == quality['identifier'] and bool(profile['3d'][i] if profile.get('3d') else False) == bool(quality.get('is_3d', False))][0]
if index == 0 or profile['finish'][index] and int(release_age) >= int(profile['stop_after'][0]): if index == 0 or (profile['finish'][index] and int(release_age) >= int(profile.get('stop_after', [0])[0])):
return True return True
return False return False
except: except:

4
couchpotato/core/plugins/scanner.py

@ -639,9 +639,9 @@ class Scanner(Plugin):
# Try with other # Try with other
if len(movie) == 0 and name_year.get('other') and name_year['other'].get('name') and name_year['other'].get('year'): if len(movie) == 0 and name_year.get('other') and name_year['other'].get('name') and name_year['other'].get('year'):
search_q2 = '%(name)s %(year)s' % name_year search_q2 = '%(name)s %(year)s' % name_year.get('other')
if search_q2 != search_q: if search_q2 != search_q:
movie = fireEvent('movie.search', q = '%(name)s %(year)s' % name_year.get('other'), merge = True, limit = 1) movie = fireEvent('movie.search', q = search_q2, merge = True, limit = 1)
if len(movie) > 0: if len(movie) > 0:
imdb_id = movie[0].get('imdb') imdb_id = movie[0].get('imdb')

2
couchpotato/core/plugins/trailer.py

@ -32,7 +32,7 @@ class Trailer(Plugin):
destination = os.path.join(group['destination_dir'], filename) destination = os.path.join(group['destination_dir'], filename)
if not os.path.isfile(destination): if not os.path.isfile(destination):
trailer_file = fireEvent('file.download', url = trailer, dest = destination, urlopen_kwargs = {'headers': {'User-Agent': 'Quicktime'}}, single = True) trailer_file = fireEvent('file.download', url = trailer, dest = destination, urlopen_kwargs = {'headers': {'User-Agent': 'Quicktime'}}, single = True)
if os.path.getsize(trailer_file) < (1024 * 1024): # Don't trust small trailers (1MB), try next one if trailer_file and os.path.getsize(trailer_file) < (1024 * 1024): # Don't trust small trailers (1MB), try next one
os.unlink(trailer_file) os.unlink(trailer_file)
continue continue
else: else:

11
couchpotato/runner.py

@ -17,7 +17,7 @@ from couchpotato import KeyHandler, LoginHandler, LogoutHandler
from couchpotato.api import NonBlockHandler, ApiHandler from couchpotato.api import NonBlockHandler, ApiHandler
from couchpotato.core.event import fireEventAsync, fireEvent from couchpotato.core.event import fireEventAsync, fireEvent
from couchpotato.core.helpers.encoding import sp from couchpotato.core.helpers.encoding import sp
from couchpotato.core.helpers.variable import getDataDir, tryInt from couchpotato.core.helpers.variable import getDataDir, tryInt, getFreeSpace
import requests import requests
from tornado.httpserver import HTTPServer from tornado.httpserver import HTTPServer
from tornado.web import Application, StaticFileHandler, RedirectHandler from tornado.web import Application, StaticFileHandler, RedirectHandler
@ -195,6 +195,15 @@ def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, En
log = CPLog(__name__) log = CPLog(__name__)
log.debug('Started with options %s', options) log.debug('Started with options %s', options)
# Check available space
try:
total_space, available_space = getFreeSpace(data_dir)
if available_space < 100:
log.error('Shutting down as CP needs some space to work. You\'ll get corrupted data otherwise. Only %sMB left', available_space)
return
except:
log.error('Failed getting diskspace: %s', traceback.format_exc())
def customwarn(message, category, filename, lineno, file = None, line = None): def customwarn(message, category, filename, lineno, file = None, line = None):
log.warning('%s %s %s line:%s', (category, message, filename, lineno)) log.warning('%s %s %s line:%s', (category, message, filename, lineno))
warnings.showwarning = customwarn warnings.showwarning = customwarn

Loading…
Cancel
Save