Browse Source

Switched event system (again)

pull/1/merge
Ruud 14 years ago
parent
commit
f9523444f4
  1. 45
      couchpotato/api/__init__.py
  2. 13
      couchpotato/cli.py
  3. 3
      couchpotato/core/__init__.py
  4. 2
      couchpotato/core/auth.py
  5. 37
      couchpotato/core/event.py
  6. 37
      couchpotato/core/helpers.py
  7. 86
      couchpotato/core/loader.py
  8. 4
      couchpotato/core/plugins/base.py
  9. 6
      couchpotato/core/plugins/file_browser/__init__.py
  10. 18
      couchpotato/core/plugins/file_browser/main.py
  11. 6
      couchpotato/core/plugins/movie_add/__init__.py
  12. 30
      couchpotato/core/plugins/movie_add/main.py
  13. 3
      couchpotato/core/plugins/renamer/__init__.py
  14. 57
      couchpotato/core/providers/base.py
  15. 4
      couchpotato/core/providers/imdb/__init__.py
  16. 83
      couchpotato/core/providers/imdb/main.py
  17. 5
      couchpotato/core/providers/tmdb/__init__.py
  18. 92
      couchpotato/core/providers/tmdb/main.py
  19. 56
      couchpotato/core/settings/__init__.py
  20. 79
      couchpotato/core/settings/loader.py
  21. 12
      couchpotato/environment.py
  22. 10
      couchpotato/static/scripts/block.js
  23. 32
      couchpotato/static/scripts/block/search.js
  24. 2
      couchpotato/static/scripts/couchpotato.js

45
couchpotato/api/__init__.py

@ -1,42 +1,20 @@
from couchpotato.api.file_browser import FileBrowser
from couchpotato.core.settings.loader import settings_loader
from couchpotato.core.settings.model import Resource from couchpotato.core.settings.model import Resource
from couchpotato.environment import Env
from flask import Module from flask import Module
from flask.helpers import jsonify from flask.helpers import jsonify
import flask
api = Module(__name__) api = Module(__name__)
def addApiView(route, func):
api.add_url_rule(route + '/', route, func)
@api.route('') @api.route('')
def index(): def index():
return jsonify({'test': 'bla'}) return jsonify({'test': 'bla'})
@api.route('settings/')
def settings_view():
return jsonify({
'sections': settings_loader.sections,
'values': Env.get('settings').getValues()
})
@api.route('setting.save/')
def setting_save_view():
a = flask.request.args
section = a.get('section')
option = a.get('name')
value = a.get('value')
Env.setting(option, section, value).save()
return jsonify({
'success': True,
});
@api.route('movie/') @api.route('movie/')
def movie(): def movie():
return jsonify({ return jsonify({
'success': True, 'success': True,
'movies': [ 'movies': [
@ -50,18 +28,3 @@ def movie():
} }
] ]
}) })
@api.route('directory.list/')
def director_list():
a = flask.request.args
try:
fb = FileBrowser(a.get('path', '/'))
dirs = fb.getDirectories()
except:
dirs = []
return jsonify({
'empty': len(dirs) == 0,
'dirs': dirs,
})

13
couchpotato/cli.py

@ -2,7 +2,6 @@ from argparse import ArgumentParser
from couchpotato import get_engine, web from couchpotato import get_engine, web
from couchpotato.api import api from couchpotato.api import api
from couchpotato.core.settings.model import * from couchpotato.core.settings.model import *
from couchpotato.environment import Env
from libs.daemon import createDaemon from libs.daemon import createDaemon
from logging import handlers from logging import handlers
import logging import logging
@ -44,10 +43,12 @@ def cmd_couchpotato(base_path, args):
# Register environment settings # Register environment settings
from couchpotato.environment import Env
Env.get('settings').setFile(os.path.join(options.data_dir, 'settings.conf')) Env.get('settings').setFile(os.path.join(options.data_dir, 'settings.conf'))
Env.set('app_dir', base_path) Env.set('app_dir', base_path)
Env.set('data_dir', options.data_dir) Env.set('data_dir', options.data_dir)
Env.set('db_path', 'sqlite:///' + os.path.join(options.data_dir, 'couchpotato.db')) Env.set('db_path', 'sqlite:///' + os.path.join(options.data_dir, 'couchpotato.db'))
Env.set('cache_dir', os.path.join(options.data_dir, 'cache'))
Env.set('quiet', options.quiet) Env.set('quiet', options.quiet)
Env.set('daemonize', options.daemonize) Env.set('daemonize', options.daemonize)
Env.set('args', args) Env.set('args', args)
@ -84,11 +85,11 @@ def cmd_couchpotato(base_path, args):
log.debug('Started with options %s' % options) log.debug('Started with options %s' % options)
# Load configs # Load configs & plugins
from couchpotato.core.settings.loader import settings_loader loader = Env.get('loader')
settings_loader.load(root = base_path) loader.preload(root = base_path)
settings_loader.addConfig('couchpotato', 'core') loader.addModule('core', 'couchpotato.core', 'core')
settings_loader.run() loader.run()
# Load migrations # Load migrations

3
couchpotato/core/__init__.py

@ -1,5 +1,8 @@
from uuid import uuid4 from uuid import uuid4
def start():
pass
config = [{ config = [{
'name': 'global', 'name': 'global',
'tab': 'general', 'tab': 'general',

2
couchpotato/core/auth.py

@ -15,7 +15,7 @@ def requires_auth(f):
@wraps(f) @wraps(f)
def decorated(*args, **kwargs): def decorated(*args, **kwargs):
auth = request.authorization auth = getattr(request, 'authorization')
if Env.setting('username') and (not auth or not check_auth(auth.username, auth.password)): if Env.setting('username') and (not auth or not check_auth(auth.username, auth.password)):
return authenticate() return authenticate()

37
couchpotato/core/event.py

@ -0,0 +1,37 @@
from couchpotato.core.logger import CPLog
from axl.axel import Event
log = CPLog(__name__)
events = {}
def addEvent(name, handler):
if events.get(name):
e = events[name]
else:
e = events[name] = Event(threads = 20, exc_info = True, traceback = True)
e += handler
def removeEvent(name, handler):
e = events[name]
e -= handler
def fireEvent(name, *args, **kwargs):
try:
e = events[name]
e.asynchronous = False
return e(*args, **kwargs)
except Exception, e:
log.debug(e)
def fireEventAsync(name, *args, **kwargs):
try:
e = events[name]
e.asynchronous = True
return e(*args, **kwargs)
except Exception, e:
log.debug(e)
def getEvent(name):
return events[name]

37
couchpotato/core/helpers.py

@ -0,0 +1,37 @@
def latinToAscii(unicrap):
xlate = {0xc0:'A', 0xc1:'A', 0xc2:'A', 0xc3:'A', 0xc4:'A', 0xc5:'A',
0xc6:'Ae', 0xc7:'C',
0xc8:'E', 0xc9:'E', 0xca:'E', 0xcb:'E', 0x86:'e',
0xcc:'I', 0xcd:'I', 0xce:'I', 0xcf:'I',
0xd0:'Th', 0xd1:'N',
0xd2:'O', 0xd3:'O', 0xd4:'O', 0xd5:'O', 0xd6:'O', 0xd8:'O',
0xd9:'U', 0xda:'U', 0xdb:'U', 0xdc:'U',
0xdd:'Y', 0xde:'th', 0xdf:'ss',
0xe0:'a', 0xe1:'a', 0xe2:'a', 0xe3:'a', 0xe4:'a', 0xe5:'a',
0xe6:'ae', 0xe7:'c',
0xe8:'e', 0xe9:'e', 0xea:'e', 0xeb:'e',
0xec:'i', 0xed:'i', 0xee:'i', 0xef:'i',
0xf0:'th', 0xf1:'n',
0xf2:'o', 0xf3:'o', 0xf4:'o', 0xf5:'o', 0xf6:'o', 0xf8:'o',
0xf9:'u', 0xfa:'u', 0xfb:'u', 0xfc:'u',
0xfd:'y', 0xfe:'th', 0xff:'y',
0xa1:'!', 0xa2:'{cent}', 0xa3:'{pound}', 0xa4:'{currency}',
0xa5:'{yen}', 0xa6:'|', 0xa7:'{section}', 0xa8:'{umlaut}',
0xa9:'{C}', 0xaa:'{^a}', 0xab:'<<', 0xac:'{not}',
0xad:'-', 0xae:'{R}', 0xaf:'_', 0xb0:'{degrees}',
0xb1:'{+/-}', 0xb2:'{^2}', 0xb3:'{^3}', 0xb4:"'",
0xb5:'{micro}', 0xb6:'{paragraph}', 0xb7:'*', 0xb8:'{cedilla}',
0xb9:'{^1}', 0xba:'{^o}', 0xbb:'>>',
0xbc:'{1/4}', 0xbd:'{1/2}', 0xbe:'{3/4}', 0xbf:'?',
0xd7:'*', 0xf7:'/'
}
r = ''
for i in unicrap:
if xlate.has_key(ord(i)):
r += xlate[ord(i)]
elif ord(i) >= 0x80:
pass
else:
r += str(i)
return r

86
couchpotato/core/loader.py

@ -0,0 +1,86 @@
from couchpotato.core.event import fireEvent, fireEventAsync
from couchpotato.core.logger import CPLog
import glob
import os
log = CPLog(__name__)
class Loader:
plugins = {}
providers = {}
modules = {}
def preload(self, root = ''):
self.paths = {
'plugin' : ('couchpotato.core.plugins', os.path.join(root, 'couchpotato', 'core', 'plugins')),
'provider' : ('couchpotato.core.providers', os.path.join(root, 'couchpotato', 'core', 'providers')),
}
for type, tuple in self.paths.iteritems():
self.addFromDir(type, tuple[0], tuple[1])
def run(self):
did_save = 0
for module_name, plugin in sorted(self.modules.iteritems()):
# Load module
m = getattr(self.loadModule(module_name), plugin.get('name'))
log.info("Loading '%s'" % module_name)
# Save default settings for plugin/provider
did_save += self.loadSettings(m, module_name, save = False)
self.loadPlugins(m, plugin.get('name'))
if did_save:
fireEvent('settings.save')
def addFromDir(self, type, module, dir):
for file in glob.glob(os.path.join(dir, '*')):
name = os.path.basename(file)
if os.path.isdir(os.path.join(dir, name)):
module_name = '%s.%s' % (module, name)
self.addModule(type, module_name, name)
def loadSettings(self, module, name, save = True):
try:
for section in module.config:
fireEventAsync('settings.options', section['name'], section)
options = {}
for key, option in section['options'].iteritems():
options[key] = option['default']
fireEventAsync('settings.register', section_name = section['name'], options = options, save = save)
return True
except Exception, e:
log.debug("Failed loading settings for '%s': %s" % (name, e))
return False
def loadPlugins(self, module, name):
try:
module.start()
return True
except Exception, e:
log.debug("Failed loading plugin '%s': %s" % (name, e))
return False
def addModule(self, type, module, name):
self.modules[module] = {
'type': type,
'name': name,
}
def loadModule(self, name):
try:
m = __import__(name)
splitted = name.split('.')
for sub in splitted[1:-1]:
m = getattr(m, sub)
return m
except:
raise

4
couchpotato/core/plugins/base.py

@ -0,0 +1,4 @@
class Plugin():
def __init__(self):
pass

6
couchpotato/core/plugins/file_browser/__init__.py

@ -0,0 +1,6 @@
from couchpotato.core.plugins.file_browser.main import FileBrowser
def start():
return FileBrowser()
config = []

18
couchpotato/api/file_browser.py → couchpotato/core/plugins/file_browser/main.py

@ -1,3 +1,6 @@
from couchpotato.api import addApiView
from couchpotato.environment import Env
from flask.helpers import jsonify
import os import os
import string import string
@ -9,6 +12,8 @@ class FileBrowser():
def __init__(self, path = '/'): def __init__(self, path = '/'):
self.path = path self.path = path
addApiView('directory.list', self.view)
def getDirectories(self): def getDirectories(self):
# Return driveletters or root if path is empty # Return driveletters or root if path is empty
@ -36,3 +41,16 @@ class FileBrowser():
driveletters.append(drive + ":") driveletters.append(drive + ":")
return driveletters return driveletters
def view(self):
try:
fb = FileBrowser(Env.getParam('path', '/'))
dirs = fb.getDirectories()
except:
dirs = []
return jsonify({
'empty': len(dirs) == 0,
'dirs': dirs,
})

6
couchpotato/core/plugins/movie_add/__init__.py

@ -0,0 +1,6 @@
from couchpotato.core.plugins.movie_add.main import MovieAdd
def start():
return MovieAdd()
config = []

30
couchpotato/core/plugins/movie_add/main.py

@ -0,0 +1,30 @@
from couchpotato.api import addApiView
from couchpotato.core.event import getEvent, fireEvent
from couchpotato.core.plugins.base import Plugin
from couchpotato.environment import Env
from flask.helpers import jsonify
class MovieAdd(Plugin):
def __init__(self):
addApiView('movie.add.search', self.search)
def search(self):
a = Env.getParams()
print fireEvent('provider.movie.search', q = a.get('q'))
movies = [
{'id': 1, 'name': 'test'}
]
return jsonify({
'success': True,
'empty': len(movies) == 0,
'movies': movies,
})
def select(self):
pass

3
couchpotato/core/plugins/renamer/__init__.py

@ -1,3 +1,6 @@
def start():
pass
config = [{ config = [{
'name': 'Renamer', 'name': 'Renamer',
'tab': 'renaming', 'tab': 'renaming',

57
couchpotato/core/providers/base.py

@ -0,0 +1,57 @@
from couchpotato.core.helpers import latinToAscii
from couchpotato.core.logger import CPLog
from string import ascii_letters, digits
import re
import unicodedata
import xml.etree.ElementTree as XMLTree
log = CPLog(__name__)
class Provider():
type = None # movie, nzb, torrent, subtitle, trailer
timeout = 10 # Default timeout for url requests
def __init__(self):
pass
def toSaveString(self, string):
string = latinToAscii(string)
string = ''.join((c for c in unicodedata.normalize('NFD', unicode(string)) if unicodedata.category(c) != 'Mn'))
safe_chars = ascii_letters + digits + '_ -.,\':!?'
r = ''.join([char if char in safe_chars else ' ' for char in string])
return re.sub('\s+' , ' ', r)
def toSearchString(self, string):
string = latinToAscii(string)
string = ''.join((c for c in unicodedata.normalize('NFD', unicode(string)) if unicodedata.category(c) != 'Mn'))
safe_chars = ascii_letters + digits + ' \''
r = ''.join([char if char in safe_chars else ' ' for char in string])
return re.sub('\s+' , ' ', r).replace('\'s', 's').replace('\'', ' ')
def gettextelements(self, xml, path):
''' Find elements and return tree'''
textelements = []
try:
elements = xml.findall(path)
except:
return
for element in elements:
textelements.append(element.text)
return textelements
def gettextelement(self, xml, path):
''' Find element and return text'''
try:
return xml.find(path).text
except:
return
def getItems(self, data, path = 'channel/item'):
try:
return XMLTree.parse(data).findall(path)
except Exception, e:
log.error('Error parsing RSS. %s' % e)
return []

4
couchpotato/core/providers/imdb/__init__.py

@ -0,0 +1,4 @@
def start():
pass
config = []

83
couchpotato/core/providers/imdb/main.py

@ -0,0 +1,83 @@
from couchpotato.core.event import addEvent
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.base import Provider
from imdb import IMDb
log = CPLog(__name__)
class IMDB(Provider):
type = 'movie'
def __init__(self):
addEvent('provider.movie.search', self.search)
self.p = IMDb('http')
def search(self):
print 'search'
def conf(self, option):
return self.config.get('IMDB', option)
def find(self, q, limit = 8, alternative = True):
''' Find movie by name '''
log.info('IMDB - Searching for movie: %s' % q)
r = self.p.search_movie(q)
return self.toResults(r, limit)
def toResults(self, r, limit = 8, one = False):
results = []
if one:
new = self.feedItem()
new.imdb = 'tt' + r.movieID
new.name = self.toSaveString(r['title'])
try:
new.year = r['year']
except:
new.year = ''
return new
else :
nr = 0
for movie in r:
results.append(self.toResults(movie, one = True))
nr += 1
if nr == limit:
break
return results
def findById(self, id):
''' Find movie by TheMovieDB ID '''
return []
def findByImdbId(self, id, details = False):
''' Find movie by IMDB ID '''
log.info('IMDB - Searching for movie: %s' % str(id))
r = self.p.get_movie(id.replace('tt', ''))
if not details:
return self.toResults(r, one = True)
else:
self.p.update(r)
self.p.update(r, info = 'release dates')
self.p.update(r, info = 'taglines')
return r
def get_IMDb_instance(self):
return IMDb('http')
def findReleaseDate(self, movie):
pass

5
couchpotato/core/providers/tmdb/__init__.py

@ -1,3 +1,8 @@
from couchpotato.core.providers.tmdb.main import TMDB
def start():
return TMDB()
config = [{ config = [{
'name': 'TheMovieDB', 'name': 'TheMovieDB',
'tab': 'providers', 'tab': 'providers',

92
couchpotato/core/providers/tmdb/main.py

@ -0,0 +1,92 @@
from __future__ import with_statement
from couchpotato.core.event import addEvent
from couchpotato.core.logger import CPLog
from couchpotato.core.providers.base import Provider
from couchpotato.environment import Env
from urllib import quote_plus
import urllib2
log = CPLog(__name__)
class TMDB(Provider):
"""Api for theMovieDb"""
type = 'movie'
apiUrl = 'http://api.themoviedb.org/2.1'
imageUrl = 'http://hwcdn.themoviedb.org'
def __init__(self):
addEvent('provider.movie.search', self.search)
def conf(self, attr):
return Env.setting(attr, 'TheMovieDB')
def search(self, q, limit = 8, alternative = True):
''' Find movie by name '''
if self.isDisabled():
return False
log.debug('TheMovieDB - Searching for movie: %s' % q)
url = "%s/%s/%s/xml/%s/%s" % (self.apiUrl, 'Movie.search', 'en', self.conf('api_key'), quote_plus(self.toSearchString(q)))
log.info('Searching: %s' % url)
data = urllib2.urlopen(url)
return self.parseXML(data, limit, alternative = alternative)
def parseXML(self, data, limit, alternative = True):
if data:
log.debug('TheMovieDB - Parsing RSS')
try:
xml = self.getItems(data, 'movies/movie')
results = []
nr = 0
for movie in xml:
id = int(self.gettextelement(movie, "id"))
name = self.gettextelement(movie, "name")
imdb = self.gettextelement(movie, "imdb_id")
year = str(self.gettextelement(movie, "released"))[:4]
# 1900 is the same as None
if year == '1900':
year = 'None'
results.append({
'id': id,
'name': self.toSaveString(name),
'imdb': imdb,
'year': year
})
alternativeName = self.gettextelement(movie, "alternative_name")
if alternativeName and alternative:
if alternativeName.lower() != name.lower() and alternativeName.lower() != 'none' and alternativeName != None:
results.append({
'id': id,
'name': self.toSaveString(alternativeName),
'imdb': imdb,
'year': year
})
nr += 1
if nr == limit:
break
#log.info('TheMovieDB - Found: %s' % results)
return results
except SyntaxError:
log.error('TheMovieDB - Failed to parse XML response from TheMovieDb')
return False
def isDisabled(self):
if self.conf('api_key') == '':
log.error('TheMovieDB - No API key provided for TheMovieDB')
True
else:
False

56
couchpotato/core/settings/__init__.py

@ -1,5 +1,7 @@
from __future__ import with_statement from __future__ import with_statement
from blinker import signal, Signal from couchpotato.api import addApiView
from couchpotato.core.event import addEvent
from flask.helpers import jsonify
import ConfigParser import ConfigParser
import os.path import os.path
import time import time
@ -7,10 +9,13 @@ import time
class Settings(): class Settings():
on_save = Signal()
on_register = Signal()
bool = {'true':True, 'false':False} bool = {'true':True, 'false':False}
options = {}
def __init__(self):
addApiView('settings', self.view)
addApiView('settings.save', self.saveView)
def setFile(self, file): def setFile(self, file):
self.file = file self.file = file
@ -21,7 +26,7 @@ class Settings():
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
self.log = CPLog(__name__) self.log = CPLog(__name__)
self.connectSignals() self.connectEvents()
def parser(self): def parser(self):
return self.p return self.p
@ -29,18 +34,17 @@ class Settings():
def sections(self): def sections(self):
return self.p.sections() return self.p.sections()
def connectSignals(self): def connectEvents(self):
signal('settings.register').connect(self.registerDefaults) addEvent('settings.options', self.addOptions)
signal('settings.save').connect(self.save) addEvent('settings.register', self.registerDefaults)
addEvent('settings.save', self.save)
def registerDefaults(self, section_name, options = {}, save = True): def registerDefaults(self, section_name, options = {}, save = True):
self.addSection(section_name) self.addSection(section_name)
for option, value in options.iteritems(): for option, value in options.iteritems():
self.setDefault(section_name, option, value) self.setDefault(section_name, option, value)
self.log.debug('Defaults for "%s": %s' % (section_name, options)) self.log.debug('Defaults for "%s": %s' % (section_name, options))
self.on_register.send(self)
if save: if save:
self.save(self) self.save(self)
@ -73,12 +77,11 @@ class Settings():
values[section][option_name] = option_value values[section][option_name] = option_value
return values return values
def save(self, caller = ''): def save(self):
with open(self.file, 'wb') as configfile: with open(self.file, 'wb') as configfile:
self.p.write(configfile) self.p.write(configfile)
self.log.debug('Saved settings') self.log.debug('Saved settings')
self.on_save.send(self)
def addSection(self, section): def addSection(self, section):
if not self.p.has_section(section): if not self.p.has_section(section):
@ -94,3 +97,32 @@ class Settings():
return True return True
except ValueError: except ValueError:
return False return False
def addOptions(self, section_name, options):
self.options[section_name] = options
def getOptions(self):
return self.options
def view(self):
return jsonify({
'options': self.getOptions(),
'values': self.getValues()
})
def saveView(self):
a = Env.getParams()
section = a.get('section')
option = a.get('name')
value = a.get('value')
self.set(option, section, value)
self.save()
return jsonify({
'success': True,
})

79
couchpotato/core/settings/loader.py

@ -1,79 +0,0 @@
from blinker import signal
from couchpotato.core.logger import CPLog
import glob
import os
log = CPLog(__name__)
class SettingsLoader:
configs = {}
sections = {}
def __init__(self):
self.settings_register = signal('settings.register')
self.settings_save = signal('settings.save')
def load(self, root = ''):
self.paths = {
'plugins' : ('couchpotato.core.plugins', os.path.join(root, 'couchpotato', 'core', 'plugins')),
'providers' : ('couchpotato.core.providers', os.path.join(root, 'couchpotato', 'core', 'providers')),
}
for type, tuple in self.paths.iteritems():
self.addFromDir(tuple[0], tuple[1])
def run(self):
did_save = 0
for module, plugin_name in self.configs.iteritems():
did_save += self.loadConfig(module, plugin_name, save = False)
if did_save:
self.settings_save.send()
def addFromDir(self, module, dir):
for file in glob.glob(os.path.join(dir, '*')):
name = os.path.basename(file)
if os.path.isdir(os.path.join(dir, name)):
self.addConfig(module, name)
def loadConfig(self, module, name, save = True):
module_name = '%s.%s' % (module, name)
try:
m = getattr(self.loadModule(module_name), name)
for section in m.config:
self.addSection(section['name'], section)
options = {}
for key, option in section['options'].iteritems():
options[key] = option['default']
self.settings_register.send(section['name'], options = options, save = save)
return True
except Exception, e:
log.error("Failed loading config for %s: %s" % (name, e))
return False
def addConfig(self, module, name):
self.configs[module] = name
def loadModule(self, name):
try:
m = __import__(name)
splitted = name.split('.')
for sub in splitted[1:-1]:
m = getattr(m, sub)
return m
except:
raise
def addSection(self, section_name, options):
self.sections[section_name] = options
def getSections(self):
return self.sections
settings_loader = SettingsLoader()

12
couchpotato/environment.py

@ -1,10 +1,13 @@
from couchpotato.core.loader import Loader
from couchpotato.core.settings import Settings from couchpotato.core.settings import Settings
import flask
class Env: class Env:
''' Environment variables ''' ''' Environment variables '''
_debug = False _debug = False
_settings = Settings() _settings = Settings()
_loader = Loader()
_options = None _options = None
_args = None _args = None
_quiet = False _quiet = False
@ -13,6 +16,7 @@ class Env:
''' Data paths and directories ''' ''' Data paths and directories '''
_app_dir = "" _app_dir = ""
_data_dir = "" _data_dir = ""
_cache_dir = ""
_db_path = "" _db_path = ""
@staticmethod @staticmethod
@ -38,3 +42,11 @@ class Env:
s = Env.get('settings') s = Env.get('settings')
s.set(section, attr, value) s.set(section, attr, value)
return s return s
@staticmethod
def getParams():
return getattr(flask.request, 'args')
@staticmethod
def getParam(attr, default = None):
return getattr(flask.request, 'args').get(attr, default)

10
couchpotato/static/scripts/block.js

@ -8,7 +8,7 @@ var BlockBase = new Class({
var self = this; var self = this;
self.setOptions(options); self.setOptions(options);
self.parent = parent; self.page = parent;
self.create(); self.create();
}, },
@ -17,6 +17,14 @@ var BlockBase = new Class({
this.el = new Element('div.block'); this.el = new Element('div.block');
}, },
api: function(){
return this.getParent().getApi()
},
getParent: function(){
return this.page
},
toElement: function(){ toElement: function(){
return this.el return this.el
} }

32
couchpotato/static/scripts/block/search.js

@ -5,7 +5,37 @@ Block.Search = new Class({
create: function(){ create: function(){
var self = this; var self = this;
self.el = new Element('div.search_form'); self.el = new Element('div.search_form').adopt(
self.input = new Element('input', {
'events': {
'keyup': self.autocomplete.bind(self)
}
})
);
},
autocomplete: function(){
var self = this;
if(self.autocomplete_timer) clearTimeout(self.autocomplete_timer)
self.autocomplete_timer = self.list.delay(300, self)
},
list: function(){
var self = this;
if(self.api_request) self.api_request.cancel();
self.api_request = self.api().request('movie.add.search', {
'data': {
'q': self.input.get('value')
},
'onComplete': self.fill.bind(self)
})
},
fill: function(){
} }
}); });

2
couchpotato/static/scripts/couchpotato.js

@ -109,7 +109,7 @@ var Api = new Class({
request: function(type, options){ request: function(type, options){
var self = this; var self = this;
new Request.JSON(Object.merge({ return new Request.JSON(Object.merge({
'method': 'get', 'method': 'get',
'url': self.createUrl(type), 'url': self.createUrl(type),
}, options)).send() }, options)).send()

Loading…
Cancel
Save