summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pyload/Core.py6
-rw-r--r--pyload/datatypes/OnlineCheck.py5
-rw-r--r--pyload/setup/Setup.py (renamed from pyload/Setup.py)50
-rw-r--r--pyload/setup/System_Checks.py126
-rw-r--r--pyload/setup/__init__.py0
-rw-r--r--pyload/setup/dependencies.py84
-rw-r--r--pyload/setup/system.py28
-rw-r--r--pyload/threads/BaseThread.py9
-rw-r--r--pyload/threads/ThreadManager.py7
-rw-r--r--pyload/utils/JsEngine.py2
-rw-r--r--pyload/utils/fs.py1
-rw-r--r--pyload/web/api_app.py14
-rw-r--r--pyload/web/app/index.html1
-rw-r--r--pyload/web/app/scripts/default.js18
-rw-r--r--pyload/web/app/scripts/helpers/ifEq.js14
-rw-r--r--pyload/web/app/scripts/models/Setup.js14
-rw-r--r--pyload/web/app/scripts/setup.js33
-rw-r--r--pyload/web/app/scripts/views/setup/setupView.js89
-rw-r--r--pyload/web/app/scripts/views/setup/systemView.js20
-rw-r--r--pyload/web/app/scripts/views/setup/welcomeView.js20
-rw-r--r--pyload/web/app/styles/default/style.less10
-rw-r--r--pyload/web/app/templates/default/setup.html16
-rw-r--r--pyload/web/app/templates/default/setup/actionbar.html24
-rw-r--r--pyload/web/app/templates/default/setup/layout.html7
-rw-r--r--pyload/web/app/templates/default/setup/system.html5
-rw-r--r--pyload/web/app/templates/default/setup/welcome.html16
-rw-r--r--pyload/web/pyload_app.py37
-rw-r--r--pyload/web/setup_app.py7
-rw-r--r--pyload/web/utils.py13
29 files changed, 458 insertions, 218 deletions
diff --git a/pyload/Core.py b/pyload/Core.py
index f97cfcf3b..5e083a14e 100644
--- a/pyload/Core.py
+++ b/pyload/Core.py
@@ -120,21 +120,21 @@ class Core(object):
elif option in ("-d", "--debug"):
self.doDebug = True
elif option in ("-u", "--user"):
- from Setup import Setup
+ from setup.Setup import Setup
self.config = ConfigParser()
s = Setup(pypath, self.config)
s.set_user()
exit()
elif option in ("-s", "--setup"):
- from Setup import Setup
+ from setup.Setup import Setup
self.config = ConfigParser()
s = Setup(pypath, self.config)
s.start()
exit()
elif option == "--changedir":
- from Setup import Setup
+ from setup.Setup import Setup
self.config = ConfigParser()
s = Setup(pypath, self.config)
diff --git a/pyload/datatypes/OnlineCheck.py b/pyload/datatypes/OnlineCheck.py
index 2797828bf..b0b19cf76 100644
--- a/pyload/datatypes/OnlineCheck.py
+++ b/pyload/datatypes/OnlineCheck.py
@@ -5,6 +5,7 @@ from time import time
from pyload.Api import OnlineCheck as OC
+
class OnlineCheck:
""" Helper class that holds result of an initiated online check """
@@ -16,6 +17,10 @@ class OnlineCheck:
self.timestamp = time()
+ def isStale(self, timeout=5):
+ """ checks if the data was updated or accessed recently """
+ return self.timestamp + timeout * 60 < time()
+
def update(self, result):
self.timestamp = time()
self.result.update(result)
diff --git a/pyload/Setup.py b/pyload/setup/Setup.py
index d2ec3731f..78afb7fcc 100644
--- a/pyload/Setup.py
+++ b/pyload/setup/Setup.py
@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
###############################################################################
-# Copyright(c) 2008-2012 pyLoad Team
+# Copyright(c) 2008-2013 pyLoad Team
# http://www.pyload.org
#
# This file is part of pyLoad.
@@ -16,7 +16,6 @@
# @author: RaNaN
###############################################################################
-import pyload.utils.pylgettext as gettext
import os
import sys
import socket
@@ -26,6 +25,7 @@ from getpass import getpass
from time import time
from sys import exit
+from pyload.utils import pylgettext as gettext
from pyload.utils.fs import abspath, dirname, exists, join, makedirs
from pyload.utils import get_console_encoding
from pyload.web.ServerThread import WebServer
@@ -48,40 +48,37 @@ class Setup():
self.yes = "yes"
self.no = "no"
-
def start(self):
+ import __builtin__
+ # set the gettext translation
+ __builtin__._ = lambda x: x
+
web = WebServer(pysetup=self)
web.start()
error = web.check_error()
+
+ # TODO: start cli in this case
if error: #todo errno 44 port already in use
print error
url = "http://%s:%d/" % (socket.gethostbyname(socket.gethostname()), web.port)
- print "Setup is started"
+ print "Setup is running at %s" % url
opened = webbrowser.open_new_tab(url)
if not opened:
- print "Please point your browser to %s" % url
-
-
- self.ask_lang()
+ print "Please point your browser to the url above."
- print ""
- print _("Would you like to configure pyLoad via Webinterface?")
- print _("You need a Browser and a connection to this PC for it.")
- print _("Url would be: http://hostname:8000/")
- viaweb = self.ask(_("Start initial webinterface for configuration?"), self.yes, bool=True)
- if viaweb:
- self.start_web()
- else:
+ cli = self.ask("Use commandline for configuration instead?", self.no, bool=True)
+ if cli:
self.start_cli()
-
-
+ else:
+ raw_input()
def start_cli(self):
+ self.ask_lang()
print _("Welcome to the pyLoad Configuration Assistent.")
print _("It will check your system and make a basic setup in order to run pyLoad.")
@@ -168,23 +165,6 @@ class Setup():
return True
- def start_web(self):
- print ""
- print _("Webinterface running for setup.")
- # TODO start browser?
- try:
- from pyload.web import ServerThread
- ServerThread.setup = self
- from pyload.web import webinterface
- webinterface.run_simple()
- self.web = True
- return True
- except Exception, e:
- print "Webinterface failed with this error: ", e
- print "Falling back to commandline setup."
- self.start_cli()
-
-
def conf_basic(self):
print ""
print _("## Basic Setup ##")
diff --git a/pyload/setup/System_Checks.py b/pyload/setup/System_Checks.py
deleted file mode 100644
index cef46956b..000000000
--- a/pyload/setup/System_Checks.py
+++ /dev/null
@@ -1,126 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-
- @author: RaNaN
-"""
-from getpass import getpass
-import module.common.pylgettext as gettext
-import os
-from os import makedirs
-from os.path import abspath, dirname, exists, join
-from subprocess import PIPE, call
-import sys
-from sys import exit
-from module.utils import get_console_encoding
-
-class System_Checks():
- def __init__(self):
- self.result = ""
-
- def print_str(self, text, translate = True):
- if translate:
- self.result += _(text) + "\n"
- else:
- self.result += text + "\n"
-
- def print_dep(self, name, value):
- """Print Status of dependency"""
- if value:
- self.print_str(name + ": OK", False)
- else:
- self.print_str(name + ": missing", False)
-
- def check_basic(self):
- self.result = "" #clear result
- python = False
- if sys.version_info[:2] > (2, 7):
- self.print_str("Your python version is to new, Please use Python 2.6/2.7")
- elif sys.version_info[:2] < (2, 5):
- self.print_str("Your python version is to old, Please use at least Python 2.5")
- else:
- self.print_str("Python Version: OK")
- python = True
-
- curl = self.check_module("pycurl")
- self.print_dep("pycurl", curl)
-
- sqlite = self.check_module("sqlite3")
- self.print_dep("sqlite3", sqlite)
-
- beaker = self.check_module("beaker")
- self.print_dep("beaker", beaker)
-
- jinja = True
- try:
- import jinja2
- v = jinja2.__version__
- if v and "unknown" not in v:
- if not v.startswith("2.5") and not v.startswith("2.6"):
- self.print_str("Your installed jinja2 version %s seems too old.") % jinja2.__version__
- self.print_str("You can safely continue but if the webinterface is not working,")
- self.print_str("please upgrade or deinstall it, pyLoad includes a sufficient jinja2 library.")
- jinja = False
- except:
- pass
- self.print_dep("jinja2", jinja)
-
- return self.result, (python and curl and sqlite and (beaker or jinja))
-
- def check_ssl(self):
- self.result = "" #clear result
- ssl = self.check_module("OpenSSL")
- self.print_dep("py-OpenSSL", ssl)
- return self.result, ssl
-
- def check_crypto(self):
- self.result = "" #clear result
- crypto = self.check_module("Crypto")
- self.print_dep("pycrypto", crypto)
- return self.result, crypto
-
- def check_captcha(self):
- self.result = "" #clear result
- pil = self.check_module("Image")
- self.print_dep("py-imaging", pil)
- if os.name == "nt":
- tesser = self.check_prog([join(pypath, "tesseract", "tesseract.exe"), "-v"])
- else:
- tesser = self.check_prog(["tesseract", "-v"])
- self.print_dep("tesseract", tesser)
- return self.result, pil and tesser
-
- def check_js(self):
- self.result = "" #clear result
- from module.common import JsEngine
- js = True if JsEngine.ENGINE else False
- self.print_dep(_("JS engine"), js)
- return self.result, pil and tesser
-
- def check_module(self, module):
- try:
- __import__(module)
- return True
- except:
- return False
-
- def check_prog(self, command):
- pipe = PIPE
- try:
- call(command, stdout=pipe, stderr=pipe)
- return True
- except:
- return False
-
diff --git a/pyload/setup/__init__.py b/pyload/setup/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/pyload/setup/__init__.py
diff --git a/pyload/setup/dependencies.py b/pyload/setup/dependencies.py
new file mode 100644
index 000000000..53457de93
--- /dev/null
+++ b/pyload/setup/dependencies.py
@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+
+# Provide gettext marker
+_ = lambda x: x
+
+
+def find_module(name):
+ from imp import find_module
+
+ try:
+ f, pathname, desc = find_module(name)
+ if f is not None:
+ f.close()
+ return True
+ except:
+ return False
+
+
+class Dependency(object):
+ name = None
+ optional = True
+ desc = None
+
+ @classmethod
+ def check(cls):
+ """ Returns (availability, version) as tuple """
+ inst = cls()
+ avail = inst.isStatisfied()
+ v = None
+ if avail:
+ v = inst.getVersion()
+
+ return avail, v
+
+ def isStatisfied(self):
+ raise NotImplementedError
+
+ def getVersion(self):
+ return None
+
+
+class Python(Dependency):
+ name = "Python"
+ optional = False
+
+ def isStatisfied(self):
+ # obviously
+ return True
+
+ def getVersion(self):
+ import sys
+
+ ".".join(str(v) for v in sys.version_info[:3])
+
+
+class JSON(Dependency):
+ name = "json"
+ optional = False
+
+ def isStatisfied(self):
+ # TODO
+ return True
+
+
+class PyCurl(Dependency):
+ name = "pycurl"
+ optional = False
+
+ def isStatisfied(self):
+ # TODO
+ return True
+
+
+class Sqlite(Dependency):
+ name = "sqlite"
+ optional = False
+
+ def isStatisfied(self):
+ # TODO
+ return True
+
+# TODO: ssl, crypto, image, tesseract, js
+
+deps = [x for x in locals().itervalues() if issubclass(x, Dependency) and x is not Dependency] \ No newline at end of file
diff --git a/pyload/setup/system.py b/pyload/setup/system.py
new file mode 100644
index 000000000..6e7039331
--- /dev/null
+++ b/pyload/setup/system.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+
+import sys
+import os
+
+# gettext decorator, translated only when needed
+_ = lambda x: x
+
+# platform usually don't change at runtime
+info = None
+
+
+def get_system_info():
+ """ Returns system information as dict """
+ global info
+
+ if info is None:
+ import platform
+
+ info = {
+ _("Platform"): platform.platform(),
+ _("Version"): sys.version,
+ _("Path"): os.path.abspath(""),
+ _("Encoding"): sys.getdefaultencoding(),
+ _("FS-Encoding"): sys.getfilesystemencoding()
+ }
+
+ return info \ No newline at end of file
diff --git a/pyload/threads/BaseThread.py b/pyload/threads/BaseThread.py
index b7912e924..3655480dd 100644
--- a/pyload/threads/BaseThread.py
+++ b/pyload/threads/BaseThread.py
@@ -10,6 +10,7 @@ from traceback import format_exc
from pyload.utils import primary_uid
from pyload.utils.fs import listdir, join, save_join, stat, exists
+from pyload.setup.system import get_system_info
class BaseThread(Thread):
@@ -137,9 +138,7 @@ class BaseThread(Thread):
def getSystemDump(self):
dump = "SYSTEM:\n\n"
- dump += """Platform: %s
-Version: %s
-Encoding: %s
-FS-Encoding: %s
- """ % (sys.platform, sys.version, sys.getdefaultencoding(), sys.getfilesystemencoding())
+ for k,v in get_system_info().iteritems():
+ dump += "%s: %s\n" % (k, v)
+
return dump
diff --git a/pyload/threads/ThreadManager.py b/pyload/threads/ThreadManager.py
index ff8bfe8d7..07b0cd6e9 100644
--- a/pyload/threads/ThreadManager.py
+++ b/pyload/threads/ThreadManager.py
@@ -167,11 +167,14 @@ class ThreadManager:
self.assignJob()
#it may be failed non critical so we try it again
- if (self.infoCache or self.infoResults) and self.timestamp < time():
+ if self.infoCache and self.timestamp < time():
self.infoCache.clear()
- self.infoResults.clear()
self.log.debug("Cleared Result cache")
+ for rid in self.infoResults.keys():
+ if self.infoResults[rid].isStale():
+ del self.infoResults[rid]
+
def tryReconnect(self):
"""checks if reconnect needed"""
diff --git a/pyload/utils/JsEngine.py b/pyload/utils/JsEngine.py
index ef7494d16..3318ffb2a 100644
--- a/pyload/utils/JsEngine.py
+++ b/pyload/utils/JsEngine.py
@@ -48,7 +48,7 @@ if not ENGINE:
if not ENGINE or DEBUG:
try:
- find_module("PyV8")
+ import PyV8
ENGINE = "pyv8"
PYV8 = True
except:
diff --git a/pyload/utils/fs.py b/pyload/utils/fs.py
index 92cc605e7..52bf0bd51 100644
--- a/pyload/utils/fs.py
+++ b/pyload/utils/fs.py
@@ -44,7 +44,6 @@ def exists(path):
def makedirs(path, mode=0755):
return os.makedirs(fs_encode(path), mode)
-# fs_decode?
def listdir(path):
return [fs_decode(x) for x in os.listdir(fs_encode(path))]
diff --git a/pyload/web/api_app.py b/pyload/web/api_app.py
index d0a41b4d0..9370e671f 100644
--- a/pyload/web/api_app.py
+++ b/pyload/web/api_app.py
@@ -6,7 +6,7 @@ from traceback import format_exc, print_exc
from bottle import route, request, response, HTTPError, parse_auth
-from utils import set_session, get_user_api
+from utils import set_session, get_user_api, add_json_header
from webinterface import PYLOAD, session
from pyload.Api import ExceptionObject
@@ -14,12 +14,6 @@ from pyload.remote.json_converter import loads, dumps, BaseEncoder
from pyload.utils import remove_chars
-def add_header(r):
- r.headers.replace("Content-type", "application/json")
- r.headers.append("Cache-Control", "no-cache, must-revalidate")
- r.headers.append("Access-Control-Allow-Origin", request.get_header('Origin', '*'))
- r.headers.append("Access-Control-Allow-Credentials", "true")
-
# returns http error
def error(code, msg):
return HTTPError(code, dumps(msg), **dict(response.headers))
@@ -29,7 +23,7 @@ def error(code, msg):
@route("/api/<func><args:re:[^#?]*>")
@route("/api/<func><args:re:[^#?]*>", method="POST")
def call_api(func, args=""):
- add_header(response)
+ add_json_header(response)
s = request.environ.get('beaker.session')
# Accepts standard http auth
@@ -96,7 +90,7 @@ def call_api(func, args=""):
@route("/api/login")
@route("/api/login", method="POST")
def login():
- add_header(response)
+ add_json_header(response)
username = request.params.get("username")
password = request.params.get("password")
@@ -128,7 +122,7 @@ def login():
@route("/api/logout")
@route("/api/logout", method="POST")
def logout():
- add_header(response)
+ add_json_header(response)
s = request.environ.get('beaker.session')
s.delete()
diff --git a/pyload/web/app/index.html b/pyload/web/app/index.html
index 4a4195b13..bf75d40ed 100644
--- a/pyload/web/app/index.html
+++ b/pyload/web/app/index.html
@@ -41,6 +41,7 @@
// TODO
window.pathPrefix = '/';
window.wsAddress = configValue('{{ws}}', 'ws://%s:7227');
+ window.setup = configValue('{{setup}}', 'false');
require(['config'], function(Config) {
require(['default'], function(App) {
diff --git a/pyload/web/app/scripts/default.js b/pyload/web/app/scripts/default.js
index 428ec2b28..91b46715e 100644
--- a/pyload/web/app/scripts/default.js
+++ b/pyload/web/app/scripts/default.js
@@ -1,5 +1,5 @@
-define('default', ['backbone', 'jquery', 'app', 'router', 'models/UserSession'],
- function(Backbone, $, App, Router, UserSession) {
+define('default', ['require', 'backbone', 'jquery', 'app', 'router', 'models/UserSession'],
+ function(require, Backbone, $, App, Router, UserSession) {
'use strict';
// Global ajax options
@@ -21,9 +21,17 @@ define('default', ['backbone', 'jquery', 'app', 'router', 'models/UserSession'],
};
$(function() {
- App.user = new UserSession();
- App.router = new Router();
- App.start();
+ // load setup async
+ if (window.setup === 'true') {
+ require(['setup'], function(SetupRouter) {
+ App.router = new SetupRouter();
+ App.start();
+ });
+ } else {
+ App.user = new UserSession();
+ App.router = new Router();
+ App.start();
+ }
});
return App;
diff --git a/pyload/web/app/scripts/helpers/ifEq.js b/pyload/web/app/scripts/helpers/ifEq.js
new file mode 100644
index 000000000..1c8a71b61
--- /dev/null
+++ b/pyload/web/app/scripts/helpers/ifEq.js
@@ -0,0 +1,14 @@
+define('helpers/ifEq', ['underscore', 'handlebars'],
+ function(_, Handlebars) {
+ /*jshint validthis:true */
+ 'use strict';
+ function ifEq(v1, v2, options) {
+ if (v1 === v2) {
+ return options.fn(this);
+ }
+ return options.inverse(this);
+ }
+
+ Handlebars.registerHelper('ifEq', ifEq);
+ return ifEq;
+ });
diff --git a/pyload/web/app/scripts/models/Setup.js b/pyload/web/app/scripts/models/Setup.js
new file mode 100644
index 000000000..82a2978db
--- /dev/null
+++ b/pyload/web/app/scripts/models/Setup.js
@@ -0,0 +1,14 @@
+define(['jquery', 'backbone', 'underscore', 'app', 'utils/apitypes'],
+ function($, Backbone, _, App, Api) {
+ 'use strict';
+
+ return Backbone.Model.extend({
+
+ defaults: {
+ lang: 'en',
+ user: null,
+ password: null
+ }
+
+ });
+ }); \ No newline at end of file
diff --git a/pyload/web/app/scripts/setup.js b/pyload/web/app/scripts/setup.js
new file mode 100644
index 000000000..94d370078
--- /dev/null
+++ b/pyload/web/app/scripts/setup.js
@@ -0,0 +1,33 @@
+/**
+ * Router and controller used in setup mode
+ */
+define([
+ // Libraries
+ 'backbone',
+ 'marionette',
+ 'app',
+
+ // Views
+ 'views/setup/setupView'
+],
+ function(Backbone, Marionette, App, SetupView) {
+ 'use strict';
+
+ return Backbone.Marionette.AppRouter.extend({
+
+ appRoutes: {
+ '': 'setup'
+ },
+
+ controller: {
+
+ setup: function() {
+
+ var view = new SetupView();
+ App.actionbar.show(new view.actionbar());
+ App.content.show(view);
+ }
+
+ }
+ });
+ });
diff --git a/pyload/web/app/scripts/views/setup/setupView.js b/pyload/web/app/scripts/views/setup/setupView.js
new file mode 100644
index 000000000..7636a0bc2
--- /dev/null
+++ b/pyload/web/app/scripts/views/setup/setupView.js
@@ -0,0 +1,89 @@
+define(['jquery', 'backbone', 'underscore', 'app', 'models/Setup', 'hbs!tpl/setup/layout', 'hbs!tpl/setup/actionbar',
+ './welcomeView', './systemView'],
+ function($, Backbone, _, App, Setup, template, templateBar, welcomeView, systemView) {
+ 'use strict';
+
+ return Backbone.Marionette.ItemView.extend({
+ template: template,
+
+ events: {
+ },
+
+ ui: {
+ page: '.setup-page'
+ },
+
+ pages: [
+ welcomeView,
+ systemView
+ ],
+
+ page: 0,
+ view: null,
+
+ initialize: function() {
+ var self = this;
+ this.model = new Setup();
+
+ this.actionbar = Backbone.Marionette.ItemView.extend({
+ template: templateBar,
+ view: this,
+ events: {
+ 'click .select-page': 'selectPage'
+ },
+
+ initialize: function() {
+ this.listenTo(self.model, 'page:changed', this.render);
+ },
+
+ serializeData: function() {
+ return {
+ page: this.view.page,
+ max: this.view.pages.length - 1,
+ pages: _.map(this.view.pages, function(p) {
+ return p.prototype.name;
+ })
+ };
+ },
+
+ selectPage: function(e) {
+ this.view.openPage(parseInt($(e.target).data('page'), 10));
+ }
+
+ });
+ this.listenTo(this.model, 'page:next', function() {
+ self.openPage(self.page++);
+ });
+ this.listenTo(this.model, 'page:prev', function() {
+ self.openPage(self.page--);
+ });
+ },
+
+ openPage: function(page) {
+ console.log('Change page', page);
+ // check if number is reasonable
+ if (!_.isNumber(page) || !_.isFinite(page))
+ return;
+
+ if (page === this.page)
+ return;
+
+ this.page = page;
+ this.onRender();
+
+ this.model.trigger('page:changed', page);
+ },
+
+ onRender: function() {
+ // close old opened view
+ if (this.view)
+ this.view.close();
+
+ // TODO: animation
+ this.view = new this.pages[this.page]({model: this.model});
+ this.ui.page.empty();
+ this.ui.page.append(this.view.render().$el);
+ }
+
+ });
+ }); \ No newline at end of file
diff --git a/pyload/web/app/scripts/views/setup/systemView.js b/pyload/web/app/scripts/views/setup/systemView.js
new file mode 100644
index 000000000..11e50213d
--- /dev/null
+++ b/pyload/web/app/scripts/views/setup/systemView.js
@@ -0,0 +1,20 @@
+define(['jquery', 'backbone', 'underscore', 'app', 'hbs!tpl/setup/system'],
+ function($, Backbone, _, App, template) {
+ 'use strict';
+
+ return Backbone.Marionette.ItemView.extend({
+
+ name: 'System',
+ template: template,
+
+ events: {
+ },
+
+ ui: {
+ },
+
+ onRender: function() {
+ }
+
+ });
+ }); \ No newline at end of file
diff --git a/pyload/web/app/scripts/views/setup/welcomeView.js b/pyload/web/app/scripts/views/setup/welcomeView.js
new file mode 100644
index 000000000..4affc9075
--- /dev/null
+++ b/pyload/web/app/scripts/views/setup/welcomeView.js
@@ -0,0 +1,20 @@
+define(['jquery', 'backbone', 'underscore', 'app', 'hbs!tpl/setup/welcome'],
+ function($, Backbone, _, App, template) {
+ 'use strict';
+
+ return Backbone.Marionette.ItemView.extend({
+
+ name: 'Language',
+ template: template,
+
+ events: {
+ },
+
+ ui: {
+ },
+
+ onRender: function() {
+ }
+
+ });
+ }); \ No newline at end of file
diff --git a/pyload/web/app/styles/default/style.less b/pyload/web/app/styles/default/style.less
index b24e5ff21..da0e68991 100644
--- a/pyload/web/app/styles/default/style.less
+++ b/pyload/web/app/styles/default/style.less
@@ -231,15 +231,13 @@ header { // background-color: @greyDark;
}
.actionbar {
+ padding-top: 2px;
padding-bottom: 3px;
- margin-bottom: 0;
+ margin-bottom: 5px;
border-bottom: 1px dashed @grey;
height: @actionbar-height;
- padding-top: 2px;
- margin-bottom: 5px;
-
& > li > a, & > li > button {
margin-top: 4px;
}
@@ -259,6 +257,10 @@ header { // background-color: @greyDark;
margin-bottom: 0;
}
+ select {
+ margin: 2px 0 0;
+ }
+
input, button {
padding-top: 2px;
padding-bottom: 2px;
diff --git a/pyload/web/app/templates/default/setup.html b/pyload/web/app/templates/default/setup.html
deleted file mode 100644
index e5c9f4b8c..000000000
--- a/pyload/web/app/templates/default/setup.html
+++ /dev/null
@@ -1,16 +0,0 @@
-{% extends 'default/base.html' %}
-{% block title %}
- {{_("Setup")}} - {{ super()}}
-{% endblock %}
-
-{% block content %}
- <div class="hero-unit">
- <h1>You did it!</h1>
- <p>pyLoad is running and ready for configuration.</p>
- <p>
- <a class="btn btn-primary btn-large">
- Go on
- </a>
- </p>
- </div>
-{% endblock %} \ No newline at end of file
diff --git a/pyload/web/app/templates/default/setup/actionbar.html b/pyload/web/app/templates/default/setup/actionbar.html
new file mode 100644
index 000000000..b109025b7
--- /dev/null
+++ b/pyload/web/app/templates/default/setup/actionbar.html
@@ -0,0 +1,24 @@
+<ul class="actionbar nav span8 offset3">
+ <li class="pull-left">
+ <ul class="breadcrumb">
+ {{#each pages}}
+ <li>
+ <a href="#" class="{{#ifEq ../page @index}}active {{/ifEq}}select-page"
+ data-page="{{@index}}">{{this}}</a>
+ {{#ifEq ../max @index}}
+
+ {{else}}
+ <span class="divider">
+ <i class="icon-long-arrow-right"></i>
+ </span>
+ {{/ifEq}}
+ </li>
+ {{/each}}
+ </ul>
+ </li>
+ <li class="pull-right">
+ <select>
+ <option>en</option>
+ </select>
+ </li>
+</ul> \ No newline at end of file
diff --git a/pyload/web/app/templates/default/setup/layout.html b/pyload/web/app/templates/default/setup/layout.html
new file mode 100644
index 000000000..7b75e53b1
--- /dev/null
+++ b/pyload/web/app/templates/default/setup/layout.html
@@ -0,0 +1,7 @@
+<div class="span3">
+ <h1 class="vertical-header">
+ {{ _ "Setup" }}
+ </h1>
+</div>
+<div class="span8 setup-page">
+</div> \ No newline at end of file
diff --git a/pyload/web/app/templates/default/setup/system.html b/pyload/web/app/templates/default/setup/system.html
new file mode 100644
index 000000000..84a217b19
--- /dev/null
+++ b/pyload/web/app/templates/default/setup/system.html
@@ -0,0 +1,5 @@
+<h1>{{ _ "System" }} </h1>
+
+<h2>{{_ "Dependencies" }}</h2>
+
+<h2>{{ _ "Optional" }}</h2> \ No newline at end of file
diff --git a/pyload/web/app/templates/default/setup/welcome.html b/pyload/web/app/templates/default/setup/welcome.html
new file mode 100644
index 000000000..f5c5af4d7
--- /dev/null
+++ b/pyload/web/app/templates/default/setup/welcome.html
@@ -0,0 +1,16 @@
+<div class="hero-unit">
+ <h1>{{ _ "Welcome!" }}</h1>
+
+ <p>{{ _ "pyLoad is running and ready for configuration." }}</p>
+
+ <p>
+ {{ _ "Select your language:" }}
+ <select>
+ <option>en</option>
+ </select>
+ </p>
+
+ <button class="btn btn-large btn-blue">
+ {{ _ "Start configuration" }}
+ </button>
+</div> \ No newline at end of file
diff --git a/pyload/web/pyload_app.py b/pyload/web/pyload_app.py
index b182816c2..1ec7cf4c9 100644
--- a/pyload/web/pyload_app.py
+++ b/pyload/web/pyload_app.py
@@ -23,7 +23,9 @@ from bottle import route, static_file, response, request, redirect, template
from webinterface import PYLOAD, PROJECT_DIR, SETUP, APP_PATH, UNAVAILALBE
-from utils import login_required
+from utils import login_required, add_json_header, select_language
+
+from pyload.utils import json_dumps
APP_ROOT = join(PROJECT_DIR, APP_PATH)
@@ -45,27 +47,42 @@ def download(fid, api):
return static_file(name, path, download=True)
+@route("/i18n")
+@route("/i18n/:lang")
+def i18n(lang=None):
+ add_json_header(response)
+
+ if lang is None:
+ pass
+ # TODO use lang from PYLOAD.config or setup
+ else:
+ # TODO auto choose language
+ lang = select_language(["en"])
+
+ return json_dumps({})
+
@route('/')
def index():
if UNAVAILALBE:
- return server_static("unavailable.html")
-
- if SETUP:
- # TODO show different page
- pass
+ return serve_static("unavailable.html")
- resp = server_static('index.html')
+ resp = serve_static('index.html')
+ # set variable depending on setup mode
+ setup = 'false' if SETUP is None else 'true'
+ ws = PYLOAD.getWSAddress() if PYLOAD else False
+ web = PYLOAD.getConfigValue('webinterface', 'port') if PYLOAD else False
# Render variables into the html page
if resp.status_code == 200:
content = resp.body.read()
- resp.body = template(content, ws=PYLOAD.getWSAddress(), web=PYLOAD.getConfigValue('webinterface', 'port'))
+ resp.body = template(content, ws=ws, web=web, setup=setup)
+ resp.content_length = len(resp.body)
return resp
# Very last route that is registered, could match all uris
@route('/<path:path>')
-def server_static(path):
+def serve_static(path):
response.headers['Expires'] = time.strftime("%a, %d %b %Y %H:%M:%S GMT",
time.gmtime(time.time() + 60 * 60 * 24 * 7))
response.headers['Cache-control'] = "public"
@@ -76,7 +93,7 @@ def server_static(path):
# gzipped and clients accepts it
# TODO: index.html is not gzipped, because of template processing
- if GZIPPED[path] and "gzip" in request.get_header("Accept-Encoding", "") and path != "index.html":
+ if GZIPPED[path] and "gzip" in request.get_header("Accept-Encoding", "") and path != "index.html":
response.headers['Vary'] = 'Accept-Encoding'
response.headers['Content-Encoding'] = 'gzip'
path += ".gz"
diff --git a/pyload/web/setup_app.py b/pyload/web/setup_app.py
index cd44ad08e..5163f9cc6 100644
--- a/pyload/web/setup_app.py
+++ b/pyload/web/setup_app.py
@@ -1,10 +1,14 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
+from time import time
+
from bottle import route, request, response, HTTPError, redirect
from webinterface import PROJECT_DIR, SETUP
+from utils import add_json_header
+
def setup_required(func):
def _view(*args, **kwargs):
# setup needs to be running
@@ -14,6 +18,9 @@ def setup_required(func):
return func(*args, **kwargs)
return _view
+# setup will close after inactivity
+TIMEOUT = 15
+timestamp = time()
@route("/setup")
@setup_required
diff --git a/pyload/web/utils.py b/pyload/web/utils.py
index dae987f84..e94089185 100644
--- a/pyload/web/utils.py
+++ b/pyload/web/utils.py
@@ -6,6 +6,11 @@ from bottle import request, HTTPError, redirect
from webinterface import PYLOAD, SETUP
+def add_json_header(r):
+ r.headers.replace("Content-type", "application/json")
+ r.headers.append("Cache-Control", "no-cache, must-revalidate")
+ r.headers.append("Access-Control-Allow-Origin", request.get_header('Origin', '*'))
+ r.headers.append("Access-Control-Allow-Credentials", "true")
def set_session(request, user):
s = request.environ.get('beaker.session')
@@ -53,6 +58,14 @@ def is_mobile():
return True
return False
+def select_language(langs):
+
+ accept = request.headers.get('Accept-Language', '')
+ # TODO
+
+ return langs[0]
+
+
def login_required(perm=None):
def _dec(func):