Settings, directory browser

This commit is contained in:
Ruud
2011-09-05 22:09:54 +02:00
parent 6430014c56
commit 1e36aeced3
13 changed files with 208 additions and 180 deletions
+1 -2
View File
@@ -4,7 +4,6 @@ import os.path
def isDict(object): def isDict(object):
return isinstance(object, dict) return isinstance(object, dict)
def mergeDicts(a, b): def mergeDicts(a, b):
assert isDict(a), isDict(b) assert isDict(a), isDict(b)
dst = a.copy() dst = a.copy()
@@ -16,7 +15,7 @@ def mergeDicts(a, b):
if key not in current_dst: if key not in current_dst:
current_dst[key] = current_src[key] current_dst[key] = current_src[key]
else: else:
if isDict(current_src[key]) and isDict(current_dst[key]) : if isDict(current_src[key]) and isDict(current_dst[key]):
stack.append((current_dst[key], current_src[key])) stack.append((current_dst[key], current_src[key]))
else: else:
current_dst[key] = current_src[key] current_dst[key] = current_src[key]
-74
View File
@@ -1,75 +1 @@
from uuid import uuid4
def start():
pass
config = [{
'name': 'core',
'groups': [
{
'tab': 'general',
'name': 'basics',
'description': 'Needs restart before changes take effect.',
'options': [
{
'name': 'username',
'default': '',
},
{
'name': 'password',
'default': '',
'type': 'password',
},
{
'name': 'host',
'advanced': True,
'default': '0.0.0.0',
'label': 'IP',
'description': 'Host that I should listen to. "0.0.0.0" listens to all ips.',
},
{
'name': 'port',
'default': 5000,
'type': 'int',
'description': 'The port I should listen to.',
},
{
'name': 'launch_browser',
'default': 1,
'type': 'bool',
'label': 'Launch Browser',
'description': 'Launch the browser when I start.',
},
],
},
{
'tab': 'general',
'name': 'advanced',
'description': "For those who know what the're doing",
'advanced': True,
'options': [
{
'name': 'api_key',
'default': uuid4().hex,
'readonly': 1,
'label': 'Api Key',
'description': "This is top-secret! Don't share this!",
},
{
'name': 'debug',
'default': 0,
'type': 'bool',
'label': 'Debug',
'description': 'Enable debugging.',
},
{
'name': 'url_base',
'default': '',
'label': 'Url Base',
'description': 'When using mod_proxy use this to append the url with this.',
},
],
},
],
}]
+17 -1
View File
@@ -1,6 +1,7 @@
from couchpotato.api import addApiView from couchpotato.api import addApiView
from couchpotato.core.helpers.request import getParam, jsonified from couchpotato.core.helpers.request import getParam, jsonified
from couchpotato.core.plugins.base import Plugin from couchpotato.core.plugins.base import Plugin
import ctypes
import os import os
import string import string
@@ -23,7 +24,7 @@ class FileBrowser(Plugin):
dirs = [] dirs = []
for f in os.listdir(path): for f in os.listdir(path):
p = os.path.join(path, f) p = os.path.join(path, f)
if(os.path.isdir(p)): if os.path.isdir(p) and ((self.is_hidden(p) and bool(int(show_hidden))) or not self.is_hidden(p)):
dirs.append(p + '/') dirs.append(p + '/')
return dirs return dirs
@@ -48,6 +49,21 @@ class FileBrowser(Plugin):
dirs = [] dirs = []
return jsonified({ return jsonified({
'is_root': getParam('path', '/') == '/',
'empty': len(dirs) == 0, 'empty': len(dirs) == 0,
'dirs': dirs, 'dirs': dirs,
}) })
def is_hidden(self, filepath):
name = os.path.basename(os.path.abspath(filepath))
return name.startswith('.') or self.has_hidden_attribute(filepath)
def has_hidden_attribute(self, filepath):
try:
attrs = ctypes.windll.kernel32.GetFileAttributesW(unicode(filepath))
assert attrs != -1
result = bool(attrs & 2)
except (AttributeError, AssertionError):
result = False
return result
+3 -1
View File
@@ -51,7 +51,9 @@ class LibraryPlugin(Plugin):
library = db.query(Library).filter_by(identifier = identifier).first() library = db.query(Library).filter_by(identifier = identifier).first()
done_status = fireEvent('status.get', 'done', single = True) done_status = fireEvent('status.get', 'done', single = True)
library_dict = library.to_dict(self.default_dict) if library:
library_dict = library.to_dict(self.default_dict)
do_update = True do_update = True
if library.status_id == done_status.get('id') and not force: if library.status_id == done_status.get('id') and not force:
+11 -16
View File
@@ -10,6 +10,14 @@ from urllib import urlencode
class MoviePlugin(Plugin): class MoviePlugin(Plugin):
default_dict = {
'profile': {'types': {'quality': {}}},
'releases': {'status': {}, 'quality': {}, 'files':{}, 'info': {}},
'library': {'titles': {}, 'files':{}},
'files': {},
'status': {}
}
def __init__(self): def __init__(self):
addApiView('movie.search', self.search) addApiView('movie.search', self.search)
addApiView('movie.list', self.list) addApiView('movie.list', self.list)
@@ -30,12 +38,7 @@ class MoviePlugin(Plugin):
movies = [] movies = []
for movie in results: for movie in results:
temp = movie.to_dict(deep = { temp = movie.to_dict(self.default_dict)
'releases': {'status': {}, 'quality': {}, 'files':{}, 'info': {}},
'library': {'titles': {}, 'files':{}},
'files': {}
})
movies.append(temp) movies.append(temp)
return jsonified({ return jsonified({
@@ -59,12 +62,7 @@ class MoviePlugin(Plugin):
if movie: if movie:
#addEvent('library.update.after', ) #addEvent('library.update.after', )
fireEventAsync('library.update', identifier = movie.library.identifier, default_title = default_title, force = True) fireEventAsync('library.update', identifier = movie.library.identifier, default_title = default_title, force = True)
fireEventAsync('searcher.single', movie.to_dict(deep = { fireEventAsync('searcher.single', movie.to_dict(self.default_dict))
'profile': {'types': {'quality': {}}},
'releases': {'status': {}, 'quality': {}, 'files': {}, 'info': {}},
'library': {'titles': {}, 'files':{}},
'files': {}
}))
return jsonified({ return jsonified({
'success': True, 'success': True,
@@ -119,10 +117,7 @@ class MoviePlugin(Plugin):
m.status_id = status_active.get('id') m.status_id = status_active.get('id')
db.commit() db.commit()
movie_dict = m.to_dict(deep = { movie_dict = m.to_dict(self.default_dict)
'releases': {'status': {}, 'quality': {}, 'files': {}, 'info': {}},
'library': {'titles': {}}
})
return jsonified({ return jsonified({
'success': True, 'success': True,
+1 -1
View File
@@ -4,7 +4,7 @@ def start():
return Wizard() return Wizard()
config = [{ config = [{
'name': 'global', 'name': 'core',
'groups': [ 'groups': [
{ {
'tab': 'general', 'tab': 'general',
@@ -3,22 +3,4 @@ from .main import ThePirateBay
def start(): def start():
return ThePirateBay() return ThePirateBay()
config = [{ config = []
'name': 'themoviedb',
'groups': [
{
'tab': 'providers',
'name': 'tmdb',
'label': 'TheMovieDB',
'advanced': True,
'description': 'Used for all calls to TheMovieDB.',
'options': [
{
'name': 'api_key',
'default': '9b939aee0aaafc12a65bf448e4af9543',
'label': 'Api Key',
},
],
},
],
}]
+7 -1
View File
@@ -3,6 +3,7 @@ from couchpotato.api import addApiView
from couchpotato.core.event import addEvent from couchpotato.core.event import addEvent
from couchpotato.core.helpers.encoding import isInt from couchpotato.core.helpers.encoding import isInt
from couchpotato.core.helpers.request import getParams, jsonified from couchpotato.core.helpers.request import getParams, jsonified
from couchpotato.core.helpers.variable import mergeDicts
import ConfigParser import ConfigParser
import os.path import os.path
import time import time
@@ -93,7 +94,12 @@ class Settings():
self.p.set(section, option, value) self.p.set(section, option, value)
def addOptions(self, section_name, options): def addOptions(self, section_name, options):
self.options[section_name] = options
if not self.options.get(section_name):
self.options[section_name] = options
else:
options['groups'] = self.options[section_name].get('groups') + options.get('groups')
self.options[section_name] = mergeDicts(self.options[section_name], options)
def getOptions(self): def getOptions(self):
return self.options return self.options
Binary file not shown.

After

Width:  |  Height:  |  Size: 757 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

@@ -114,6 +114,7 @@ Form.Check = new Class({
this.check(); this.check();
} }
this.fireEvent('change', this); this.fireEvent('change', this);
this.input.fireEvent('change', this);
return this; return this;
}, },
uncheck: function() { uncheck: function() {
+66 -38
View File
@@ -479,63 +479,77 @@ Option.Directory = new Class({
type: 'span', type: 'span',
browser: '', browser: '',
save_on_change: false, save_on_change: false,
use_cache: false,
create: function(){ create: function(){
var self = this; var self = this;
self.el.adopt( self.el.adopt(
self.createLabel(), self.createLabel(),
self.input = new Element('span.directory', { new Element('span.directory.inlay', {
'text': self.getSettingValue(),
'events': { 'events': {
'click': self.showBrowser.bind(self) 'click': self.showBrowser.bind(self)
} }
}) }).adopt(
self.input = new Element('span', {
'text': self.getSettingValue()
})
)
); );
self.cached = {}; self.cached = {};
}, },
selectDirectory: function(e, el){ selectDirectory: function(dir){
var self = this; var self = this;
self.input.set('text', el.get('data-value')); self.input.set('text', dir);
self.getDirs() self.getDirs()
self.fireEvent('change')
}, },
previousDirectory: function(e){ previousDirectory: function(e){
var self = this; var self = this;
self.selectDirectory(null, self.back_button) self.selectDirectory(self.getParentDir())
}, },
showBrowser: function(){ showBrowser: function(){
var self = this; var self = this;
if(!self.browser) if(!self.browser){
self.browser = new Element('div.directory_list').adopt( self.browser = new Element('div.directory_list').adopt(
new Element('div.pointer'),
new Element('div.actions').adopt( new Element('div.actions').adopt(
self.back_button = new Element('a.button.back', { self.back_button = new Element('a.back', {
'text': '', 'html': '',
'events': { 'events': {
'click': self.previousDirectory.bind(self) 'click': self.previousDirectory.bind(self)
} }
}), }),
new Element('label', { new Element('label', {
'text': 'Show hidden files' 'text': 'Hidden folders'
}).adopt( }).adopt(
self.show_hidden = new Element('input[type=checkbox].inlay') self.show_hidden = new Element('input[type=checkbox].inlay', {
'events': {
'change': self.getDirs.bind(self)
}
})
) )
), ),
self.dir_list = new Element('ul', { self.dir_list = new Element('ul', {
'events': { 'events': {
'click:relay(li)': self.selectDirectory.bind(self) 'click:relay(li)': function(e, el){
(e).stop();
self.selectDirectory(el.get('data-value'))
},
'mousewheel': function(e){
(e).stopPropagation();
}
} }
}), }),
new Element('div.actions').adopt( new Element('div.actions').adopt(
new Element('a.button.cancel', { new Element('a.cancel', {
'text': 'Cancel', 'text': 'Cancel',
'events': { 'events': {
'click': self.hideBrowser.bind(self) 'click': self.hideBrowser.bind(self)
@@ -547,21 +561,32 @@ Option.Directory = new Class({
self.save_button = new Element('a.button.save', { self.save_button = new Element('a.button.save', {
'text': 'Save', 'text': 'Save',
'events': { 'events': {
'click': self.hideBrowser.bind(self, true) 'click': function(e){
self.hideBrowser(e, true)
}
} }
}) })
) )
).inject(self.input, 'after') ).inject(self.el)
new Form.Check(self.show_hidden);
}
self.initial_directory = self.input.get('text');
self.getDirs() self.getDirs()
self.browser.show() self.browser.show()
self.el.addEvent('outerClick', self.hideBrowser.bind(self)) self.el.addEvent('outerClick', self.hideBrowser.bind(self))
}, },
hideBrowser: function(save){ hideBrowser: function(e, save){
var self = this; var self = this;
(e).stop();
if(save) self.save() if(save)
self.save()
else
self.input.set('text', self.initial_directory);
self.browser.hide() self.browser.hide()
self.el.removeEvent('outerClick', self.hideBrowser.bind(self)) self.el.removeEvent('outerClick', self.hideBrowser.bind(self))
@@ -571,41 +596,43 @@ Option.Directory = new Class({
fillBrowser: function(json){ fillBrowser: function(json){
var self = this; var self = this;
var c = self.getParentDir();
var v = self.input.get('text'); var v = self.input.get('text');
var previous_dir = self.getParentDir(c.substring(0, c.length-1)); var previous_dir = self.getParentDir();
if(previous_dir){ if(previous_dir != v){
self.back_button.set('data-value', previous_dir) self.back_button.set('data-value', previous_dir)
self.back_button.set('text', self.getCurrentDirname(previous_dir)) self.back_button.set('html', '« '+self.getCurrentDirname(previous_dir))
self.back_button.show() self.back_button.show()
} }
else { else {
self.back_button.hide() self.back_button.hide()
} }
if(!json) if(self.use_cache)
json = self.cached[c]; if(!json)
else json = self.cached[v];
self.cached[c] = json; else
self.cached[v] = json;
self.dir_list.empty(); setTimeout(function(){
json.dirs.each(function(dir){ self.dir_list.empty();
if(dir.indexOf(v) != -1){ json.dirs.each(function(dir){
new Element('li', { if(dir.indexOf(v) != -1){
'data-value': dir, new Element('li', {
'text': self.getCurrentDirname(dir) 'data-value': dir,
}).inject(self.dir_list) 'text': self.getCurrentDirname(dir)
} }).inject(self.dir_list)
}) }
});
}, 50);
}, },
getDirs: function(){ getDirs: function(){
var self = this; var self = this;
var c = self.getParentDir(); var c = self.input.get('text');
if(self.cached[c]){ if(self.cached[c] && self.use_cache){
self.fillBrowser() self.fillBrowser()
} }
else { else {
@@ -625,7 +652,8 @@ Option.Directory = new Class({
var v = dir || self.input.get('text'); var v = dir || self.input.get('text');
var sep = Api.getOption('path_sep'); var sep = Api.getOption('path_sep');
var dirs = v.split(sep); var dirs = v.split(sep);
dirs.pop(); if(dirs.pop() == '')
dirs.pop();
return dirs.join(sep) + sep return dirs.join(sep) + sep
}, },
+95 -22
View File
@@ -1,7 +1,15 @@
/* @override http://localhost:5000/static/style/page/settings.css */ /* @override
http://localhost:5000/static/style/page/settings.css
http://192.168.1.20:5000/static/style/page/settings.css
*/
.page.settings { .page.settings:after {
overflow: hidden; content: ".";
display: block;
clear: both;
visibility: hidden;
line-height: 0;
height: 0;
} }
.page.settings .tabs { .page.settings .tabs {
@@ -165,39 +173,104 @@
.page.settings .directory { .page.settings .directory {
display: inline-block; display: inline-block;
padding: 0 4px; padding: 0 4% 0 4px;
font-size: 13px; font-size: 13px;
width: 29.7%; width: 26.3%;
background-image: url('../../images/icon.folder.gif');
background-repeat: no-repeat;
background-position: 97% center;
overflow: hidden;
} }
.page.settings .directory > span {
height: 25px;
display: inline-block;
float: right;
text-align: right;
white-space: nowrap;
cursor: pointer;
}
.page.settings .directory_list { .page.settings .directory_list {
z-index: 2;
position: absolute; position: absolute;
width: 300px; width: 360px;
margin: 0 0 0 16.5%; margin: -2px 0 20px 60px;
background: #282d34; background: #5c697b;
border: 1px solid #1f242b; border-radius: 3px;
position: absolute;
box-shadow: 0 1px 2px rgba(0,0,0,0.4);
-moz-box-shadow: 0 1px 2px rgba(0,0,0,0.4);
-webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.4);
border-radius:3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px; -webkit-border-radius: 3px;
-moz-border-radius: 3px;
box-shadow: 0 0 50px rgba(0,0,0,0.55);
-moz-box-shadow: 0 0 50px rgba(0,0,0,0.55);
-webkit-box-shadow: 0 0 50px rgba(0,0,0,0.55);
} }
.page.settings .directory_list .pointer {
border-right: 10px solid transparent;
border-left: 10px solid transparent;
border-bottom: 10px solid #5c697b;
display: block;
position: absolute;
width: 0px;
margin: -9px 0 0 48.5%;
}
.page.settings .directory_list ul { .page.settings .directory_list ul {
width: 100%; width: 100%;
max-height: 200px; height: 200px;
overflow: auto; overflow: auto;
} }
.page.settings .directory_list li { .page.settings .directory_list li {
padding: 2px 10px; padding: 0 10px;
} cursor: pointer;
margin: 0;
border-top: 1px solid rgba(255,255,255,0.1);
background: url('../../images/right.arrow.png') no-repeat 98% center;
}
.page.settings .directory_list li:last-child {
border-bottom: 1px solid rgba(255,255,255,0.1);
}
.page.settings .directory_list li:hover {
background-color: #515c68;
}
.page.settings .directory_list .actions { .page.settings .directory_list .actions {
clear: both; clear: both;
padding: 10px; padding: 10px;
background: #414953;
} }
.page.settings .directory_list .actions:first-child { border-bottom: 1px solid #1f242b; }
.page.settings .directory_list .actions:last-child { border-top: 1px solid #1f242b; } .page.settings .directory_list .actions {}
.page.settings .directory_list .actions label {
float: right;
width: auto;
padding: 5px 3px;
}
.page.settings .directory_list .actions .inlay {
margin: -2px 0 0 7px;
}
.page.settings .directory_list .actions .back {
font-weight: bold;
width: 160px;
display: inline-block;
}
.page.settings .directory_list .actions:last-child {
float: right;
}
.page.settings .directory_list .actions:last-child > span {
padding: 0 5px;
text-shadow: none;
}
.page.settings .directory_list .actions:last-child > .cancel {
font-weight: bold;
color: #ddd;
}
.page.settings .directory_list .actions:last-child > .save {
background: #9dc156;
}