Merge branch 'refs/heads/develop'
This commit is contained in:
@@ -33,7 +33,7 @@ Linux (ubuntu / debian):
|
|||||||
* 'cd' to the folder of your choosing.
|
* 'cd' to the folder of your choosing.
|
||||||
* Run `git clone https://github.com/RuudBurger/CouchPotatoServer.git`
|
* Run `git clone https://github.com/RuudBurger/CouchPotatoServer.git`
|
||||||
* Then do `python CouchPotatoServer/CouchPotato.py` to start
|
* Then do `python CouchPotatoServer/CouchPotato.py` to start
|
||||||
* To run on boot copy the init script. `cp CouchPotatoServer/init/ubuntu /etc/init.d/couchpotato`
|
* To run on boot copy the init script. `sudo cp CouchPotatoServer/init/ubuntu /etc/init.d/couchpotato`
|
||||||
* Change the paths inside the init script. `nano /etc/init.d/couchpotato`
|
* Change the paths inside the init script. `sudo nano /etc/init.d/couchpotato`
|
||||||
* Make it executable. `chmod +x /etc/init.d/couchpotato`
|
* Make it executable. `sudo chmod +x /etc/init.d/couchpotato`
|
||||||
* Add it to defaults. `sudo update-rc.d couchpotato defaults`
|
* Add it to defaults. `sudo update-rc.d couchpotato defaults`
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ config = [{
|
|||||||
'name': 'host',
|
'name': 'host',
|
||||||
'advanced': True,
|
'advanced': True,
|
||||||
'default': '0.0.0.0',
|
'default': '0.0.0.0',
|
||||||
|
'hidden': True,
|
||||||
'label': 'IP',
|
'label': 'IP',
|
||||||
'description': 'Host that I should listen to. "0.0.0.0" listens to all ips.',
|
'description': 'Host that I should listen to. "0.0.0.0" listens to all ips.',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
from .main import Updater
|
from .main import Updater
|
||||||
|
from couchpotato.environment import Env
|
||||||
|
import os
|
||||||
|
|
||||||
def start():
|
def start():
|
||||||
return Updater()
|
return Updater()
|
||||||
@@ -33,6 +35,7 @@ config = [{
|
|||||||
{
|
{
|
||||||
'name': 'git_command',
|
'name': 'git_command',
|
||||||
'default': 'git',
|
'default': 'git',
|
||||||
|
'hidden': not os.path.isdir(os.path.join(Env.get('app_dir'), '.git')),
|
||||||
'advanced': True
|
'advanced': True
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
from base64 import b32decode, b16encode
|
from base64 import b32decode, b16encode
|
||||||
from couchpotato.core.event import addEvent
|
from couchpotato.core.event import addEvent
|
||||||
from couchpotato.core.helpers.encoding import toSafeString
|
|
||||||
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
|
|
||||||
import os
|
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
|
|
||||||
@@ -23,29 +20,17 @@ class Downloader(Plugin):
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
addEvent('download', self.download)
|
addEvent('download', self.download)
|
||||||
addEvent('download.status', self.getDownloadStatus)
|
addEvent('download.status', self.getAllDownloadStatus)
|
||||||
|
addEvent('download.remove_failed', self.removeFailed)
|
||||||
|
|
||||||
def download(self, data = {}, movie = {}, manual = False, filedata = None):
|
def download(self, data = {}, movie = {}, manual = False, filedata = None):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def getDownloadStatus(self, data = {}, movie = {}):
|
def getAllDownloadStatus(self):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def createNzbName(self, data, movie):
|
def removeFailed(self, name = {}, nzo_id = {}):
|
||||||
tag = self.cpTag(movie)
|
return False
|
||||||
return '%s%s' % (toSafeString(data.get('name')[:127 - len(tag)]), tag)
|
|
||||||
|
|
||||||
def createFileName(self, data, filedata, movie):
|
|
||||||
name = os.path.join(self.createNzbName(data, movie))
|
|
||||||
if data.get('type') == 'nzb' and 'DOCTYPE nzb' not in filedata and '</nzb>' not in filedata:
|
|
||||||
return '%s.%s' % (name, 'rar')
|
|
||||||
return '%s.%s' % (name, data.get('type'))
|
|
||||||
|
|
||||||
def cpTag(self, movie):
|
|
||||||
if Env.setting('enabled', 'renamer'):
|
|
||||||
return '.cp(' + movie['library'].get('identifier') + ')' if movie['library'].get('identifier') else ''
|
|
||||||
|
|
||||||
return ''
|
|
||||||
|
|
||||||
def isCorrectType(self, item_type):
|
def isCorrectType(self, item_type):
|
||||||
is_correct = item_type in self.type
|
is_correct = item_type in self.type
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ config = [{
|
|||||||
'name': 'nzbget',
|
'name': 'nzbget',
|
||||||
'label': 'NZBGet',
|
'label': 'NZBGet',
|
||||||
'description': 'Send NZBs to your NZBGet installation.',
|
'description': 'Send NZBs to your NZBGet installation.',
|
||||||
'wizard': True,
|
|
||||||
'options': [
|
'options': [
|
||||||
{
|
{
|
||||||
'name': 'enabled',
|
'name': 'enabled',
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ config = [{
|
|||||||
'name': 'pneumatic',
|
'name': 'pneumatic',
|
||||||
'label': 'Pneumatic',
|
'label': 'Pneumatic',
|
||||||
'description': 'Download the .strm file to a specific folder.',
|
'description': 'Download the .strm file to a specific folder.',
|
||||||
'wizard': True,
|
|
||||||
'options': [
|
'options': [
|
||||||
{
|
{
|
||||||
'name': 'enabled',
|
'name': 'enabled',
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from couchpotato.core.downloaders.base import Downloader
|
from couchpotato.core.downloaders.base import Downloader
|
||||||
from couchpotato.core.helpers.encoding import tryUrlencode
|
from couchpotato.core.helpers.encoding import tryUrlencode
|
||||||
from couchpotato.core.helpers.variable import cleanHost
|
from couchpotato.core.helpers.variable import cleanHost, mergeDicts
|
||||||
from couchpotato.core.logger import CPLog
|
from couchpotato.core.logger import CPLog
|
||||||
import json
|
import json
|
||||||
import traceback
|
import traceback
|
||||||
@@ -63,106 +63,92 @@ class Sabnzbd(Downloader):
|
|||||||
log.error("Unknown error: " + result[:40])
|
log.error("Unknown error: " + result[:40])
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def getDownloadStatus(self, data = {}, movie = {}):
|
def getAllDownloadStatus(self):
|
||||||
if self.isDisabled(manual = True) or not self.isCorrectType(data.get('type')):
|
if self.isDisabled(manual = False):
|
||||||
return
|
return False
|
||||||
|
|
||||||
nzbname = self.createNzbName(data, movie)
|
log.debug('Checking SABnzbd download status.')
|
||||||
log.info('Checking download status of "%s" at SABnzbd.', nzbname)
|
|
||||||
|
|
||||||
# Go through Queue
|
# Go through Queue
|
||||||
params = {
|
|
||||||
'apikey': self.conf('api_key'),
|
|
||||||
'mode': 'queue',
|
|
||||||
'output': 'json'
|
|
||||||
}
|
|
||||||
url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(params)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sab = self.urlopen(url, timeout = 60, show_error = False)
|
queue = self.call({
|
||||||
|
'mode': 'queue',
|
||||||
|
})
|
||||||
except:
|
except:
|
||||||
log.error('Failed checking status: %s', traceback.format_exc())
|
log.error('Failed getting queue: %s', traceback.format_exc())
|
||||||
return False
|
return False
|
||||||
|
|
||||||
try:
|
|
||||||
history = json.loads(sab)
|
|
||||||
except:
|
|
||||||
log.debug("Result text from SAB: " + sab[:40])
|
|
||||||
log.error('Failed parsing json status: %s', traceback.format_exc())
|
|
||||||
return False
|
|
||||||
|
|
||||||
try:
|
|
||||||
for slot in history['queue']['slots']:
|
|
||||||
log.debug('Found %s in SabNZBd queue, which is %s, with %s left', (slot['filename'], slot['status'], slot['timeleft']))
|
|
||||||
if slot['filename'] == nzbname:
|
|
||||||
return slot['status'].lower()
|
|
||||||
except:
|
|
||||||
log.debug('No items in queue: %s', (traceback.format_exc()))
|
|
||||||
|
|
||||||
# Go through history items
|
# Go through history items
|
||||||
params = {
|
try:
|
||||||
'apikey': self.conf('api_key'),
|
history = self.call({
|
||||||
'mode': 'history',
|
'mode': 'history',
|
||||||
'limit': 15,
|
'limit': 15,
|
||||||
'output': 'json'
|
})
|
||||||
}
|
except:
|
||||||
url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(params)
|
log.error('Failed getting history json: %s', traceback.format_exc())
|
||||||
|
return False
|
||||||
|
|
||||||
|
statuses = []
|
||||||
|
|
||||||
|
# Get busy releases
|
||||||
|
for item in queue.get('slots', []):
|
||||||
|
statuses.append({
|
||||||
|
'id': item['nzo_id'],
|
||||||
|
'name': item['filename'],
|
||||||
|
'status': 'busy',
|
||||||
|
'original_status': item['status'],
|
||||||
|
'timeleft': item['timeleft'] if not queue['paused'] else -1,
|
||||||
|
})
|
||||||
|
|
||||||
|
# Get old releases
|
||||||
|
for item in history.get('slots', []):
|
||||||
|
|
||||||
|
status = 'busy'
|
||||||
|
if item['status'] == 'Failed' or (item['status'] == 'Completed' and item['fail_message'].strip()):
|
||||||
|
status = 'failed'
|
||||||
|
elif item['status'] == 'Completed':
|
||||||
|
status = 'completed'
|
||||||
|
|
||||||
|
statuses.append({
|
||||||
|
'id': item['nzo_id'],
|
||||||
|
'name': item['name'],
|
||||||
|
'status': status,
|
||||||
|
'original_status': item['status'],
|
||||||
|
'timeleft': 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
return statuses
|
||||||
|
|
||||||
|
def removeFailed(self, item):
|
||||||
|
|
||||||
|
if not self.conf('delete_failed', default = True):
|
||||||
|
return False
|
||||||
|
|
||||||
|
log.info('%s failed downloading, deleting...', item['name'])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sab = self.urlopen(url, timeout = 60, show_error = False)
|
self.call({
|
||||||
|
'mode': 'history',
|
||||||
|
'name': 'delete',
|
||||||
|
'del_files': '1',
|
||||||
|
'value': item['id']
|
||||||
|
}, use_json = False)
|
||||||
except:
|
except:
|
||||||
log.error('Failed getting history: %s', traceback.format_exc())
|
log.error('Failed deleting: %s', traceback.format_exc())
|
||||||
return
|
return False
|
||||||
|
|
||||||
try:
|
return True
|
||||||
history = json.loads(sab)
|
|
||||||
except:
|
|
||||||
log.debug("Result text from SAB: " + sab[:40])
|
|
||||||
log.error('Failed parsing history json: %s', traceback.format_exc())
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
def call(self, params, use_json = True):
|
||||||
for slot in history['history']['slots']:
|
|
||||||
log.debug('Found %s in SabNZBd history, which has %s', (slot['name'], slot['status']))
|
|
||||||
if slot['name'] == nzbname:
|
|
||||||
# Note: if post process even if failed is on in SabNZBd, it will complete with a fail message
|
|
||||||
if slot['status'] == 'Failed' or (slot['status'] == 'Completed' and slot['fail_message'].strip()):
|
|
||||||
|
|
||||||
# Delete failed download
|
url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(mergeDicts(params, {
|
||||||
if self.conf('delete_failed', default = True):
|
'apikey': self.conf('api_key'),
|
||||||
|
'output': 'json'
|
||||||
|
}))
|
||||||
|
|
||||||
log.info('%s failed downloading, deleting...', slot['name'])
|
data = self.urlopen(url, timeout = 60, show_error = False)
|
||||||
params = {
|
if use_json:
|
||||||
'apikey': self.conf('api_key'),
|
return json.loads(data)[params['mode']]
|
||||||
'mode': 'history',
|
else:
|
||||||
'name': 'delete',
|
return data
|
||||||
'del_files': '1',
|
|
||||||
'value': slot['nzo_id']
|
|
||||||
}
|
|
||||||
url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(params)
|
|
||||||
|
|
||||||
try:
|
|
||||||
sab = self.urlopen(url, timeout = 60, show_error = False)
|
|
||||||
except:
|
|
||||||
log.error('Failed deleting: %s', traceback.format_exc())
|
|
||||||
return False
|
|
||||||
|
|
||||||
result = sab.strip()
|
|
||||||
if not result:
|
|
||||||
log.error("SABnzbd didn't return anything.")
|
|
||||||
|
|
||||||
log.debug("Result text from SAB: " + result[:40])
|
|
||||||
if result == "ok":
|
|
||||||
log.info('SabNZBd deleted failed release %s successfully.', slot['name'])
|
|
||||||
elif result == "Missing authentication":
|
|
||||||
log.error("Incorrect username/password or API?.")
|
|
||||||
else:
|
|
||||||
log.error("Unknown error: " + result[:40])
|
|
||||||
|
|
||||||
return 'failed'
|
|
||||||
else:
|
|
||||||
return slot['status'].lower()
|
|
||||||
except:
|
|
||||||
log.debug('No items in history: %s', (traceback.format_exc()))
|
|
||||||
|
|
||||||
return 'not_found'
|
|
||||||
|
|||||||
+22
-41
@@ -46,49 +46,30 @@ def fireEvent(name, *args, **kwargs):
|
|||||||
#log.debug('Firing event %s', name)
|
#log.debug('Firing event %s', name)
|
||||||
try:
|
try:
|
||||||
|
|
||||||
# Fire after event
|
options = {
|
||||||
is_after_event = False
|
'is_after_event': False, # Fire after event
|
||||||
try:
|
'on_complete': False, # onComplete event
|
||||||
del kwargs['is_after_event']
|
'single': False, # Return single handler
|
||||||
is_after_event = True
|
'merge': False, # Merge items
|
||||||
except: pass
|
'in_order': False, # Fire them in specific order, waits for the other to finish
|
||||||
|
}
|
||||||
|
|
||||||
# onComplete event
|
# Do options
|
||||||
on_complete = False
|
for x in options:
|
||||||
try:
|
try:
|
||||||
on_complete = kwargs['on_complete']
|
val = kwargs[x]
|
||||||
del kwargs['on_complete']
|
del kwargs[x]
|
||||||
except: pass
|
options[x] = val
|
||||||
|
except: pass
|
||||||
# Return single handler
|
|
||||||
single = False
|
|
||||||
try:
|
|
||||||
del kwargs['single']
|
|
||||||
single = True
|
|
||||||
except: pass
|
|
||||||
|
|
||||||
# Merge items
|
|
||||||
merge = False
|
|
||||||
try:
|
|
||||||
del kwargs['merge']
|
|
||||||
merge = True
|
|
||||||
except: pass
|
|
||||||
|
|
||||||
# Merge items
|
|
||||||
in_order = False
|
|
||||||
try:
|
|
||||||
del kwargs['in_order']
|
|
||||||
in_order = True
|
|
||||||
except: pass
|
|
||||||
|
|
||||||
e = events[name]
|
e = events[name]
|
||||||
if not in_order: e.lock.acquire()
|
if not options['in_order']: e.lock.acquire()
|
||||||
e.asynchronous = False
|
e.asynchronous = False
|
||||||
e.in_order = in_order
|
e.in_order = options['in_order']
|
||||||
result = e(*args, **kwargs)
|
result = e(*args, **kwargs)
|
||||||
if not in_order: e.lock.release()
|
if not options['in_order']: e.lock.release()
|
||||||
|
|
||||||
if single and not merge:
|
if options['single'] and not options['merge']:
|
||||||
results = None
|
results = None
|
||||||
|
|
||||||
# Loop over results, stop when first not None result is found.
|
# Loop over results, stop when first not None result is found.
|
||||||
@@ -112,7 +93,7 @@ def fireEvent(name, *args, **kwargs):
|
|||||||
errorHandler(r[1])
|
errorHandler(r[1])
|
||||||
|
|
||||||
# Merge
|
# Merge
|
||||||
if merge and len(results) > 0:
|
if options['merge'] and len(results) > 0:
|
||||||
# Dict
|
# Dict
|
||||||
if type(results[0]) == dict:
|
if type(results[0]) == dict:
|
||||||
merged = {}
|
merged = {}
|
||||||
@@ -133,11 +114,11 @@ def fireEvent(name, *args, **kwargs):
|
|||||||
log.debug('Return modified results for %s', name)
|
log.debug('Return modified results for %s', name)
|
||||||
results = modified_results
|
results = modified_results
|
||||||
|
|
||||||
if not is_after_event:
|
if not options['is_after_event']:
|
||||||
fireEvent('%s.after' % name, is_after_event = True)
|
fireEvent('%s.after' % name, is_after_event = True)
|
||||||
|
|
||||||
if on_complete:
|
if options['on_complete']:
|
||||||
on_complete()
|
options['on_complete']()
|
||||||
|
|
||||||
return results
|
return results
|
||||||
except KeyError, e:
|
except KeyError, e:
|
||||||
|
|||||||
@@ -118,8 +118,16 @@ def getTitle(library_dict):
|
|||||||
try:
|
try:
|
||||||
return library_dict['titles'][0]['title']
|
return library_dict['titles'][0]['title']
|
||||||
except:
|
except:
|
||||||
log.error('Could not get title for %s', library_dict['identifier'])
|
try:
|
||||||
return None
|
for title in library_dict.titles:
|
||||||
|
if title.default:
|
||||||
|
return title.title
|
||||||
|
except:
|
||||||
|
log.error('Could not get title for %s', library_dict.identifier)
|
||||||
|
return None
|
||||||
|
|
||||||
|
log.error('Could not get title for %s', library_dict['identifier'])
|
||||||
|
return None
|
||||||
except:
|
except:
|
||||||
log.error('Could not get title for library item: %s', library_dict)
|
log.error('Could not get title for library item: %s', library_dict)
|
||||||
return None
|
return None
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import traceback
|
|||||||
class CPLog(object):
|
class CPLog(object):
|
||||||
|
|
||||||
context = ''
|
context = ''
|
||||||
replace_private = ['api', 'apikey', 'api_key', 'password', 'username', 'h']
|
replace_private = ['api', 'apikey', 'api_key', 'password', 'username', 'h', 'uid', 'key']
|
||||||
|
|
||||||
def __init__(self, context = ''):
|
def __init__(self, context = ''):
|
||||||
if context.endswith('.main'):
|
if context.endswith('.main'):
|
||||||
|
|||||||
@@ -79,7 +79,6 @@ class CoreNotifier(Notification):
|
|||||||
q.update({Notif.read: True})
|
q.update({Notif.read: True})
|
||||||
|
|
||||||
db.commit()
|
db.commit()
|
||||||
#db.close()
|
|
||||||
|
|
||||||
return jsonified({
|
return jsonified({
|
||||||
'success': True
|
'success': True
|
||||||
@@ -107,7 +106,6 @@ class CoreNotifier(Notification):
|
|||||||
ndict['type'] = 'notification'
|
ndict['type'] = 'notification'
|
||||||
notifications.append(ndict)
|
notifications.append(ndict)
|
||||||
|
|
||||||
#db.close()
|
|
||||||
return jsonified({
|
return jsonified({
|
||||||
'success': True,
|
'success': True,
|
||||||
'empty': len(notifications) == 0,
|
'empty': len(notifications) == 0,
|
||||||
@@ -133,7 +131,6 @@ class CoreNotifier(Notification):
|
|||||||
|
|
||||||
self.frontend(type = listener, data = data)
|
self.frontend(type = listener, data = data)
|
||||||
|
|
||||||
#db.close()
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def frontend(self, type = 'notification', data = {}, message = None):
|
def frontend(self, type = 'notification', data = {}, message = None):
|
||||||
|
|||||||
@@ -5,13 +5,12 @@ def start():
|
|||||||
|
|
||||||
config = [{
|
config = [{
|
||||||
'name': 'automation',
|
'name': 'automation',
|
||||||
'order': 30,
|
'order': 101,
|
||||||
'groups': [
|
'groups': [
|
||||||
{
|
{
|
||||||
'tab': 'automation',
|
'tab': 'automation',
|
||||||
'name': 'automation',
|
'name': 'automation',
|
||||||
'label': 'Automation',
|
'label': 'Minimal movie requirements',
|
||||||
'description': 'Minimal movie requirements',
|
|
||||||
'options': [
|
'options': [
|
||||||
{
|
{
|
||||||
'name': 'year',
|
'name': 'year',
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
from StringIO import StringIO
|
from StringIO import StringIO
|
||||||
from couchpotato import addView
|
from couchpotato import addView
|
||||||
from couchpotato.core.event import fireEvent, addEvent
|
from couchpotato.core.event import fireEvent, addEvent
|
||||||
from couchpotato.core.helpers.encoding import tryUrlencode, simplifyString, ss
|
from couchpotato.core.helpers.encoding import tryUrlencode, simplifyString, ss, \
|
||||||
|
toSafeString
|
||||||
from couchpotato.core.helpers.variable import getExt
|
from couchpotato.core.helpers.variable import getExt
|
||||||
from couchpotato.core.logger import CPLog
|
from couchpotato.core.logger import CPLog
|
||||||
from couchpotato.environment import Env
|
from couchpotato.environment import Env
|
||||||
@@ -245,6 +246,22 @@ class Plugin(object):
|
|||||||
Env.get('cache').set(cache_key, value, timeout)
|
Env.get('cache').set(cache_key, value, timeout)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
def createNzbName(self, data, movie):
|
||||||
|
tag = self.cpTag(movie)
|
||||||
|
return '%s%s' % (toSafeString(data.get('name')[:127 - len(tag)]), tag)
|
||||||
|
|
||||||
|
def createFileName(self, data, filedata, movie):
|
||||||
|
name = os.path.join(self.createNzbName(data, movie))
|
||||||
|
if data.get('type') == 'nzb' and 'DOCTYPE nzb' not in filedata and '</nzb>' not in filedata:
|
||||||
|
return '%s.%s' % (name, 'rar')
|
||||||
|
return '%s.%s' % (name, data.get('type'))
|
||||||
|
|
||||||
|
def cpTag(self, movie):
|
||||||
|
if Env.setting('enabled', 'renamer'):
|
||||||
|
return '.cp(' + movie['library'].get('identifier') + ')' if movie['library'].get('identifier') else ''
|
||||||
|
|
||||||
|
return ''
|
||||||
|
|
||||||
def isDisabled(self):
|
def isDisabled(self):
|
||||||
return not self.isEnabled()
|
return not self.isEnabled()
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ class FileBrowser(Plugin):
|
|||||||
},
|
},
|
||||||
'return': {'type': 'object', 'example': """{
|
'return': {'type': 'object', 'example': """{
|
||||||
'is_root': bool, //is top most folder
|
'is_root': bool, //is top most folder
|
||||||
|
'parent': string, //parent folder of requested path
|
||||||
|
'home': string, //user home folder
|
||||||
'empty': bool, //directory is empty
|
'empty': bool, //directory is empty
|
||||||
'dirs': array, //directory names
|
'dirs': array, //directory names
|
||||||
}"""}
|
}"""}
|
||||||
@@ -64,14 +66,35 @@ class FileBrowser(Plugin):
|
|||||||
|
|
||||||
path = getParam('path', '/')
|
path = getParam('path', '/')
|
||||||
|
|
||||||
|
# Set proper home dir for some systems
|
||||||
|
try:
|
||||||
|
import pwd
|
||||||
|
os.environ['HOME'] = pwd.getpwuid(os.geteuid()).pw_dir
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
home = os.path.expanduser('~')
|
||||||
|
|
||||||
|
if not path:
|
||||||
|
path = home
|
||||||
|
|
||||||
try:
|
try:
|
||||||
dirs = self.getDirectories(path = path, show_hidden = getParam('show_hidden', True))
|
dirs = self.getDirectories(path = path, show_hidden = getParam('show_hidden', True))
|
||||||
except:
|
except:
|
||||||
dirs = []
|
dirs = []
|
||||||
|
|
||||||
|
parent = os.path.dirname(path.rstrip(os.path.sep))
|
||||||
|
if parent == path.rstrip(os.path.sep):
|
||||||
|
parent = '/'
|
||||||
|
elif parent != '/' and parent[-2:] != ':\\':
|
||||||
|
parent += os.path.sep
|
||||||
|
|
||||||
return jsonified({
|
return jsonified({
|
||||||
'is_root': path == '/' or not path,
|
'is_root': path == '/',
|
||||||
'empty': len(dirs) == 0,
|
'empty': len(dirs) == 0,
|
||||||
|
'parent': parent,
|
||||||
|
'home': home + os.path.sep,
|
||||||
|
'platform': os.name,
|
||||||
'dirs': dirs,
|
'dirs': dirs,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -109,7 +109,6 @@ class FileManager(Plugin):
|
|||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
type_dict = ft.to_dict()
|
type_dict = ft.to_dict()
|
||||||
#db.close()
|
|
||||||
return type_dict
|
return type_dict
|
||||||
|
|
||||||
def getTypes(self):
|
def getTypes(self):
|
||||||
@@ -122,5 +121,4 @@ class FileManager(Plugin):
|
|||||||
for type_object in results:
|
for type_object in results:
|
||||||
types.append(type_object.to_dict())
|
types.append(type_object.to_dict())
|
||||||
|
|
||||||
#db.close()
|
|
||||||
return types
|
return types
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ class LibraryPlugin(Plugin):
|
|||||||
|
|
||||||
library_dict = l.to_dict(self.default_dict)
|
library_dict = l.to_dict(self.default_dict)
|
||||||
|
|
||||||
#db.close()
|
|
||||||
return library_dict
|
return library_dict
|
||||||
|
|
||||||
def update(self, identifier, default_title = '', force = False):
|
def update(self, identifier, default_title = '', force = False):
|
||||||
|
|||||||
@@ -431,9 +431,11 @@ class MoviePlugin(Plugin):
|
|||||||
|
|
||||||
movie = db.query(Movie).filter_by(id = movie_id).first()
|
movie = db.query(Movie).filter_by(id = movie_id).first()
|
||||||
if movie:
|
if movie:
|
||||||
|
deleted = False
|
||||||
if delete_from == 'all':
|
if delete_from == 'all':
|
||||||
db.delete(movie)
|
db.delete(movie)
|
||||||
db.commit()
|
db.commit()
|
||||||
|
deleted = True
|
||||||
else:
|
else:
|
||||||
done_status = fireEvent('status.get', 'done', single = True)
|
done_status = fireEvent('status.get', 'done', single = True)
|
||||||
|
|
||||||
@@ -456,6 +458,7 @@ class MoviePlugin(Plugin):
|
|||||||
if total_releases == total_deleted:
|
if total_releases == total_deleted:
|
||||||
db.delete(movie)
|
db.delete(movie)
|
||||||
db.commit()
|
db.commit()
|
||||||
|
deleted = True
|
||||||
elif new_movie_status:
|
elif new_movie_status:
|
||||||
new_status = fireEvent('status.get', new_movie_status, single = True)
|
new_status = fireEvent('status.get', new_movie_status, single = True)
|
||||||
movie.profile_id = None
|
movie.profile_id = None
|
||||||
@@ -464,6 +467,9 @@ class MoviePlugin(Plugin):
|
|||||||
else:
|
else:
|
||||||
fireEvent('movie.restatus', movie.id, single = True)
|
fireEvent('movie.restatus', movie.id, single = True)
|
||||||
|
|
||||||
|
if deleted:
|
||||||
|
fireEvent('notify.frontend', type = 'movie.deleted', data = movie.to_dict())
|
||||||
|
|
||||||
#db.close()
|
#db.close()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,17 @@ var MovieList = new Class({
|
|||||||
|
|
||||||
if(options.add_new)
|
if(options.add_new)
|
||||||
App.addEvent('movie.added', self.movieAdded.bind(self))
|
App.addEvent('movie.added', self.movieAdded.bind(self))
|
||||||
|
|
||||||
|
App.addEvent('movie.deleted', self.movieDeleted.bind(self))
|
||||||
|
},
|
||||||
|
|
||||||
|
movieDeleted: function(notification){
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if(!self.movies_added[notification.data.id])
|
||||||
|
self.movies_added[notification.data.id].destroy();
|
||||||
|
|
||||||
|
self.checkIfEmpty();
|
||||||
},
|
},
|
||||||
|
|
||||||
movieAdded: function(notification){
|
movieAdded: function(notification){
|
||||||
@@ -43,6 +54,8 @@ var MovieList = new Class({
|
|||||||
|
|
||||||
if(!self.movies_added[notification.data.id])
|
if(!self.movies_added[notification.data.id])
|
||||||
self.createMovie(notification.data, 'top');
|
self.createMovie(notification.data, 'top');
|
||||||
|
|
||||||
|
self.checkIfEmpty();
|
||||||
},
|
},
|
||||||
|
|
||||||
create: function(){
|
create: function(){
|
||||||
@@ -309,6 +322,8 @@ var MovieList = new Class({
|
|||||||
|
|
||||||
erase_movies.each(function(movie){
|
erase_movies.each(function(movie){
|
||||||
self.movies.erase(movie);
|
self.movies.erase(movie);
|
||||||
|
|
||||||
|
movie.destroy()
|
||||||
});
|
});
|
||||||
|
|
||||||
self.calculateSelected();
|
self.calculateSelected();
|
||||||
@@ -458,6 +473,8 @@ var MovieList = new Class({
|
|||||||
self.addMovies(json.movies, json.total);
|
self.addMovies(json.movies, json.total);
|
||||||
self.load_more.set('text', 'load more movies');
|
self.load_more.set('text', 'load more movies');
|
||||||
if(self.scrollspy) self.scrollspy.start();
|
if(self.scrollspy) self.scrollspy.start();
|
||||||
|
|
||||||
|
self.checkIfEmpty()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -475,6 +492,28 @@ var MovieList = new Class({
|
|||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
checkIfEmpty: function(){
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var is_empty = self.movies.length == 0;
|
||||||
|
|
||||||
|
if(is_empty && self.options.on_empty_element){
|
||||||
|
self.el.grab(self.options.on_empty_element);
|
||||||
|
|
||||||
|
if(self.navigation)
|
||||||
|
self.navigation.hide();
|
||||||
|
|
||||||
|
self.empty_element = self.options.on_empty_element;
|
||||||
|
}
|
||||||
|
else if(self.empty_element){
|
||||||
|
self.empty_element.destroy();
|
||||||
|
|
||||||
|
if(self.navigation)
|
||||||
|
self.navigation.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
toElement: function(){
|
toElement: function(){
|
||||||
return this.el;
|
return this.el;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -534,5 +534,5 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.movies .alph_nav .more_menu > a {
|
.movies .alph_nav .more_menu > a {
|
||||||
background-position: center -157px;
|
background-position: center -158px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,14 +16,41 @@ var Movie = new Class({
|
|||||||
self.profile = Quality.getProfile(data.profile_id) || {};
|
self.profile = Quality.getProfile(data.profile_id) || {};
|
||||||
self.parent(self, options);
|
self.parent(self, options);
|
||||||
|
|
||||||
App.addEvent('movie.update.'+data.id, self.update.bind(self));
|
self.addEvents();
|
||||||
|
},
|
||||||
|
|
||||||
|
addEvents: function(){
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
App.addEvent('movie.update.'+self.data.id, self.update.bind(self));
|
||||||
|
|
||||||
['movie.busy', 'searcher.started'].each(function(listener){
|
['movie.busy', 'searcher.started'].each(function(listener){
|
||||||
App.addEvent(listener+'.'+data.id, function(notification){
|
App.addEvent(listener+'.'+self.data.id, function(notification){
|
||||||
if(notification.data)
|
if(notification.data)
|
||||||
self.busy(true)
|
self.busy(true)
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
|
App.addEvent('searcher.ended.'+self.data.id, function(notification){
|
||||||
|
if(notification.data)
|
||||||
|
self.busy(false)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function(){
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self.el.destroy();
|
||||||
|
delete self.list.movies_added[self.get('id')];
|
||||||
|
self.list.movies.erase(self)
|
||||||
|
|
||||||
|
self.list.checkIfEmpty();
|
||||||
|
|
||||||
|
// Remove events
|
||||||
|
App.removeEvents('movie.update.'+self.data.id);
|
||||||
|
['movie.busy', 'searcher.started'].each(function(listener){
|
||||||
|
App.removeEvents(listener+'.'+self.data.id);
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
busy: function(set_busy){
|
busy: function(set_busy){
|
||||||
@@ -359,7 +386,7 @@ var ReleaseAction = new Class({
|
|||||||
|
|
||||||
var status = Status.get(release.status_id);
|
var status = Status.get(release.status_id);
|
||||||
|
|
||||||
if((status.identifier == 'ignored' || status.identifier == 'failed') || (!self.next_release && status.identifier == 'available')){
|
if((self.next_release && (status.identifier == 'ignored' || status.identifier == 'failed')) || (!self.next_release && status.identifier == 'available')){
|
||||||
self.hide_on_click = false;
|
self.hide_on_click = false;
|
||||||
self.show();
|
self.show();
|
||||||
buttons_done = true;
|
buttons_done = true;
|
||||||
@@ -397,19 +424,11 @@ var ReleaseAction = new Class({
|
|||||||
var status = Status.get(release.status_id),
|
var status = Status.get(release.status_id),
|
||||||
quality = Quality.getProfile(release.quality_id) || {},
|
quality = Quality.getProfile(release.quality_id) || {},
|
||||||
info = release.info;
|
info = release.info;
|
||||||
|
release.status = status;
|
||||||
if( status.identifier == 'ignored' || status.identifier == 'failed'){
|
|
||||||
self.last_release = release;
|
|
||||||
}
|
|
||||||
else if(!self.next_release && status.identifier == 'available'){
|
|
||||||
self.next_release = release;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create release
|
// Create release
|
||||||
new Element('div', {
|
new Element('div', {
|
||||||
'class': 'item '+status.identifier +
|
'class': 'item '+status.identifier,
|
||||||
(self.next_release && self.next_release.id == release.id ? ' next_release' : '') +
|
|
||||||
(self.last_release && self.last_release.id == release.id ? ' last_release' : ''),
|
|
||||||
'id': 'release_'+release.id
|
'id': 'release_'+release.id
|
||||||
}).adopt(
|
}).adopt(
|
||||||
new Element('span.name', {'text': self.get(release, 'name'), 'title': self.get(release, 'name')}),
|
new Element('span.name', {'text': self.get(release, 'name'), 'title': self.get(release, 'name')}),
|
||||||
@@ -442,11 +461,27 @@ var ReleaseAction = new Class({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
).inject(self.release_container)
|
).inject(self.release_container)
|
||||||
|
|
||||||
|
if(status.identifier == 'ignored' || status.identifier == 'failed' || status.identifier == 'snatched'){
|
||||||
|
if(!self.last_release || (self.last_release && self.last_release.status.identifier != 'snatched' && status.identifier == 'snatched'))
|
||||||
|
self.last_release = release;
|
||||||
|
}
|
||||||
|
else if(!self.next_release && status.identifier == 'available'){
|
||||||
|
self.next_release = release;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(self.last_release){
|
||||||
|
self.release_container.getElement('#release_'+self.last_release.id).addClass('last_release');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(self.next_release){
|
||||||
|
self.release_container.getElement('#release_'+self.next_release.id).addClass('next_release');
|
||||||
|
}
|
||||||
|
|
||||||
self.trynext_container.adopt(
|
self.trynext_container.adopt(
|
||||||
new Element('span.or', {
|
new Element('span.or', {
|
||||||
'text': 'Download'
|
'text': 'This movie is snatched, if anything went wrong, download'
|
||||||
}),
|
}),
|
||||||
self.last_release ? new Element('a.button.orange', {
|
self.last_release ? new Element('a.button.orange', {
|
||||||
'text': 'the same release again',
|
'text': 'the same release again',
|
||||||
@@ -455,7 +490,7 @@ var ReleaseAction = new Class({
|
|||||||
}
|
}
|
||||||
}) : null,
|
}) : null,
|
||||||
self.next_release && self.last_release ? new Element('span.or', {
|
self.next_release && self.last_release ? new Element('span.or', {
|
||||||
'text': 'or'
|
'text': ','
|
||||||
}) : null,
|
}) : null,
|
||||||
self.next_release ? [new Element('a.button.green', {
|
self.next_release ? [new Element('a.button.green', {
|
||||||
'text': self.last_release ? 'another release' : 'the best release',
|
'text': self.last_release ? 'another release' : 'the best release',
|
||||||
|
|||||||
@@ -339,7 +339,7 @@ Block.Search.Item = new Class({
|
|||||||
'height': null,
|
'height': null,
|
||||||
'width': null
|
'width': null
|
||||||
}) : null,
|
}) : null,
|
||||||
self.info.in_wanted ? new Element('span.in_wanted', {
|
self.info.in_wanted && self.info.in_wanted.profile ? new Element('span.in_wanted', {
|
||||||
'text': 'Already in wanted list: ' + self.info.in_wanted.profile.label
|
'text': 'Already in wanted list: ' + self.info.in_wanted.profile.label
|
||||||
}) : (in_library ? new Element('span.in_library', {
|
}) : (in_library ? new Element('span.in_library', {
|
||||||
'text': 'Already in library: ' + in_library.join(', ')
|
'text': 'Already in library: ' + in_library.join(', ')
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ class ProfilePlugin(Plugin):
|
|||||||
for profile in profiles:
|
for profile in profiles:
|
||||||
temp.append(profile.to_dict(self.to_dict))
|
temp.append(profile.to_dict(self.to_dict))
|
||||||
|
|
||||||
#db.close()
|
|
||||||
return temp
|
return temp
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
@@ -84,7 +83,6 @@ class ProfilePlugin(Plugin):
|
|||||||
|
|
||||||
profile_dict = p.to_dict(self.to_dict)
|
profile_dict = p.to_dict(self.to_dict)
|
||||||
|
|
||||||
#db.close()
|
|
||||||
return jsonified({
|
return jsonified({
|
||||||
'success': True,
|
'success': True,
|
||||||
'profile': profile_dict
|
'profile': profile_dict
|
||||||
@@ -95,7 +93,6 @@ class ProfilePlugin(Plugin):
|
|||||||
db = get_session()
|
db = get_session()
|
||||||
default = db.query(Profile).first()
|
default = db.query(Profile).first()
|
||||||
default_dict = default.to_dict(self.to_dict)
|
default_dict = default.to_dict(self.to_dict)
|
||||||
#db.close()
|
|
||||||
|
|
||||||
return default_dict
|
return default_dict
|
||||||
|
|
||||||
@@ -113,7 +110,6 @@ class ProfilePlugin(Plugin):
|
|||||||
order += 1
|
order += 1
|
||||||
|
|
||||||
db.commit()
|
db.commit()
|
||||||
#db.close()
|
|
||||||
|
|
||||||
return jsonified({
|
return jsonified({
|
||||||
'success': True
|
'success': True
|
||||||
@@ -137,8 +133,6 @@ class ProfilePlugin(Plugin):
|
|||||||
except Exception, e:
|
except Exception, e:
|
||||||
message = log.error('Failed deleting Profile: %s', e)
|
message = log.error('Failed deleting Profile: %s', e)
|
||||||
|
|
||||||
#db.close()
|
|
||||||
|
|
||||||
return jsonified({
|
return jsonified({
|
||||||
'success': success,
|
'success': success,
|
||||||
'message': message
|
'message': message
|
||||||
@@ -181,10 +175,10 @@ class ProfilePlugin(Plugin):
|
|||||||
)
|
)
|
||||||
p.types.append(profile_type)
|
p.types.append(profile_type)
|
||||||
|
|
||||||
db.commit()
|
|
||||||
quality_order += 1
|
quality_order += 1
|
||||||
|
|
||||||
order += 1
|
order += 1
|
||||||
|
|
||||||
#db.close()
|
db.commit()
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -86,7 +86,10 @@ var Profile = new Class({
|
|||||||
},
|
},
|
||||||
'onComplete': function(json){
|
'onComplete': function(json){
|
||||||
if(json.success){
|
if(json.success){
|
||||||
self.data = json.profile
|
self.data = json.profile;
|
||||||
|
self.type_container.getElement('li:first-child input[type=checkbox]')
|
||||||
|
.set('checked', true)
|
||||||
|
.getParent().addClass('checked');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -239,9 +242,17 @@ Profile.Type = new Class({
|
|||||||
),
|
),
|
||||||
new Element('span.finish').adopt(
|
new Element('span.finish').adopt(
|
||||||
self.finish = new Element('input.inlay.finish[type=checkbox]', {
|
self.finish = new Element('input.inlay.finish[type=checkbox]', {
|
||||||
'checked': data.finish,
|
'checked': data.finish !== undefined ? data.finish : 1,
|
||||||
'events': {
|
'events': {
|
||||||
'change': self.fireEvent.bind(self, 'change')
|
'change': function(e){
|
||||||
|
if(self.el == self.el.getParent().getElement(':first-child')){
|
||||||
|
self.finish_class.check();
|
||||||
|
alert('Top quality always finishes the search')
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.fireEvent('change');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
@@ -255,7 +266,7 @@ Profile.Type = new Class({
|
|||||||
|
|
||||||
self.el[self.data.quality_id > 0 ? 'removeClass' : 'addClass']('is_empty');
|
self.el[self.data.quality_id > 0 ? 'removeClass' : 'addClass']('is_empty');
|
||||||
|
|
||||||
new Form.Check(self.finish);
|
self.finish_class = new Form.Check(self.finish);
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from couchpotato.core.plugins.base import Plugin
|
|||||||
from couchpotato.core.settings.model import Quality, Profile, ProfileType
|
from couchpotato.core.settings.model import Quality, Profile, ProfileType
|
||||||
import os.path
|
import os.path
|
||||||
import re
|
import re
|
||||||
|
import time
|
||||||
|
|
||||||
log = CPLog(__name__)
|
log = CPLog(__name__)
|
||||||
|
|
||||||
@@ -68,7 +69,6 @@ class QualityPlugin(Plugin):
|
|||||||
q = mergeDicts(self.getQuality(quality.identifier), quality.to_dict())
|
q = mergeDicts(self.getQuality(quality.identifier), quality.to_dict())
|
||||||
temp.append(q)
|
temp.append(q)
|
||||||
|
|
||||||
#db.close()
|
|
||||||
return temp
|
return temp
|
||||||
|
|
||||||
def single(self, identifier = ''):
|
def single(self, identifier = ''):
|
||||||
@@ -80,7 +80,6 @@ class QualityPlugin(Plugin):
|
|||||||
if quality:
|
if quality:
|
||||||
quality_dict = dict(self.getQuality(quality.identifier), **quality.to_dict())
|
quality_dict = dict(self.getQuality(quality.identifier), **quality.to_dict())
|
||||||
|
|
||||||
#db.close()
|
|
||||||
return quality_dict
|
return quality_dict
|
||||||
|
|
||||||
def getQuality(self, identifier):
|
def getQuality(self, identifier):
|
||||||
@@ -100,7 +99,6 @@ class QualityPlugin(Plugin):
|
|||||||
setattr(quality, params.get('value_type'), params.get('value'))
|
setattr(quality, params.get('value_type'), params.get('value'))
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
#db.close()
|
|
||||||
return jsonified({
|
return jsonified({
|
||||||
'success': True
|
'success': True
|
||||||
})
|
})
|
||||||
@@ -113,46 +111,48 @@ class QualityPlugin(Plugin):
|
|||||||
for q in self.qualities:
|
for q in self.qualities:
|
||||||
|
|
||||||
# Create quality
|
# Create quality
|
||||||
quality = db.query(Quality).filter_by(identifier = q.get('identifier')).first()
|
qual = db.query(Quality).filter_by(identifier = q.get('identifier')).first()
|
||||||
|
|
||||||
if not quality:
|
if not qual:
|
||||||
log.info('Creating quality: %s', q.get('label'))
|
log.info('Creating quality: %s', q.get('label'))
|
||||||
quality = Quality()
|
qual = Quality()
|
||||||
db.add(quality)
|
qual.order = order
|
||||||
|
qual.identifier = q.get('identifier')
|
||||||
|
qual.label = toUnicode(q.get('label'))
|
||||||
|
qual.size_min, qual.size_max = q.get('size')
|
||||||
|
|
||||||
quality.order = order
|
db.add(qual)
|
||||||
quality.identifier = q.get('identifier')
|
|
||||||
quality.label = toUnicode(q.get('label'))
|
|
||||||
quality.size_min, quality.size_max = q.get('size')
|
|
||||||
|
|
||||||
# Create single quality profile
|
# Create single quality profile
|
||||||
profile = db.query(Profile).filter(
|
prof = db.query(Profile).filter(
|
||||||
Profile.core == True
|
Profile.core == True
|
||||||
).filter(
|
).filter(
|
||||||
Profile.types.any(quality = quality)
|
Profile.types.any(quality = qual)
|
||||||
).all()
|
).all()
|
||||||
|
|
||||||
if not profile:
|
if not prof:
|
||||||
log.info('Creating profile: %s', q.get('label'))
|
log.info('Creating profile: %s', q.get('label'))
|
||||||
profile = Profile(
|
prof = Profile(
|
||||||
core = True,
|
core = True,
|
||||||
label = toUnicode(quality.label),
|
label = toUnicode(qual.label),
|
||||||
order = order
|
order = order
|
||||||
)
|
)
|
||||||
db.add(profile)
|
db.add(prof)
|
||||||
|
|
||||||
profile_type = ProfileType(
|
profile_type = ProfileType(
|
||||||
quality = quality,
|
quality = qual,
|
||||||
profile = profile,
|
profile = prof,
|
||||||
finish = True,
|
finish = True,
|
||||||
order = 0
|
order = 0
|
||||||
)
|
)
|
||||||
profile.types.append(profile_type)
|
prof.types.append(profile_type)
|
||||||
|
|
||||||
order += 1
|
order += 1
|
||||||
db.commit()
|
|
||||||
|
|
||||||
#db.close()
|
db.commit()
|
||||||
|
|
||||||
|
time.sleep(0.3) # Wait a moment
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def guess(self, files, extra = {}):
|
def guess(self, files, extra = {}):
|
||||||
|
|||||||
@@ -88,8 +88,6 @@ class Release(Plugin):
|
|||||||
|
|
||||||
fireEvent('movie.restatus', movie.id)
|
fireEvent('movie.restatus', movie.id)
|
||||||
|
|
||||||
#db.close()
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
@@ -108,7 +106,6 @@ class Release(Plugin):
|
|||||||
|
|
||||||
release_id = getParam('id')
|
release_id = getParam('id')
|
||||||
|
|
||||||
#db.close()
|
|
||||||
return jsonified({
|
return jsonified({
|
||||||
'success': self.delete(release_id)
|
'success': self.delete(release_id)
|
||||||
})
|
})
|
||||||
@@ -152,7 +149,6 @@ class Release(Plugin):
|
|||||||
rel.status_id = available_status.get('id') if rel.status_id is ignored_status.get('id') else ignored_status.get('id')
|
rel.status_id = available_status.get('id') if rel.status_id is ignored_status.get('id') else ignored_status.get('id')
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
#db.close()
|
|
||||||
return jsonified({
|
return jsonified({
|
||||||
'success': True
|
'success': True
|
||||||
})
|
})
|
||||||
@@ -161,6 +157,7 @@ class Release(Plugin):
|
|||||||
|
|
||||||
db = get_session()
|
db = get_session()
|
||||||
id = getParam('id')
|
id = getParam('id')
|
||||||
|
status_snatched = fireEvent('status.add', 'snatched', single = True)
|
||||||
|
|
||||||
rel = db.query(Relea).filter_by(id = id).first()
|
rel = db.query(Relea).filter_by(id = id).first()
|
||||||
if rel:
|
if rel:
|
||||||
@@ -181,14 +178,16 @@ class Release(Plugin):
|
|||||||
'files': {}
|
'files': {}
|
||||||
}), manual = True, single = True)
|
}), manual = True, single = True)
|
||||||
|
|
||||||
#db.close()
|
if success:
|
||||||
|
rel.status_id = status_snatched.get('id')
|
||||||
|
db.commit()
|
||||||
|
|
||||||
return jsonified({
|
return jsonified({
|
||||||
'success': success
|
'success': success
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
log.error('Couldn\'t find release with id: %s', id)
|
log.error('Couldn\'t find release with id: %s', id)
|
||||||
|
|
||||||
#db.close()
|
|
||||||
return jsonified({
|
return jsonified({
|
||||||
'success': False
|
'success': False
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ log = CPLog(__name__)
|
|||||||
class Renamer(Plugin):
|
class Renamer(Plugin):
|
||||||
|
|
||||||
renaming_started = False
|
renaming_started = False
|
||||||
|
checking_snatched = False
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
@@ -33,6 +34,7 @@ class Renamer(Plugin):
|
|||||||
addEvent('app.load', self.scan)
|
addEvent('app.load', self.scan)
|
||||||
|
|
||||||
fireEvent('schedule.interval', 'renamer.check_snatched', self.checkSnatched, minutes = self.conf('run_every'))
|
fireEvent('schedule.interval', 'renamer.check_snatched', self.checkSnatched, minutes = self.conf('run_every'))
|
||||||
|
fireEvent('schedule.interval', 'renamer.check_snatched_forced', self.scan, hours = 2)
|
||||||
|
|
||||||
def scanView(self):
|
def scanView(self):
|
||||||
|
|
||||||
@@ -386,7 +388,6 @@ class Renamer(Plugin):
|
|||||||
if self.shuttingDown():
|
if self.shuttingDown():
|
||||||
break
|
break
|
||||||
|
|
||||||
#db.close()
|
|
||||||
self.renaming_started = False
|
self.renaming_started = False
|
||||||
|
|
||||||
def getRenameExtras(self, extra_type = '', replacements = {}, folder_name = '', file_name = '', destination = '', group = {}, current_file = ''):
|
def getRenameExtras(self, extra_type = '', replacements = {}, folder_name = '', file_name = '', destination = '', group = {}, current_file = ''):
|
||||||
@@ -495,6 +496,11 @@ class Renamer(Plugin):
|
|||||||
loge('Couldn\'t remove empty directory %s: %s', (folder, traceback.format_exc()))
|
loge('Couldn\'t remove empty directory %s: %s', (folder, traceback.format_exc()))
|
||||||
|
|
||||||
def checkSnatched(self):
|
def checkSnatched(self):
|
||||||
|
if self.checking_snatched:
|
||||||
|
log.debug('Already checking snatched')
|
||||||
|
|
||||||
|
self.checking_snatched = True
|
||||||
|
|
||||||
snatched_status = fireEvent('status.get', 'snatched', single = True)
|
snatched_status = fireEvent('status.get', 'snatched', single = True)
|
||||||
ignored_status = fireEvent('status.get', 'ignored', single = True)
|
ignored_status = fireEvent('status.get', 'ignored', single = True)
|
||||||
failed_status = fireEvent('status.get', 'failed', single = True)
|
failed_status = fireEvent('status.get', 'failed', single = True)
|
||||||
@@ -504,57 +510,74 @@ class Renamer(Plugin):
|
|||||||
db = get_session()
|
db = get_session()
|
||||||
rels = db.query(Release).filter_by(status_id = snatched_status.get('id')).all()
|
rels = db.query(Release).filter_by(status_id = snatched_status.get('id')).all()
|
||||||
|
|
||||||
if rels:
|
|
||||||
log.debug('Checking status snatched releases...')
|
|
||||||
|
|
||||||
scan_required = False
|
scan_required = False
|
||||||
|
|
||||||
for rel in rels:
|
if rels:
|
||||||
|
self.checking_snatched = True
|
||||||
# Get current selected title
|
log.debug('Checking status snatched releases...')
|
||||||
default_title = ''
|
# get queue and history (once) from SABnzbd
|
||||||
for title in rel.movie.library.titles:
|
statuses = fireEvent('download.status', merge = True)
|
||||||
if title.default: default_title = title.title
|
if not statuses:
|
||||||
|
|
||||||
# Check if movie has already completed and is manage tab (legacy db correction)
|
|
||||||
if rel.movie.status_id == done_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')
|
|
||||||
db.commit()
|
|
||||||
continue
|
|
||||||
|
|
||||||
item = {}
|
|
||||||
for info in rel.info:
|
|
||||||
item[info.identifier] = info.value
|
|
||||||
|
|
||||||
movie_dict = fireEvent('movie.get', rel.movie_id, single = True)
|
|
||||||
|
|
||||||
# check status
|
|
||||||
downloadstatus = fireEvent('download.status', data = item, movie = movie_dict, single = True)
|
|
||||||
if not downloadstatus:
|
|
||||||
log.debug('Download status functionality is not implemented for active downloaders.')
|
log.debug('Download status functionality is not implemented for active downloaders.')
|
||||||
scan_required = True
|
scan_required = True
|
||||||
else:
|
else:
|
||||||
log.debug('Download status: %s' , downloadstatus)
|
try:
|
||||||
|
for rel in rels:
|
||||||
|
rel_dict = rel.to_dict({'info': {}})
|
||||||
|
|
||||||
if downloadstatus == 'failed':
|
# Get current selected title
|
||||||
if self.conf('next_on_failed'):
|
default_title = getTitle(rel.movie.library)
|
||||||
fireEvent('searcher.try_next_release', movie_id = rel.movie_id)
|
|
||||||
else:
|
|
||||||
rel.status_id = failed_status.get('id')
|
|
||||||
db.commit()
|
|
||||||
|
|
||||||
log.info('Download of %s failed.', item['name'])
|
# Check if movie has already completed and is manage tab (legacy db correction)
|
||||||
|
if rel.movie.status_id == done_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')
|
||||||
|
db.commit()
|
||||||
|
continue
|
||||||
|
|
||||||
elif downloadstatus == 'completed':
|
movie_dict = fireEvent('movie.get', rel.movie_id, single = True)
|
||||||
log.info('Download of %s completed!', item['name'])
|
|
||||||
scan_required = True
|
|
||||||
|
|
||||||
elif downloadstatus == 'not_found':
|
# check status
|
||||||
log.info('%s not found in downloaders', item['name'])
|
nzbname = self.createNzbName(rel_dict['info'], movie_dict)
|
||||||
rel.status_id = ignored_status.get('id')
|
|
||||||
db.commit()
|
found = False
|
||||||
|
for item in statuses:
|
||||||
|
if item['name'] == nzbname:
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
if item['status'] == 'busy':
|
||||||
|
pass
|
||||||
|
elif item['status'] == 'failed':
|
||||||
|
fireEvent('download.remove_failed', item, single = True)
|
||||||
|
|
||||||
|
if self.conf('next_on_failed'):
|
||||||
|
fireEvent('searcher.try_next_release', movie_id = rel.movie_id)
|
||||||
|
else:
|
||||||
|
rel.status_id = failed_status.get('id')
|
||||||
|
db.commit()
|
||||||
|
elif item['status'] == 'completed':
|
||||||
|
log.info('Download of %s completed!', item['name'])
|
||||||
|
scan_required = True
|
||||||
|
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not found:
|
||||||
|
log.info('%s not found in downloaders', nzbname)
|
||||||
|
rel.status_id = ignored_status.get('id')
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
if self.conf('next_on_failed'):
|
||||||
|
fireEvent('searcher.try_next_release', movie_id = rel.movie_id)
|
||||||
|
|
||||||
|
except:
|
||||||
|
log.error('Failed checking for release in downloader: %s', traceback.format_exc())
|
||||||
|
|
||||||
# Note that Queued, Downloading, Paused, Repair and Unpackimg are also available as status for SabNZBd
|
|
||||||
if scan_required:
|
if scan_required:
|
||||||
fireEvent('renamer.scan')
|
fireEvent('renamer.scan')
|
||||||
|
|
||||||
|
self.checking_snatched = False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|||||||
@@ -542,7 +542,6 @@ class Scanner(Plugin):
|
|||||||
break
|
break
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
#db.close()
|
|
||||||
|
|
||||||
# Search based on OpenSubtitleHash
|
# Search based on OpenSubtitleHash
|
||||||
if not imdb_id and not group['is_dvd']:
|
if not imdb_id and not group['is_dvd']:
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ name_scores = [
|
|||||||
# Video
|
# Video
|
||||||
'x264:1', 'h264:1',
|
'x264:1', 'h264:1',
|
||||||
# Audio
|
# Audio
|
||||||
'DTS:4', 'AC3:2',
|
'dts:4', 'ac3:2',
|
||||||
# Quality
|
# Quality
|
||||||
'720p:10', '1080p:10', 'bluray:10', 'dvd:1', 'dvdrip:1', 'brrip:1', 'bdrip:1', 'bd50:1', 'bd25:1',
|
'720p:10', '1080p:10', 'bluray:10', 'dvd:1', 'dvdrip:1', 'brrip:1', 'bdrip:1', 'bd50:1', 'bd25:1',
|
||||||
# Language / Subs
|
# Language / Subs
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from couchpotato import get_session
|
from couchpotato import get_session
|
||||||
from couchpotato.api import addApiView
|
from couchpotato.api import addApiView
|
||||||
from couchpotato.core.event import addEvent, fireEvent
|
from couchpotato.core.event import addEvent, fireEvent, fireEventAsync
|
||||||
from couchpotato.core.helpers.encoding import simplifyString, toUnicode
|
from couchpotato.core.helpers.encoding import simplifyString, toUnicode
|
||||||
from couchpotato.core.helpers.request import jsonified, getParam
|
from couchpotato.core.helpers.request import jsonified, getParam
|
||||||
from couchpotato.core.helpers.variable import md5, getTitle
|
from couchpotato.core.helpers.variable import md5, getTitle
|
||||||
@@ -36,9 +36,38 @@ class Searcher(Plugin):
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
addApiView('searcher.full_search', self.allMoviesView, docs = {
|
||||||
|
'desc': 'Starts a full search for all wanted movies',
|
||||||
|
})
|
||||||
|
|
||||||
|
addApiView('searcher.progress', self.getProgress, docs = {
|
||||||
|
'desc': 'Get the progress of current full search',
|
||||||
|
'return': {'type': 'object', 'example': """{
|
||||||
|
'progress': False || object, total & to_go,
|
||||||
|
}"""},
|
||||||
|
})
|
||||||
|
|
||||||
# Schedule cronjob
|
# Schedule cronjob
|
||||||
fireEvent('schedule.cron', 'searcher.all', self.allMovies, day = self.conf('cron_day'), hour = self.conf('cron_hour'), minute = self.conf('cron_minute'))
|
fireEvent('schedule.cron', 'searcher.all', self.allMovies, day = self.conf('cron_day'), hour = self.conf('cron_hour'), minute = self.conf('cron_minute'))
|
||||||
|
|
||||||
|
def allMoviesView(self):
|
||||||
|
|
||||||
|
in_progress = self.in_progress
|
||||||
|
if not in_progress:
|
||||||
|
fireEventAsync('searcher.all')
|
||||||
|
fireEvent('notify.frontend', type = 'searcher.started', data = True, message = 'Full search started')
|
||||||
|
else:
|
||||||
|
fireEvent('notify.frontend', type = 'searcher.already_started', data = True, message = 'Full search already in progress')
|
||||||
|
|
||||||
|
return jsonified({
|
||||||
|
'success': not in_progress
|
||||||
|
})
|
||||||
|
|
||||||
|
def getProgress(self):
|
||||||
|
|
||||||
|
return jsonified({
|
||||||
|
'progress': self.in_progress
|
||||||
|
})
|
||||||
|
|
||||||
def allMovies(self):
|
def allMovies(self):
|
||||||
|
|
||||||
@@ -54,6 +83,11 @@ class Searcher(Plugin):
|
|||||||
Movie.status.has(identifier = 'active')
|
Movie.status.has(identifier = 'active')
|
||||||
).all()
|
).all()
|
||||||
|
|
||||||
|
self.in_progress = {
|
||||||
|
'total': len(movies),
|
||||||
|
'to_go': len(movies),
|
||||||
|
}
|
||||||
|
|
||||||
for movie in movies:
|
for movie in movies:
|
||||||
movie_dict = movie.to_dict({
|
movie_dict = movie.to_dict({
|
||||||
'profile': {'types': {'quality': {}}},
|
'profile': {'types': {'quality': {}}},
|
||||||
@@ -65,15 +99,17 @@ class Searcher(Plugin):
|
|||||||
try:
|
try:
|
||||||
self.single(movie_dict)
|
self.single(movie_dict)
|
||||||
except IndexError:
|
except IndexError:
|
||||||
|
log.error('Forcing library update for %s, if you see this often, please report: %s', (movie_dict['library']['identifier'], traceback.format_exc()))
|
||||||
fireEvent('library.update', movie_dict['library']['identifier'], force = True)
|
fireEvent('library.update', movie_dict['library']['identifier'], force = True)
|
||||||
except:
|
except:
|
||||||
log.error('Search failed for %s: %s', (movie_dict['library']['identifier'], traceback.format_exc()))
|
log.error('Search failed for %s: %s', (movie_dict['library']['identifier'], traceback.format_exc()))
|
||||||
|
|
||||||
|
self.in_progress['to_go'] -= 1
|
||||||
|
|
||||||
# Break if CP wants to shut down
|
# Break if CP wants to shut down
|
||||||
if self.shuttingDown():
|
if self.shuttingDown():
|
||||||
break
|
break
|
||||||
|
|
||||||
#db.close()
|
|
||||||
self.in_progress = False
|
self.in_progress = False
|
||||||
|
|
||||||
def single(self, movie):
|
def single(self, movie):
|
||||||
@@ -192,7 +228,6 @@ class Searcher(Plugin):
|
|||||||
|
|
||||||
fireEvent('notify.frontend', type = 'searcher.ended.%s' % movie['id'], data = True)
|
fireEvent('notify.frontend', type = 'searcher.ended.%s' % movie['id'], data = True)
|
||||||
|
|
||||||
#db.close()
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def download(self, data, movie, manual = False):
|
def download(self, data, movie, manual = False):
|
||||||
@@ -243,7 +278,6 @@ class Searcher(Plugin):
|
|||||||
except Exception, e:
|
except Exception, e:
|
||||||
log.error('Failed marking movie finished: %s %s', (e, traceback.format_exc()))
|
log.error('Failed marking movie finished: %s %s', (e, traceback.format_exc()))
|
||||||
|
|
||||||
#db.close()
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
log.info('Tried to download, but none of the downloaders are enabled')
|
log.info('Tried to download, but none of the downloaders are enabled')
|
||||||
@@ -254,7 +288,7 @@ class Searcher(Plugin):
|
|||||||
imdb_results = kwargs.get('imdb_results', False)
|
imdb_results = kwargs.get('imdb_results', False)
|
||||||
retention = Env.setting('retention', section = 'nzb')
|
retention = Env.setting('retention', section = 'nzb')
|
||||||
|
|
||||||
if nzb.get('seeds') is None and retention < nzb.get('age', 0):
|
if nzb.get('seeds') is None and 0 < retention < nzb.get('age', 0):
|
||||||
log.info('Wrong: Outside retention, age is %s, needs %s or lower: %s', (nzb['age'], retention, nzb['name']))
|
log.info('Wrong: Outside retention, age is %s, needs %s or lower: %s', (nzb['age'], retention, nzb['name']))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -354,9 +388,11 @@ class Searcher(Plugin):
|
|||||||
year_name = fireEvent('scanner.name_year', name, single = True)
|
year_name = fireEvent('scanner.name_year', name, single = True)
|
||||||
if movie_year < datetime.datetime.now().year - 3 and not year_name.get('year', None):
|
if movie_year < datetime.datetime.now().year - 3 and not year_name.get('year', None):
|
||||||
if size > 3000: # Assume dvdr
|
if size > 3000: # Assume dvdr
|
||||||
return 'dvdr' == preferred_quality['identifier']
|
log.info('Quality was missing in name, assuming it\'s a DVD-R based on the size: %s', (size))
|
||||||
|
found['dvdr'] = True
|
||||||
else: # Assume dvdrip
|
else: # Assume dvdrip
|
||||||
return 'dvdrip' == preferred_quality['identifier']
|
log.info('Quality was missing in name, assuming it\'s a DVD-Rip based on the size: %s', (size))
|
||||||
|
found['dvdrip'] = True
|
||||||
|
|
||||||
# Allow other qualities
|
# Allow other qualities
|
||||||
for allowed in preferred_quality.get('allow'):
|
for allowed in preferred_quality.get('allow'):
|
||||||
@@ -410,6 +446,11 @@ class Searcher(Plugin):
|
|||||||
if not dates or (dates.get('theater', 0) == 0 and dates.get('dvd', 0) == 0):
|
if not dates or (dates.get('theater', 0) == 0 and dates.get('dvd', 0) == 0):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
|
|
||||||
|
# For movies before 1972
|
||||||
|
if dates.get('theater', 0) < 0 or dates.get('dvd', 0) < 0:
|
||||||
|
return True
|
||||||
|
|
||||||
if wanted_quality in pre_releases:
|
if wanted_quality in pre_releases:
|
||||||
# Prerelease 1 week before theaters
|
# Prerelease 1 week before theaters
|
||||||
if dates.get('theater') - 604800 < now:
|
if dates.get('theater') - 604800 < now:
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ config = [{
|
|||||||
'groups': [
|
'groups': [
|
||||||
{
|
{
|
||||||
'tab': 'renamer',
|
'tab': 'renamer',
|
||||||
'subtab': 'subtitles',
|
|
||||||
'name': 'subtitle',
|
'name': 'subtitle',
|
||||||
'label': 'Download subtitles after rename',
|
'label': 'Download subtitles',
|
||||||
|
'description': 'after rename',
|
||||||
'options': [
|
'options': [
|
||||||
{
|
{
|
||||||
'name': 'enabled',
|
'name': 'enabled',
|
||||||
|
|||||||
@@ -40,8 +40,6 @@ class Subtitle(Plugin):
|
|||||||
# get subtitles for those files
|
# get subtitles for those files
|
||||||
subliminal.list_subtitles(files, cache_dir = Env.get('cache_dir'), multi = True, languages = self.getLanguages(), services = self.services)
|
subliminal.list_subtitles(files, cache_dir = Env.get('cache_dir'), multi = True, languages = self.getLanguages(), services = self.services)
|
||||||
|
|
||||||
#db.close()
|
|
||||||
|
|
||||||
def searchSingle(self, group):
|
def searchSingle(self, group):
|
||||||
|
|
||||||
if self.isDisabled(): return
|
if self.isDisabled(): return
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ config = [{
|
|||||||
'groups': [
|
'groups': [
|
||||||
{
|
{
|
||||||
'tab': 'renamer',
|
'tab': 'renamer',
|
||||||
'subtab': 'trailer',
|
|
||||||
'name': 'trailer',
|
'name': 'trailer',
|
||||||
'label': 'Download trailer after rename',
|
'label': 'Download trailer',
|
||||||
|
'description': 'after rename',
|
||||||
'options': [
|
'options': [
|
||||||
{
|
{
|
||||||
'name': 'enabled',
|
'name': 'enabled',
|
||||||
@@ -24,12 +24,6 @@ config = [{
|
|||||||
'type': 'dropdown',
|
'type': 'dropdown',
|
||||||
'values': [('1080P', '1080p'), ('720P', '720p'), ('480P', '480p')],
|
'values': [('1080P', '1080p'), ('720P', '720p'), ('480P', '480p')],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
'name': 'automatic',
|
|
||||||
'default': False,
|
|
||||||
'type': 'bool',
|
|
||||||
'description': 'Automaticly search & download for movies in library',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -14,12 +14,13 @@
|
|||||||
|
|
||||||
.page.wizard .tab_wrapper {
|
.page.wizard .tab_wrapper {
|
||||||
background: #5c697b;
|
background: #5c697b;
|
||||||
padding: 18px 0;
|
padding: 10px 0;
|
||||||
font-size: 23px;
|
font-size: 18px;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
min-width: 960px;
|
||||||
left: 0;
|
left: 0;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
box-shadow: 0 0 50px rgba(0,0,0,0.55);
|
box-shadow: 0 0 50px rgba(0,0,0,0.55);
|
||||||
@@ -36,7 +37,7 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
.page.wizard .tabs li a {
|
.page.wizard .tabs li a {
|
||||||
padding: 20px 30px;
|
padding: 20px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page.wizard .tab_wrapper .pointer {
|
.page.wizard .tab_wrapper .pointer {
|
||||||
@@ -45,7 +46,7 @@
|
|||||||
border-top: 10px solid #5c697b;
|
border-top: 10px solid #5c697b;
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 60px;
|
top: 44px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page.wizard .tab_content {
|
.page.wizard .tab_content {
|
||||||
@@ -58,11 +59,25 @@
|
|||||||
.page.wizard .wgroup_finish {
|
.page.wizard .wgroup_finish {
|
||||||
height: 300px;
|
height: 300px;
|
||||||
}
|
}
|
||||||
|
.page.wizard .wgroup_finish h1 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.page.wizard .wgroup_finish .wizard_support,
|
||||||
|
.page.wizard .wgroup_finish .description {
|
||||||
|
font-size: 25px;
|
||||||
|
line-height: 120%;
|
||||||
|
margin: 20px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.page.wizard .button.green {
|
.page.wizard .button.green {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
font-size: 25px;
|
font-size: 25px;
|
||||||
margin: 10px 30px;
|
margin: 10px 30px 80px;
|
||||||
display: block;
|
display: block;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.page.wizard .tab_nzb_providers {
|
||||||
|
margin: 20px 0 0 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -37,21 +37,37 @@ Page.Wizard = new Class({
|
|||||||
},
|
},
|
||||||
'downloaders': {
|
'downloaders': {
|
||||||
'title': 'What download apps are you using?',
|
'title': 'What download apps are you using?',
|
||||||
'description': 'If you don\'t have any of these listed, you have to use Blackhole. Or drop me a line, maybe I\'ll support your download app.'
|
'description': 'CP needs an external download app to work with. Choose one below. For more downloaders check settings after you have filled in the wizard. If your download app isn\'t in the list, use Blackhole.'
|
||||||
},
|
},
|
||||||
'providers': {
|
'providers': {
|
||||||
'title': 'Are you registered at any of these sites?',
|
'title': 'Are you registered at any of these sites?',
|
||||||
'description': 'CP uses these sites to search for movies. A few free are enabled by default, but it\'s always better to have a few more.'
|
'description': 'CP uses these sites to search for movies. A few free are enabled by default, but it\'s always better to have a few more. Check settings for the full list of available providers.',
|
||||||
|
'include': ['nzb_providers', 'torrent_providers']
|
||||||
},
|
},
|
||||||
'renamer': {
|
'renamer': {
|
||||||
'title': 'Move & rename the movies after downloading?',
|
'title': 'Move & rename the movies after downloading?',
|
||||||
'description': ''
|
'description': 'The coolest part of CP is that it can move and organize your downloaded movies automagically. Check settings and you can even download trailers, subtitles and other data when it has finished downloading. It\'s awesome!'
|
||||||
|
},
|
||||||
|
'automation': {
|
||||||
|
'title': 'Easily add movies to your wanted list!',
|
||||||
|
'description': 'You can easily add movies from your favorite movie site, like IMDB, Rotten Tomatoes, Apple Trailers and more. Just install the userscript or drag the bookmarklet to your browsers bookmarks.' +
|
||||||
|
'<br />Once installed, just click the bookmarklet on a movie page and watch the magic happen ;)',
|
||||||
|
'content': function(){
|
||||||
|
return App.createUserscriptButtons().setStyles({
|
||||||
|
'background-image': "url('"+Api.createUrl('static/userscript/userscript.png')+"')"
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
'finish': {
|
'finish': {
|
||||||
'title': 'Finish Up',
|
'title': 'Finishing Up',
|
||||||
'description': 'Are you done? Did you fill in everything as much as possible? Yes, ok gogogo!',
|
'description': 'Are you done? Did you fill in everything as much as possible?' +
|
||||||
|
'<br />Be sure to check the settings to see what more CP can do!<br /><br />' +
|
||||||
|
'<div class="wizard_support">After you\'ve used CP for a while, and you like it (which of course you will), consider supporting CP. Maybe even by writing some code. <br />Or by getting a subscription at <a href="https://usenetserver.com/partners/?a_aid=couchpotato&a_bid=3f357c6f">Usenet Server</a> or <a href="http://www.newshosting.com/partners/?a_aid=couchpotato&a_bid=a0b022df">Newshosting</a>.</div>',
|
||||||
'content': new Element('div').adopt(
|
'content': new Element('div').adopt(
|
||||||
new Element('a.button.green', {
|
new Element('a.button.green', {
|
||||||
|
'styles': {
|
||||||
|
'margin-top': 20
|
||||||
|
},
|
||||||
'text': 'I\'m ready to start the awesomeness, wow this button is big and green!',
|
'text': 'I\'m ready to start the awesomeness, wow this button is big and green!',
|
||||||
'events': {
|
'events': {
|
||||||
'click': function(e){
|
'click': function(e){
|
||||||
@@ -76,7 +92,7 @@ Page.Wizard = new Class({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
groups: ['welcome', 'general', 'downloaders', 'searcher', 'providers', 'renamer', 'finish'],
|
groups: ['welcome', 'general', 'downloaders', 'searcher', 'providers', 'renamer', 'automation', 'finish'],
|
||||||
|
|
||||||
open: function(action, params){
|
open: function(action, params){
|
||||||
var self = this;
|
var self = this;
|
||||||
@@ -110,7 +126,8 @@ Page.Wizard = new Class({
|
|||||||
var form = self.el.getElement('.uniForm');
|
var form = self.el.getElement('.uniForm');
|
||||||
var tabs = self.el.getElement('.tabs');
|
var tabs = self.el.getElement('.tabs');
|
||||||
|
|
||||||
self.groups.each(function(group){
|
self.groups.each(function(group, nr){
|
||||||
|
|
||||||
if(self.headers[group]){
|
if(self.headers[group]){
|
||||||
group_container = new Element('.wgroup_'+group, {
|
group_container = new Element('.wgroup_'+group, {
|
||||||
'styles': {
|
'styles': {
|
||||||
@@ -120,6 +137,14 @@ Page.Wizard = new Class({
|
|||||||
'duration': 350
|
'duration': 350
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(self.headers[group].include){
|
||||||
|
self.headers[group].include.each(function(inc){
|
||||||
|
group_container.addClass('wgroup_'+inc);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var content = self.headers[group].content
|
||||||
group_container.adopt(
|
group_container.adopt(
|
||||||
new Element('h1', {
|
new Element('h1', {
|
||||||
'text': self.headers[group].title
|
'text': self.headers[group].title
|
||||||
@@ -127,15 +152,40 @@ Page.Wizard = new Class({
|
|||||||
self.headers[group].description ? new Element('span.description', {
|
self.headers[group].description ? new Element('span.description', {
|
||||||
'html': self.headers[group].description
|
'html': self.headers[group].description
|
||||||
}) : null,
|
}) : null,
|
||||||
self.headers[group].content ? self.headers[group].content : null
|
content ? (typeOf(content) == 'function' ? content() : content) : null
|
||||||
).inject(form);
|
).inject(form);
|
||||||
}
|
}
|
||||||
|
|
||||||
var tab_navigation = tabs.getElement('.t_'+group);
|
var tab_navigation = tabs.getElement('.t_'+group);
|
||||||
|
|
||||||
|
if(!tab_navigation && self.headers[group] && self.headers[group].include){
|
||||||
|
tab_navigation = []
|
||||||
|
self.headers[group].include.each(function(inc){
|
||||||
|
tab_navigation.include(tabs.getElement('.t_'+inc));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if(tab_navigation && group_container){
|
if(tab_navigation && group_container){
|
||||||
tab_navigation.inject(tabs); // Tab navigation
|
tabs.adopt(tab_navigation); // Tab navigation
|
||||||
self.el.getElement('.tab_'+group).inject(group_container); // Tab content
|
|
||||||
if(self.headers[group]){
|
if(self.headers[group] && self.headers[group].include){
|
||||||
|
|
||||||
|
self.headers[group].include.each(function(inc){
|
||||||
|
self.el.getElement('.tab_'+inc).inject(group_container);
|
||||||
|
})
|
||||||
|
|
||||||
|
new Element('li.t_'+group).adopt(
|
||||||
|
new Element('a', {
|
||||||
|
'href': App.createUrl('wizard/'+group),
|
||||||
|
'text': (self.headers[group].label || group).capitalize()
|
||||||
|
})
|
||||||
|
).inject(tabs);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
self.el.getElement('.tab_'+group).inject(group_container); // Tab content
|
||||||
|
|
||||||
|
if(tab_navigation.getElement && self.headers[group]){
|
||||||
var a = tab_navigation.getElement('a');
|
var a = tab_navigation.getElement('a');
|
||||||
a.set('text', (self.headers[group].label || group).capitalize());
|
a.set('text', (self.headers[group].label || group).capitalize());
|
||||||
var url_split = a.get('href').split('wizard')[1].split('/');
|
var url_split = a.get('href').split('wizard')[1].split('/');
|
||||||
@@ -163,6 +213,8 @@ Page.Wizard = new Class({
|
|||||||
// Hide retention
|
// Hide retention
|
||||||
self.el.getElement('.tab_searcher').hide();
|
self.el.getElement('.tab_searcher').hide();
|
||||||
self.el.getElement('.t_searcher').hide();
|
self.el.getElement('.t_searcher').hide();
|
||||||
|
self.el.getElement('.t_nzb_providers').hide();
|
||||||
|
self.el.getElement('.t_torrent_providers').hide();
|
||||||
|
|
||||||
// Add pointer
|
// Add pointer
|
||||||
new Element('.tab_wrapper').wraps(tabs).adopt(
|
new Element('.tab_wrapper').wraps(tabs).adopt(
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ class MovieResultModifier(Plugin):
|
|||||||
except:
|
except:
|
||||||
log.error('Tried getting more info on searched movies: %s', traceback.format_exc())
|
log.error('Tried getting more info on searched movies: %s', traceback.format_exc())
|
||||||
|
|
||||||
#db.close()
|
|
||||||
return temp
|
return temp
|
||||||
|
|
||||||
def checkLibrary(self, result):
|
def checkLibrary(self, result):
|
||||||
|
|||||||
@@ -94,7 +94,6 @@ class CouchPotatoApi(MovieProvider):
|
|||||||
db = get_session()
|
db = get_session()
|
||||||
active_movies = db.query(Movie).filter(Movie.status.has(identifier = 'active')).all()
|
active_movies = db.query(Movie).filter(Movie.status.has(identifier = 'active')).all()
|
||||||
movies = [x.library.identifier for x in active_movies]
|
movies = [x.library.identifier for x in active_movies]
|
||||||
#db.close()
|
|
||||||
|
|
||||||
suggestions = self.suggest(movies, ignore)
|
suggestions = self.suggest(movies, ignore)
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ config = [{
|
|||||||
'groups': [
|
'groups': [
|
||||||
{
|
{
|
||||||
'tab': 'searcher',
|
'tab': 'searcher',
|
||||||
'subtab': 'providers',
|
'subtab': 'nzb_providers',
|
||||||
'name': 'Mysterbin',
|
'name': 'Mysterbin',
|
||||||
'description': 'Free provider, less accurate. See <a href="http://www.mysterbin.com/">Mysterbin</a>',
|
'description': 'Free provider, less accurate. See <a href="http://www.mysterbin.com/">Mysterbin</a>',
|
||||||
'options': [
|
'options': [
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ config = [{
|
|||||||
'groups': [
|
'groups': [
|
||||||
{
|
{
|
||||||
'tab': 'searcher',
|
'tab': 'searcher',
|
||||||
'subtab': 'providers',
|
'subtab': 'nzb_providers',
|
||||||
'name': 'newzbin',
|
'name': 'newzbin',
|
||||||
'description': 'See <a href="https://www.newzbin2.es/">Newzbin</a>',
|
'description': 'See <a href="https://www.newzbin2.es/">Newzbin</a>',
|
||||||
'wizard': True,
|
'wizard': True,
|
||||||
|
|||||||
@@ -8,8 +8,9 @@ config = [{
|
|||||||
'groups': [
|
'groups': [
|
||||||
{
|
{
|
||||||
'tab': 'searcher',
|
'tab': 'searcher',
|
||||||
'subtab': 'providers',
|
'subtab': 'nzb_providers',
|
||||||
'name': 'newznab',
|
'name': 'newznab',
|
||||||
|
'order': 10,
|
||||||
'description': 'Enable multiple NewzNab providers such as <a href="http://nzb.su" target="_blank">NZB.su</a> and <a href="http://nzbs.org" target="_blank">nzbs.org</a>',
|
'description': 'Enable multiple NewzNab providers such as <a href="http://nzb.su" target="_blank">NZB.su</a> and <a href="http://nzbs.org" target="_blank">nzbs.org</a>',
|
||||||
'wizard': True,
|
'wizard': True,
|
||||||
'options': [
|
'options': [
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ config = [{
|
|||||||
'groups': [
|
'groups': [
|
||||||
{
|
{
|
||||||
'tab': 'searcher',
|
'tab': 'searcher',
|
||||||
'subtab': 'providers',
|
'subtab': 'nzb_providers',
|
||||||
'name': 'NZBClub',
|
'name': 'NZBClub',
|
||||||
'description': 'Free provider, less accurate. See <a href="https://www.nzbclub.com/">NZBClub</a>',
|
'description': 'Free provider, less accurate. See <a href="https://www.nzbclub.com/">NZBClub</a>',
|
||||||
'options': [
|
'options': [
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ config = [{
|
|||||||
'groups': [
|
'groups': [
|
||||||
{
|
{
|
||||||
'tab': 'searcher',
|
'tab': 'searcher',
|
||||||
'subtab': 'providers',
|
'subtab': 'nzb_providers',
|
||||||
'name': 'nzbindex',
|
'name': 'nzbindex',
|
||||||
'description': 'Free provider, less accurate. See <a href="http://www.nzbindex.nl/">NZBIndex</a>',
|
'description': 'Free provider, less accurate. See <a href="http://www.nzbindex.nl/">NZBIndex</a>',
|
||||||
'options': [
|
'options': [
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ config = [{
|
|||||||
'groups': [
|
'groups': [
|
||||||
{
|
{
|
||||||
'tab': 'searcher',
|
'tab': 'searcher',
|
||||||
'subtab': 'providers',
|
'subtab': 'nzb_providers',
|
||||||
'name': 'nzbmatrix',
|
'name': 'nzbmatrix',
|
||||||
'label': 'NZBMatrix',
|
'label': 'NZBMatrix',
|
||||||
'description': 'See <a href="https://nzbmatrix.com/">NZBMatrix</a>',
|
'description': 'See <a href="https://nzbmatrix.com/">NZBMatrix</a>',
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ config = [{
|
|||||||
'groups': [
|
'groups': [
|
||||||
{
|
{
|
||||||
'tab': 'searcher',
|
'tab': 'searcher',
|
||||||
'subtab': 'providers',
|
'subtab': 'nzb_providers',
|
||||||
'name': 'nzbsrus',
|
'name': 'nzbsrus',
|
||||||
'label': 'Nzbsrus',
|
'label': 'Nzbsrus',
|
||||||
'description': 'See <a href="https://www.nzbsrus.com/">NZBsRus</a>',
|
'description': 'See <a href="https://www.nzbsrus.com/">NZBsRus</a>',
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ config = [{
|
|||||||
'groups': [
|
'groups': [
|
||||||
{
|
{
|
||||||
'tab': 'searcher',
|
'tab': 'searcher',
|
||||||
'subtab': 'providers',
|
'subtab': 'torrent_providers',
|
||||||
'name': 'KickAssTorrents',
|
'name': 'KickAssTorrents',
|
||||||
'description': 'See <a href="https://kat.ph/">KickAssTorrents</a>',
|
'description': 'See <a href="https://kat.ph/">KickAssTorrents</a>',
|
||||||
|
'wizard': True,
|
||||||
'options': [
|
'options': [
|
||||||
{
|
{
|
||||||
'name': 'enabled',
|
'name': 'enabled',
|
||||||
|
|||||||
@@ -5,32 +5,34 @@ def start():
|
|||||||
|
|
||||||
config = [{
|
config = [{
|
||||||
'name': 'passthepopcorn',
|
'name': 'passthepopcorn',
|
||||||
'groups': [{
|
'groups': [
|
||||||
'tab': 'searcher',
|
{
|
||||||
'subtab': 'providers',
|
'tab': 'searcher',
|
||||||
'name': 'PassThePopcorn',
|
'subtab': 'torrent_providers',
|
||||||
'description': 'See <a href="http://passthepopcorn.me">PassThePopcorn.me</a>',
|
'name': 'PassThePopcorn',
|
||||||
'options': [
|
'description': 'See <a href="http://passthepopcorn.me">PassThePopcorn.me</a>',
|
||||||
{
|
'options': [
|
||||||
'name': 'enabled',
|
{
|
||||||
'type': 'enabler',
|
'name': 'enabled',
|
||||||
'default': False
|
'type': 'enabler',
|
||||||
},
|
'default': False
|
||||||
{
|
},
|
||||||
'name': 'domain',
|
{
|
||||||
'advanced': True,
|
'name': 'domain',
|
||||||
'label': 'Proxy server',
|
'advanced': True,
|
||||||
'description': 'Domain for requests (HTTPS only!), keep empty to use default (tls.passthepopcorn.me).',
|
'label': 'Proxy server',
|
||||||
},
|
'description': 'Domain for requests (HTTPS only!), keep empty to use default (tls.passthepopcorn.me).',
|
||||||
{
|
},
|
||||||
'name': 'username',
|
{
|
||||||
'default': '',
|
'name': 'username',
|
||||||
},
|
'default': '',
|
||||||
{
|
},
|
||||||
'name': 'password',
|
{
|
||||||
'default': '',
|
'name': 'password',
|
||||||
'type': 'password',
|
'default': '',
|
||||||
}
|
'type': 'password',
|
||||||
],
|
}
|
||||||
}]
|
],
|
||||||
|
}
|
||||||
|
]
|
||||||
}]
|
}]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ config = [{
|
|||||||
'groups': [
|
'groups': [
|
||||||
{
|
{
|
||||||
'tab': 'searcher',
|
'tab': 'searcher',
|
||||||
'subtab': 'providers',
|
'subtab': 'torrent_providers',
|
||||||
'name': 'PublicHD',
|
'name': 'PublicHD',
|
||||||
'description': 'Public Torrent site with only HD content. See <a href="http://publichd.eu/">PublicHD</a>',
|
'description': 'Public Torrent site with only HD content. See <a href="http://publichd.eu/">PublicHD</a>',
|
||||||
'options': [
|
'options': [
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ config = [{
|
|||||||
'groups': [
|
'groups': [
|
||||||
{
|
{
|
||||||
'tab': 'searcher',
|
'tab': 'searcher',
|
||||||
'subtab': 'providers',
|
'subtab': 'torrent_providers',
|
||||||
'name': 'SceneAccess',
|
'name': 'SceneAccess',
|
||||||
'description': 'See <a href="https://sceneaccess.eu/">SceneAccess</a>',
|
'description': 'See <a href="https://sceneaccess.eu/">SceneAccess</a>',
|
||||||
'options': [
|
'options': [
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ config = [{
|
|||||||
'groups': [
|
'groups': [
|
||||||
{
|
{
|
||||||
'tab': 'searcher',
|
'tab': 'searcher',
|
||||||
'subtab': 'providers',
|
'subtab': 'torrent_providers',
|
||||||
'name': 'SceneHD',
|
'name': 'SceneHD',
|
||||||
'description': 'See <a href="http://scenehd.org">SceneHD</a>',
|
'description': 'See <a href="http://scenehd.org">SceneHD</a>',
|
||||||
'options': [
|
'options': [
|
||||||
|
|||||||
@@ -5,23 +5,26 @@ def start():
|
|||||||
|
|
||||||
config = [{
|
config = [{
|
||||||
'name': 'thepiratebay',
|
'name': 'thepiratebay',
|
||||||
'groups': [{
|
'groups': [
|
||||||
'tab': 'searcher',
|
{
|
||||||
'subtab': 'providers',
|
'tab': 'searcher',
|
||||||
'name': 'ThePirateBay',
|
'subtab': 'torrent_providers',
|
||||||
'description': 'The world\'s largest bittorrent tracker. See <a href="http://fucktimkuik.org/">ThePirateBay</a>',
|
'name': 'ThePirateBay',
|
||||||
'options': [
|
'description': 'The world\'s largest bittorrent tracker. See <a href="http://fucktimkuik.org/">ThePirateBay</a>',
|
||||||
{
|
'wizard': True,
|
||||||
'name': 'enabled',
|
'options': [
|
||||||
'type': 'enabler',
|
{
|
||||||
'default': False
|
'name': 'enabled',
|
||||||
},
|
'type': 'enabler',
|
||||||
{
|
'default': False
|
||||||
'name': 'domain',
|
},
|
||||||
'advanced': True,
|
{
|
||||||
'label': 'Proxy server',
|
'name': 'domain',
|
||||||
'description': 'Domain for requests, keep empty to let CouchPotato pick.',
|
'advanced': True,
|
||||||
}
|
'label': 'Proxy server',
|
||||||
],
|
'description': 'Domain for requests, keep empty to let CouchPotato pick.',
|
||||||
}]
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]
|
||||||
}]
|
}]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ config = [{
|
|||||||
'groups': [
|
'groups': [
|
||||||
{
|
{
|
||||||
'tab': 'searcher',
|
'tab': 'searcher',
|
||||||
'subtab': 'providers',
|
'subtab': 'torrent_providers',
|
||||||
'name': 'TorrentLeech',
|
'name': 'TorrentLeech',
|
||||||
'description': 'See <a href="http://torrentleech.org">TorrentLeech</a>',
|
'description': 'See <a href="http://torrentleech.org">TorrentLeech</a>',
|
||||||
'options': [
|
'options': [
|
||||||
|
|||||||
@@ -204,7 +204,6 @@ class Settings(object):
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
#db.close()
|
|
||||||
return prop
|
return prop
|
||||||
|
|
||||||
def setProperty(self, identifier, value = ''):
|
def setProperty(self, identifier, value = ''):
|
||||||
@@ -221,4 +220,3 @@ class Settings(object):
|
|||||||
p.value = toUnicode(value)
|
p.value = toUnicode(value)
|
||||||
|
|
||||||
db.commit()
|
db.commit()
|
||||||
#db.close()
|
|
||||||
|
|||||||
@@ -170,18 +170,17 @@ def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, En
|
|||||||
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
|
||||||
|
|
||||||
|
# Check if database exists
|
||||||
|
db = Env.get('db_path')
|
||||||
|
db_exists = os.path.isfile(db_path)
|
||||||
|
|
||||||
# Load configs & plugins
|
# Load configs & plugins
|
||||||
loader = Env.get('loader')
|
loader = Env.get('loader')
|
||||||
loader.preload(root = base_path)
|
loader.preload(root = base_path)
|
||||||
loader.run()
|
loader.run()
|
||||||
|
|
||||||
|
|
||||||
# Load migrations
|
# Load migrations
|
||||||
initialize = True
|
if db_exists:
|
||||||
db = Env.get('db_path')
|
|
||||||
if os.path.isfile(db_path):
|
|
||||||
initialize = False
|
|
||||||
|
|
||||||
from migrate.versioning.api import version_control, db_version, version, upgrade
|
from migrate.versioning.api import version_control, db_version, version, upgrade
|
||||||
repo = os.path.join(base_path, 'couchpotato', 'core', 'migration')
|
repo = os.path.join(base_path, 'couchpotato', 'core', 'migration')
|
||||||
@@ -201,7 +200,8 @@ def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, En
|
|||||||
from couchpotato.core.settings.model import setup
|
from couchpotato.core.settings.model import setup
|
||||||
setup()
|
setup()
|
||||||
|
|
||||||
if initialize:
|
# Fill database with needed stuff
|
||||||
|
if not db_exists:
|
||||||
fireEvent('app.initialize', in_order = True)
|
fireEvent('app.initialize', in_order = True)
|
||||||
|
|
||||||
# Create app
|
# Create app
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 143 KiB |
@@ -281,6 +281,47 @@ var CouchPotato = new Class({
|
|||||||
window.open(url);
|
window.open(url);
|
||||||
else
|
else
|
||||||
window.location = url;
|
window.location = url;
|
||||||
|
},
|
||||||
|
|
||||||
|
createUserscriptButtons: function(){
|
||||||
|
|
||||||
|
var userscript = false;
|
||||||
|
try {
|
||||||
|
if(Components.interfaces.gmIGreasemonkeyService)
|
||||||
|
userscript = true
|
||||||
|
}
|
||||||
|
catch(e){
|
||||||
|
userscript = Browser.chrome === true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var host_url = window.location.protocol + '//' + window.location.host;
|
||||||
|
|
||||||
|
return new Element('div.group_userscript').adopt(
|
||||||
|
(userscript ? [new Element('a.userscript.button', {
|
||||||
|
'text': 'Install userscript',
|
||||||
|
'href': Api.createUrl('userscript.get')+randomString()+'/couchpotato.user.js',
|
||||||
|
'target': '_self'
|
||||||
|
}), new Element('span.or[text=or]')] : null),
|
||||||
|
new Element('span.bookmarklet').adopt(
|
||||||
|
new Element('a.button.orange', {
|
||||||
|
'text': '+CouchPotato',
|
||||||
|
'href': "javascript:void((function(){var e=document.createElement('script');e.setAttribute('type','text/javascript');e.setAttribute('charset','UTF-8');e.setAttribute('src','" +
|
||||||
|
host_url + Api.createUrl('userscript.bookmark') +
|
||||||
|
"?host="+ encodeURI(host_url + Api.createUrl('userscript.get')+randomString()+'/') +
|
||||||
|
"&r='+Math.random()*99999999);document.body.appendChild(e)})());",
|
||||||
|
'target': '',
|
||||||
|
'events': {
|
||||||
|
'click': function(e){
|
||||||
|
(e).stop()
|
||||||
|
alert('Drag it to your bookmark ;)')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
new Element('span', {
|
||||||
|
'text': '⇽ Drag this to your bookmarks'
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ Page.Settings = new Class({
|
|||||||
if(self.tabs[tab_name] && self.tabs[tab_name].tab)
|
if(self.tabs[tab_name] && self.tabs[tab_name].tab)
|
||||||
return self.tabs[tab_name].tab
|
return self.tabs[tab_name].tab
|
||||||
|
|
||||||
var label = (tab.label || tab.name || tab_name).capitalize()
|
var label = tab.label || (tab.name || tab_name).capitalize()
|
||||||
var tab_el = new Element('li.t_'+tab_name).adopt(
|
var tab_el = new Element('li.t_'+tab_name).adopt(
|
||||||
new Element('a', {
|
new Element('a', {
|
||||||
'href': App.createUrl(self.name+'/'+tab_name),
|
'href': App.createUrl(self.name+'/'+tab_name),
|
||||||
@@ -244,7 +244,7 @@ Page.Settings = new Class({
|
|||||||
if(!parent_tab.subtabs_el)
|
if(!parent_tab.subtabs_el)
|
||||||
parent_tab.subtabs_el = new Element('ul.subtabs').inject(parent_tab.tab);
|
parent_tab.subtabs_el = new Element('ul.subtabs').inject(parent_tab.tab);
|
||||||
|
|
||||||
var label = (tab.label || tab.name || tab_name).capitalize()
|
var label = tab.label || (tab.name || tab_name.replace('_', ' ')).capitalize()
|
||||||
var tab_el = new Element('li.t_'+tab_name).adopt(
|
var tab_el = new Element('li.t_'+tab_name).adopt(
|
||||||
new Element('a', {
|
new Element('a', {
|
||||||
'href': App.createUrl(self.name+'/'+parent_tab_name+'/'+tab_name),
|
'href': App.createUrl(self.name+'/'+parent_tab_name+'/'+tab_name),
|
||||||
@@ -274,7 +274,7 @@ Page.Settings = new Class({
|
|||||||
'class': (group.advanced ? 'inlineLabels advanced' : 'inlineLabels') + ' group_' + (group.name || '') + ' subtab_' + (group.subtab || '')
|
'class': (group.advanced ? 'inlineLabels advanced' : 'inlineLabels') + ' group_' + (group.name || '') + ' subtab_' + (group.subtab || '')
|
||||||
}).adopt(
|
}).adopt(
|
||||||
new Element('h2', {
|
new Element('h2', {
|
||||||
'text': (group.label || group.name).capitalize()
|
'text': group.label || (group.name).capitalize()
|
||||||
}).adopt(
|
}).adopt(
|
||||||
new Element('span.hint', {
|
new Element('span.hint', {
|
||||||
'html': group.description || ''
|
'html': group.description || ''
|
||||||
@@ -635,7 +635,7 @@ Option.Directory = new Class({
|
|||||||
),
|
),
|
||||||
self.dir_list = new Element('ul', {
|
self.dir_list = new Element('ul', {
|
||||||
'events': {
|
'events': {
|
||||||
'click:relay(li)': function(e, el){
|
'click:relay(li:not(.empty))': function(e, el){
|
||||||
(e).preventDefault();
|
(e).preventDefault();
|
||||||
self.selectDirectory(el.get('data-value'))
|
self.selectDirectory(el.get('data-value'))
|
||||||
},
|
},
|
||||||
@@ -701,12 +701,24 @@ Option.Directory = new Class({
|
|||||||
fillBrowser: function(json){
|
fillBrowser: function(json){
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var v = self.input.get('text');
|
self.data = json;
|
||||||
|
|
||||||
|
var v = self.getValue();
|
||||||
var previous_dir = self.getParentDir();
|
var previous_dir = self.getParentDir();
|
||||||
|
|
||||||
|
if(v == '')
|
||||||
|
self.input.set('text', json.home);
|
||||||
|
|
||||||
if(previous_dir != v && previous_dir.length >= 1 && !json.is_root){
|
if(previous_dir != v && previous_dir.length >= 1 && !json.is_root){
|
||||||
|
|
||||||
|
var prev_dirname = self.getCurrentDirname(previous_dir);
|
||||||
|
if(previous_dir == json.home)
|
||||||
|
prev_dirname = 'Home';
|
||||||
|
else if (previous_dir == '/' && json.platform == 'nt')
|
||||||
|
prev_dirname = 'Computer';
|
||||||
|
|
||||||
self.back_button.set('data-value', previous_dir)
|
self.back_button.set('data-value', previous_dir)
|
||||||
self.back_button.set('html', '« '+self.getCurrentDirname(previous_dir))
|
self.back_button.set('html', '« '+prev_dirname)
|
||||||
self.back_button.show()
|
self.back_button.show()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -719,23 +731,24 @@ Option.Directory = new Class({
|
|||||||
else
|
else
|
||||||
self.cached[v] = json;
|
self.cached[v] = json;
|
||||||
|
|
||||||
setTimeout(function(){
|
self.dir_list.empty();
|
||||||
self.dir_list.empty();
|
if(json.dirs.length > 0)
|
||||||
json.dirs.each(function(dir){
|
json.dirs.each(function(dir){
|
||||||
if(dir.indexOf(v) != -1){
|
new Element('li', {
|
||||||
new Element('li', {
|
'data-value': dir,
|
||||||
'data-value': dir,
|
'text': self.getCurrentDirname(dir)
|
||||||
'text': self.getCurrentDirname(dir)
|
}).inject(self.dir_list)
|
||||||
}).inject(self.dir_list)
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}, 50);
|
else
|
||||||
|
new Element('li.empty', {
|
||||||
|
'text': 'Selected folder is empty'
|
||||||
|
}).inject(self.dir_list)
|
||||||
},
|
},
|
||||||
|
|
||||||
getDirs: function(){
|
getDirs: function(){
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var c = self.input.get('text');
|
var c = self.getValue();
|
||||||
|
|
||||||
if(self.cached[c] && self.use_cache){
|
if(self.cached[c] && self.use_cache){
|
||||||
self.fillBrowser()
|
self.fillBrowser()
|
||||||
@@ -754,7 +767,10 @@ Option.Directory = new Class({
|
|||||||
getParentDir: function(dir){
|
getParentDir: function(dir){
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var v = dir || self.input.get('text');
|
if(!dir && self.data && self.data.parent)
|
||||||
|
return self.data.parent;
|
||||||
|
|
||||||
|
var v = dir || self.getValue();
|
||||||
var sep = Api.getOption('path_sep');
|
var sep = Api.getOption('path_sep');
|
||||||
var dirs = v.split(sep);
|
var dirs = v.split(sep);
|
||||||
if(dirs.pop() == '')
|
if(dirs.pop() == '')
|
||||||
|
|||||||
@@ -10,16 +10,73 @@ Page.Wanted = new Class({
|
|||||||
|
|
||||||
if(!self.wanted){
|
if(!self.wanted){
|
||||||
|
|
||||||
|
self.manual_search = new Element('a', {
|
||||||
|
'title': 'Force a search for the full wanted list',
|
||||||
|
'text': 'Search all wanted',
|
||||||
|
'events':{
|
||||||
|
'click': self.doFullSearch.bind(self, true)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// See if userscript can be installed
|
||||||
|
|
||||||
|
|
||||||
// Wanted movies
|
// Wanted movies
|
||||||
self.wanted = new MovieList({
|
self.wanted = new MovieList({
|
||||||
'identifier': 'wanted',
|
'identifier': 'wanted',
|
||||||
'status': 'active',
|
'status': 'active',
|
||||||
'actions': MovieActions,
|
'actions': MovieActions,
|
||||||
'add_new': true
|
'add_new': true,
|
||||||
|
'menu': [self.manual_search],
|
||||||
|
'on_empty_element': App.createUserscriptButtons().setStyles({
|
||||||
|
'background-image': "url('"+Api.createUrl('static/images/emptylist.png')+"')",
|
||||||
|
'height': 750,
|
||||||
|
'width': 800,
|
||||||
|
'padding-top': 260,
|
||||||
|
'margin-top': -50
|
||||||
|
})
|
||||||
});
|
});
|
||||||
$(self.wanted).inject(self.el);
|
$(self.wanted).inject(self.el);
|
||||||
|
|
||||||
|
// Check if search is in progress
|
||||||
|
self.startProgressInterval();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
doFullSearch: function(full){
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if(!self.search_in_progress){
|
||||||
|
|
||||||
|
Api.request('searcher.full_search');
|
||||||
|
self.startProgressInterval();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
startProgressInterval: function(){
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var start_text = self.manual_search.get('text');
|
||||||
|
self.progress_interval = setInterval(function(){
|
||||||
|
Api.request('searcher.progress', {
|
||||||
|
'onComplete': function(json){
|
||||||
|
self.search_in_progress = true;
|
||||||
|
if(!json.progress){
|
||||||
|
clearInterval(self.progress_interval);
|
||||||
|
self.search_in_progress = false;
|
||||||
|
self.manual_search.set('text', start_text);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var progress = json.progress;
|
||||||
|
self.manual_search.set('text', 'Searching.. (' + (((progress.total-progress.to_go)/progress.total)*100).round() + '%)');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
@@ -222,7 +279,7 @@ window.addEvent('domready', function(){
|
|||||||
movie.set('tween', {
|
movie.set('tween', {
|
||||||
'duration': 300,
|
'duration': 300,
|
||||||
'onComplete': function(){
|
'onComplete': function(){
|
||||||
movie.destroy();
|
self.movie.destroy()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
movie.tween('height', 0);
|
movie.tween('height', 0);
|
||||||
|
|||||||
@@ -376,22 +376,12 @@ body > .spinner, .mask{
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.select .list:before {
|
|
||||||
content: ' ';
|
|
||||||
height: 0;
|
|
||||||
position: absolute;
|
|
||||||
width: 0;
|
|
||||||
border: 6px solid transparent;
|
|
||||||
border-bottom-color: #282d34;
|
|
||||||
margin: -11px 0 0 70px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select .list {
|
.select .list {
|
||||||
display: none;
|
display: none;
|
||||||
background: #282d34;
|
background: #282d34;
|
||||||
border: 1px solid #1f242b;
|
border: 1px solid #1f242b;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
margin: 30px 0 0 0;
|
margin: 28px 0 0 0;
|
||||||
box-shadow: 0 20px 20px -10px rgba(0,0,0,0.4);
|
box-shadow: 0 20px 20px -10px rgba(0,0,0,0.4);
|
||||||
border-radius:3px;
|
border-radius:3px;
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
|
|||||||
@@ -236,6 +236,19 @@
|
|||||||
background-color: #515c68;
|
background-color: #515c68;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.page .directory_list li.empty {
|
||||||
|
background: none;
|
||||||
|
height: 100px;
|
||||||
|
text-align: center;
|
||||||
|
font-style: italic;
|
||||||
|
border: none;
|
||||||
|
line-height: 100px;
|
||||||
|
cursor: default;
|
||||||
|
color: #BBB;
|
||||||
|
text-shadow: none;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
.page .directory_list .actions {
|
.page .directory_list .actions {
|
||||||
clear: both;
|
clear: both;
|
||||||
padding: 4% 4% 2%;
|
padding: 4% 4% 2%;
|
||||||
@@ -319,12 +332,11 @@
|
|||||||
|
|
||||||
.page .tag_input > ul {
|
.page .tag_input > ul {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding: 3px 0;
|
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
cursor: text;
|
cursor: text;
|
||||||
width: 30%;
|
width: 30%;
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
height: 27px;
|
min-height: 27px;
|
||||||
line-height: 0;
|
line-height: 0;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
@@ -339,7 +351,7 @@
|
|||||||
min-width: 2px;
|
min-width: 2px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0 !important;
|
margin: 4px 0 0 !important;
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
background: 0;
|
background: 0;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
@@ -400,7 +412,7 @@
|
|||||||
margin: -9px 0 0 -16px;
|
margin: -9px 0 0 -16px;
|
||||||
border-radius: 30px 30px 0 0;
|
border-radius: 30px 30px 0 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background: url('../../images/icon.delete.png') no-repeat center 2px, -webkit-linear-gradient(
|
background: url('../../images/icon.delete.png') no-repeat center 2px, linear-gradient(
|
||||||
270deg,
|
270deg,
|
||||||
#5b9bd1 0%,
|
#5b9bd1 0%,
|
||||||
#5b9bd1 100%
|
#5b9bd1 100%
|
||||||
|
|||||||
Reference in New Issue
Block a user