Browse Source

Merge branch 'develop'

pull/5327/head
Ruud 10 years ago
parent
commit
56557787d1
  1. 16
      .editorconfig
  2. 3
      .gitignore
  3. 198
      Gruntfile.js
  4. 18
      README.md
  5. 44
      config.rb
  6. 18
      couchpotato/core/_base/_core.py
  7. 189
      couchpotato/core/_base/clientscript.py
  8. 14
      couchpotato/core/_base/downloader/static/downloaders.js
  9. 1
      couchpotato/core/_base/updater/main.py
  10. 10
      couchpotato/core/_base/updater/static/updater.js
  11. 2
      couchpotato/core/database.py
  12. 4
      couchpotato/core/downloaders/putio/static/putio.js
  13. 5
      couchpotato/core/downloaders/sabnzbd.py
  14. 4
      couchpotato/core/downloaders/transmission.py
  15. 7
      couchpotato/core/media/__init__.py
  16. 2
      couchpotato/core/media/_base/providers/nzb/nzbclub.py
  17. 131
      couchpotato/core/media/_base/providers/torrent/hd4free.py
  18. 5
      couchpotato/core/media/_base/providers/torrent/kickasstorrents.py
  19. 2
      couchpotato/core/media/_base/providers/torrent/yify.py
  20. 277
      couchpotato/core/media/_base/search/static/search.css
  21. 128
      couchpotato/core/media/_base/search/static/search.js
  22. 503
      couchpotato/core/media/_base/search/static/search.scss
  23. 11
      couchpotato/core/media/movie/_base/main.py
  24. 154
      couchpotato/core/media/movie/_base/static/details.js
  25. 207
      couchpotato/core/media/movie/_base/static/list.js
  26. 26
      couchpotato/core/media/movie/_base/static/manage.js
  27. 900
      couchpotato/core/media/movie/_base/static/movie.actions.js
  28. 1074
      couchpotato/core/media/movie/_base/static/movie.css
  29. 316
      couchpotato/core/media/movie/_base/static/movie.js
  30. 1248
      couchpotato/core/media/movie/_base/static/movie.scss
  31. 50
      couchpotato/core/media/movie/_base/static/page.js
  32. 125
      couchpotato/core/media/movie/_base/static/search.js
  33. 107
      couchpotato/core/media/movie/_base/static/wanted.js
  34. 14
      couchpotato/core/media/movie/charts/__init__.py
  35. 101
      couchpotato/core/media/movie/charts/main.py
  36. 124
      couchpotato/core/media/movie/charts/static/charts.js
  37. 0
      couchpotato/core/media/movie/charts/static/charts.scss
  38. 58
      couchpotato/core/media/movie/providers/automation/bluray.py
  39. 68
      couchpotato/core/media/movie/providers/automation/imdb.py
  40. 11
      couchpotato/core/media/movie/providers/automation/popularmovies.py
  41. 95
      couchpotato/core/media/movie/providers/automation/rottentomatoes.py
  42. 4
      couchpotato/core/media/movie/providers/automation/trakt/static/trakt.js
  43. 2
      couchpotato/core/media/movie/providers/info/themoviedb.py
  44. 11
      couchpotato/core/media/movie/providers/torrent/hd4free.py
  45. 55
      couchpotato/core/media/movie/suggestion.py
  46. 0
      couchpotato/core/media/movie/suggestion/__init__.py
  47. 162
      couchpotato/core/media/movie/suggestion/static/suggest.css
  48. 173
      couchpotato/core/media/movie/suggestion/static/suggest.js
  49. 78
      couchpotato/core/notifications/core/static/notification.js
  50. 4
      couchpotato/core/notifications/twitter/static/twitter.js
  51. 28
      couchpotato/core/notifications/xbmc.py
  52. 37
      couchpotato/core/plugins/base.py
  53. 34
      couchpotato/core/plugins/category/static/category.js
  54. 19
      couchpotato/core/plugins/category/static/category.scss
  55. 4
      couchpotato/core/plugins/dashboard.py
  56. 7
      couchpotato/core/plugins/log/main.py
  57. 199
      couchpotato/core/plugins/log/static/log.css
  58. 157
      couchpotato/core/plugins/log/static/log.js
  59. 159
      couchpotato/core/plugins/log/static/log.scss
  60. 197
      couchpotato/core/plugins/profile/static/profile.css
  61. 76
      couchpotato/core/plugins/profile/static/profile.js
  62. 150
      couchpotato/core/plugins/profile/static/profile.scss
  63. 26
      couchpotato/core/plugins/quality/static/quality.css
  64. 42
      couchpotato/core/plugins/quality/static/quality.js
  65. 19
      couchpotato/core/plugins/quality/static/quality.scss
  66. 4
      couchpotato/core/plugins/release/main.py
  67. 5
      couchpotato/core/plugins/renamer.py
  68. 19
      couchpotato/core/plugins/userscript/static/userscript.js
  69. 0
      couchpotato/core/plugins/userscript/static/userscript.scss
  70. 84
      couchpotato/core/plugins/wizard/static/wizard.css
  71. 447
      couchpotato/core/plugins/wizard/static/wizard.js
  72. 62
      couchpotato/core/plugins/wizard/static/wizard.scss
  73. BIN
      couchpotato/static/fonts/Elusive-Icons.eot
  74. 298
      couchpotato/static/fonts/Elusive-Icons.svg
  75. BIN
      couchpotato/static/fonts/Elusive-Icons.ttf
  76. BIN
      couchpotato/static/fonts/Elusive-Icons.woff
  77. BIN
      couchpotato/static/fonts/Lobster-webfont.eot
  78. 246
      couchpotato/static/fonts/Lobster-webfont.svg
  79. BIN
      couchpotato/static/fonts/Lobster-webfont.ttf
  80. BIN
      couchpotato/static/fonts/Lobster-webfont.woff
  81. BIN
      couchpotato/static/fonts/Lobster-webfont.woff2
  82. BIN
      couchpotato/static/fonts/OpenSans-Light-webfont.eot
  83. 1831
      couchpotato/static/fonts/OpenSans-Light-webfont.svg
  84. BIN
      couchpotato/static/fonts/OpenSans-Light-webfont.ttf
  85. BIN
      couchpotato/static/fonts/OpenSans-Light-webfont.woff
  86. 190
      couchpotato/static/fonts/config.json
  87. BIN
      couchpotato/static/fonts/icons.eot
  88. 41
      couchpotato/static/fonts/icons.svg
  89. BIN
      couchpotato/static/fonts/icons.ttf
  90. BIN
      couchpotato/static/fonts/icons.woff
  91. 8
      couchpotato/static/scripts/api.js
  92. 8
      couchpotato/static/scripts/block.js
  93. 4
      couchpotato/static/scripts/block/footer.js
  94. 52
      couchpotato/static/scripts/block/header.js
  95. 110
      couchpotato/static/scripts/block/menu.js
  96. 71
      couchpotato/static/scripts/block/navigation.js
  97. 2069
      couchpotato/static/scripts/combined.base.min.js
  98. 3844
      couchpotato/static/scripts/combined.plugins.min.js
  99. 9028
      couchpotato/static/scripts/combined.vendor.min.js
  100. 243
      couchpotato/static/scripts/couchpotato.js

16
.editorconfig

@ -0,0 +1,16 @@
# http://editorconfig.org
root = true
[*]
indent_style = tab
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.py]
indent_style = space
[*.md]
trim_trailing_whitespace = false

3
.gitignore

@ -1,5 +1,8 @@
*.pyc
/data/
/_env/
/_source/
.project
.pydevproject
node_modules
.tmp

198
Gruntfile.js

@ -0,0 +1,198 @@
'use strict';
module.exports = function(grunt){
require('jit-grunt')(grunt);
require('time-grunt')(grunt);
grunt.loadNpmTasks('grunt-shell-spawn');
// Configurable paths
var config = {
python: grunt.file.exists('./_env/bin/python') ? './_env/bin/python' : 'python',
tmp: '.tmp',
base: 'couchpotato',
css_dest: 'couchpotato/static/style/combined.min.css',
scripts_vendor_dest: 'couchpotato/static/scripts/combined.vendor.min.js',
scripts_base_dest: 'couchpotato/static/scripts/combined.base.min.js',
scripts_plugins_dest: 'couchpotato/static/scripts/combined.plugins.min.js'
};
var vendor_scripts_files = [
'couchpotato/static/scripts/vendor/mootools.js',
'couchpotato/static/scripts/vendor/mootools_more.js',
'couchpotato/static/scripts/vendor/Array.stableSort.js',
'couchpotato/static/scripts/vendor/history.js',
'couchpotato/static/scripts/vendor/dynamics.js',
'couchpotato/static/scripts/vendor/fastclick.js'
];
var scripts_files = [
'couchpotato/static/scripts/library/uniform.js',
'couchpotato/static/scripts/library/question.js',
'couchpotato/static/scripts/library/scrollspy.js',
'couchpotato/static/scripts/couchpotato.js',
'couchpotato/static/scripts/api.js',
'couchpotato/static/scripts/page.js',
'couchpotato/static/scripts/block.js',
'couchpotato/static/scripts/block/navigation.js',
'couchpotato/static/scripts/block/header.js',
'couchpotato/static/scripts/block/footer.js',
'couchpotato/static/scripts/block/menu.js',
'couchpotato/static/scripts/page/home.js',
'couchpotato/static/scripts/page/settings.js',
'couchpotato/static/scripts/page/about.js',
'couchpotato/static/scripts/page/login.js'
];
grunt.initConfig({
// Project settings
config: config,
// Make sure code styles are up to par and there are no obvious mistakes
jshint: {
options: {
reporter: require('jshint-stylish'),
unused: false,
camelcase: false,
devel: true
},
all: [
'<%= config.base %>/{,**/}*.js',
'!<%= config.base %>/static/scripts/vendor/{,**/}*.js',
'!<%= config.base %>/static/scripts/combined.*.js'
]
},
// Compiles Sass to CSS and generates necessary files if requested
sass: {
options: {
compass: true,
update: true,
sourcemap: 'none'
},
server: {
files: [{
expand: true,
cwd: '<%= config.base %>/',
src: ['**/*.scss'],
dest: '<%= config.tmp %>/styles/',
ext: '.css'
}]
}
},
// Empties folders to start fresh
clean: {
server: '.tmp'
},
// Add vendor prefixed styles
autoprefixer: {
options: {
browsers: ['last 2 versions'],
remove: false,
cascade: false
},
dist: {
files: [{
expand: true,
cwd: '<%= config.tmp %>/styles/',
src: '{,**/}*.css',
dest: '<%= config.tmp %>/styles/'
}]
}
},
cssmin: {
dist: {
options: {
keepBreaks: true
},
files: {
'<%= config.css_dest %>': ['<%= config.tmp %>/styles/**/*.css']
}
}
},
uglify: {
options: {
mangle: false,
compress: false,
beautify: true,
screwIE8: true
},
vendor: {
files: {
'<%= config.scripts_vendor_dest %>': vendor_scripts_files
}
},
base: {
files: {
'<%= config.scripts_base_dest %>': scripts_files
}
},
plugins: {
files: {
'<%= config.scripts_plugins_dest %>': ['<%= config.base %>/core/**/*.js']
}
}
},
shell: {
runCouchPotato: {
command: '<%= config.python %> CouchPotato.py',
options: {
stdout: true,
stderr: true
}
}
},
// COOL TASKS ==============================================================
watch: {
scss: {
files: ['<%= config.base %>/**/*.{scss,sass}'],
tasks: ['sass:server', 'autoprefixer', 'cssmin']
},
js: {
files: [
'<%= config.base %>/**/*.js',
'!<%= config.base %>/static/scripts/combined.*.js'
],
tasks: ['uglify:base', 'uglify:plugins', 'jshint']
},
livereload: {
options: {
livereload: 35729
},
files: [
'<%= config.css_dest %>',
'<%= config.scripts_vendor_dest %>',
'<%= config.scripts_base_dest %>',
'<%= config.scripts_plugins_dest %>'
]
}
},
concurrent: {
options: {
logConcurrentOutput: true
},
tasks: ['shell:runCouchPotato', 'watch']
}
});
grunt.registerTask('default', [
'clean:server',
'sass:server',
'autoprefixer',
'cssmin',
'uglify:vendor',
'uglify:base',
'uglify:plugins',
'concurrent'
]);
};

18
README.md

@ -25,6 +25,7 @@ OS X:
* If you're on Leopard (10.5) install Python 2.6+: [Python 2.6.5](http://www.python.org/download/releases/2.6.5/)
* Install [GIT](http://git-scm.com/)
* Install [LXML](http://lxml.de/installation.html) for better/faster website scraping
* Open up `Terminal`
* Go to your App folder `cd /Applications`
* Run `git clone https://github.com/RuudBurger/CouchPotatoServer.git`
@ -35,6 +36,7 @@ Linux:
* (Ubuntu / Debian) Install [GIT](http://git-scm.com/) with `apt-get install git-core`
* (Fedora / CentOS) Install [GIT](http://git-scm.com/) with `yum install git`
* Install [LXML](http://lxml.de/installation.html) for better/faster website scraping
* 'cd' to the folder of your choosing.
* Run `git clone https://github.com/RuudBurger/CouchPotatoServer.git`
* Then do `python CouchPotatoServer/CouchPotato.py` to start
@ -49,7 +51,7 @@ Linux:
* Open your browser and go to `http://localhost:5050/`
Docker:
* You can use [razorgirl's Dockerfile](https://github.com/razorgirl/docker-couchpotato) to quickly build your own isolated app container. It's based on the Linux instructions above. For more info about Docker check out the [official website](https://www.docker.com).
* You can use [linuxserver.io](https://github.com/linuxserver/docker-couchpotato) or [razorgirl's](https://github.com/razorgirl/docker-couchpotato) to quickly build your own isolated app container. It's based on the Linux instructions above. For more info about Docker check out the [official website](https://www.docker.com).
FreeBSD:
@ -66,3 +68,17 @@ FreeBSD:
* If not default install, specify options with startup flags in `ee /etc/rc.conf`
* Finally, `service couchpotato start`
* Open your browser and go to: `http://server:5050/`
## Development
Be sure you're running the latest version of [Python 2.7](http://python.org/).
If you're going to add styling or doing some javascript work you'll need a few tools that build and compress scss -> css and combine the javascript files. [Node/NPM](https://nodejs.org/), [Grunt](http://gruntjs.com/installing-grunt), [Compass](http://compass-style.org/install/)
After you've got these tools you can install the packages using `npm install`. Once this process has finished you can start CP using the command `grunt`. This will start all the needed tools and watches any files for changes.
You can now change css and javascript and it wil reload the page when needed.
By default it will combine files used in the core folder. If you're adding a new .scss or .js file, you might need to add it and then restart the grunt process for it to combine it properly.
Don't forget to enable development inside the CP settings. This disables some functions and also makes sure javascript rrors are pushed to console instead of the log.

44
config.rb

@ -0,0 +1,44 @@
# First, require any additional compass plugins installed on your system.
# require 'zen-grids'
# require 'susy'
# require 'breakpoint'
# Toggle this between :development and :production when deploying the CSS to the
# live server. Development mode will retain comments and spacing from the
# original Sass source and adds line numbering comments for easier debugging.
environment = :development
# environment = :development
# In development, we can turn on the FireSass-compatible debug_info.
firesass = false
# firesass = true
# Location of the your project's resources.
# Set this to the root of your project. All resource locations above are
# considered to be relative to this path.
http_path = "/"
# To use relative paths to assets in your compiled CSS files, set this to true.
# relative_assets = true
##
## You probably don't need to edit anything below this.
##
sass_dir = "./couchpotato/static/style"
css_dir = "./couchpotato/static/style"
# You can select your preferred output style here (can be overridden via the command line):
# output_style = :expanded or :nested or :compact or :compressed
output_style = (environment == :development) ? :expanded : :compressed
# To disable debugging comments that display the original location of your selectors. Uncomment:
# line_comments = false
# Pass options to sass. For development, we turn on the FireSass-compatible
# debug_info if the firesass config variable above is true.
sass_options = (environment == :development && firesass == true) ? {:debug_info => true} : {}

18
couchpotato/core/_base/_core.py

@ -53,6 +53,7 @@ class Core(Plugin):
addEvent('app.version', self.version)
addEvent('app.load', self.checkDataDir)
addEvent('app.load', self.cleanUpFolders)
addEvent('app.load.after', self.dependencies)
addEvent('setting.save.core.password', self.md5Password)
addEvent('setting.save.core.api_key', self.checkApikey)
@ -73,6 +74,15 @@ class Core(Plugin):
except:
log.debug('Failed setting default ssl context: %s', traceback.format_exc())
def dependencies(self):
# Check if lxml is available
try: from lxml import etree
except: log.error('LXML not available, please install for better/faster scraping support: `http://lxml.de/installation.html`')
try: import OpenSSL
except: log.error('OpenSSL not available, please install for better requests validation: `https://pyopenssl.readthedocs.org/en/latest/install.html`')
def md5Password(self, value):
return md5(value) if value else ''
@ -183,8 +193,9 @@ class Core(Plugin):
if host == '0.0.0.0' or host == '':
host = 'localhost'
port = Env.setting('port')
ssl = Env.setting('ssl_cert') and Env.setting('ssl_key')
return '%s:%d%s' % (cleanHost(host).rstrip('/'), int(port), Env.get('web_base'))
return '%s:%d%s' % (cleanHost(host, ssl = ssl).rstrip('/'), int(port), Env.get('web_base'))
def createApiUrl(self):
return '%sapi/%s' % (self.createBaseUrl(), Env.setting('api_key'))
@ -276,6 +287,11 @@ config = [{
'description': 'Let 3rd party app do stuff. <a target="_self" href="../../docs/">Docs</a>',
},
{
'name': 'dereferer',
'default': 'http://www.dereferer.org/?',
'description': 'Derefer links to external sites, keep empty for no dereferer. Example: http://www.dereferer.org/? or http://www.nullrefer.com/?.',
},
{
'name': 'use_proxy',
'default': 0,
'type': 'bool',

189
couchpotato/core/_base/clientscript.py

@ -1,16 +1,10 @@
import os
import re
import traceback
from couchpotato.core.event import addEvent
from couchpotato.core.helpers.encoding import ss
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin
from couchpotato.environment import Env
from minify.cssmin import cssmin
from minify.jsmin import jsmin
from tornado.web import StaticFileHandler
log = CPLog(__name__)
@ -20,129 +14,35 @@ autoload = 'ClientScript'
class ClientScript(Plugin):
core_static = {
paths = {
'style': [
'style/main.css',
'style/uniform.generic.css',
'style/uniform.css',
'style/settings.css',
'style/combined.min.css',
],
'script': [
'scripts/library/mootools.js',
'scripts/library/mootools_more.js',
'scripts/library/uniform.js',
'scripts/library/form_replacement/form_check.js',
'scripts/library/form_replacement/form_radio.js',
'scripts/library/form_replacement/form_dropdown.js',
'scripts/library/form_replacement/form_selectoption.js',
'scripts/library/question.js',
'scripts/library/scrollspy.js',
'scripts/library/spin.js',
'scripts/library/Array.stableSort.js',
'scripts/library/async.js',
'scripts/couchpotato.js',
'scripts/api.js',
'scripts/library/history.js',
'scripts/page.js',
'scripts/block.js',
'scripts/block/navigation.js',
'scripts/block/footer.js',
'scripts/block/menu.js',
'scripts/page/home.js',
'scripts/page/settings.js',
'scripts/page/about.js',
'scripts/combined.vendor.min.js',
'scripts/combined.base.min.js',
'scripts/combined.plugins.min.js',
],
}
urls = {'style': {}, 'script': {}}
minified = {'style': {}, 'script': {}}
paths = {'style': {}, 'script': {}}
comment = {
'style': '/*** %s:%d ***/\n',
'script': '// %s:%d\n'
}
html = {
'style': '<link rel="stylesheet" href="%s" type="text/css">',
'script': '<script type="text/javascript" src="%s"></script>',
}
def __init__(self):
addEvent('register_style', self.registerStyle)
addEvent('register_script', self.registerScript)
addEvent('clientscript.get_styles', self.getStyles)
addEvent('clientscript.get_scripts', self.getScripts)
if not Env.get('dev'):
addEvent('app.load', self.minify)
self.makeRelative()
self.addCore()
def makeRelative(self):
def addCore(self):
for static_type in self.paths:
for static_type in self.core_static:
for rel_path in self.core_static.get(static_type):
updates_paths = []
for rel_path in self.paths.get(static_type):
file_path = os.path.join(Env.get('app_dir'), 'couchpotato', 'static', rel_path)
core_url = 'static/%s' % rel_path
if static_type == 'script':
self.registerScript(core_url, file_path, position = 'front')
else:
self.registerStyle(core_url, file_path, position = 'front')
def minify(self):
# Create cache dir
cache = Env.get('cache_dir')
parent_dir = os.path.join(cache, 'minified')
self.makeDir(parent_dir)
Env.get('app').add_handlers(".*$", [(Env.get('web_base') + 'minified/(.*)', StaticFileHandler, {'path': parent_dir})])
for file_type in ['style', 'script']:
ext = 'js' if file_type is 'script' else 'css'
positions = self.paths.get(file_type, {})
for position in positions:
files = positions.get(position)
self._minify(file_type, files, position, position + '.' + ext)
def _minify(self, file_type, files, position, out):
cache = Env.get('cache_dir')
out_name = out
out = os.path.join(cache, 'minified', out_name)
raw = []
for file_path in files:
f = open(file_path, 'r').read()
if file_type == 'script':
data = jsmin(f)
else:
data = self.prefix(f)
data = cssmin(data)
data = data.replace('../images/', '../static/images/')
data = data.replace('../fonts/', '../static/fonts/')
data = data.replace('../../static/', '../static/') # Replace inside plugins
raw.append({'file': file_path, 'date': int(os.path.getmtime(file_path)), 'data': data})
# Combine all files together with some comments
data = ''
for r in raw:
data += self.comment.get(file_type) % (ss(r.get('file')), r.get('date'))
data += r.get('data') + '\n\n'
self.createFile(out, data.strip())
core_url = 'static/%s?%d' % (rel_path, tryInt(os.path.getmtime(file_path)))
if not self.minified.get(file_type):
self.minified[file_type] = {}
if not self.minified[file_type].get(position):
self.minified[file_type][position] = []
updates_paths.append(core_url)
minified_url = 'minified/%s?%s' % (out_name, tryInt(os.path.getmtime(out)))
self.minified[file_type][position].append(minified_url)
self.paths[static_type] = updates_paths
def getStyles(self, *args, **kwargs):
return self.get('style', *args, **kwargs)
@ -150,63 +50,8 @@ class ClientScript(Plugin):
def getScripts(self, *args, **kwargs):
return self.get('script', *args, **kwargs)
def get(self, type, as_html = False, location = 'head'):
data = '' if as_html else []
try:
try:
if not Env.get('dev'):
return self.minified[type][location]
except:
pass
return self.urls[type][location]
except:
log.error('Error getting minified %s, %s: %s', (type, location, traceback.format_exc()))
return data
def registerStyle(self, api_path, file_path, position = 'head'):
self.register(api_path, file_path, 'style', position)
def registerScript(self, api_path, file_path, position = 'head'):
self.register(api_path, file_path, 'script', position)
def register(self, api_path, file_path, type, location):
api_path = '%s?%s' % (api_path, tryInt(os.path.getmtime(file_path)))
if not self.urls[type].get(location):
self.urls[type][location] = []
self.urls[type][location].append(api_path)
if not self.paths[type].get(location):
self.paths[type][location] = []
self.paths[type][location].append(file_path)
prefix_properties = ['border-radius', 'transform', 'transition', 'box-shadow']
prefix_tags = ['ms', 'moz', 'webkit']
def prefix(self, data):
trimmed_data = re.sub('(\t|\n|\r)+', '', data)
new_data = ''
colon_split = trimmed_data.split(';')
for splt in colon_split:
curl_split = splt.strip().split('{')
for curly in curl_split:
curly = curly.strip()
for prop in self.prefix_properties:
if curly[:len(prop) + 1] == prop + ':':
for tag in self.prefix_tags:
new_data += ' -%s-%s; ' % (tag, curly)
new_data += curly + (' { ' if len(curl_split) > 1 else ' ')
new_data += '; '
new_data = new_data.replace('{ ;', '; ').replace('} ;', '} ')
def get(self, type):
if type in self.paths:
return self.paths[type]
return new_data
return []

14
couchpotato/core/_base/downloader/static/downloaders.js

@ -16,8 +16,8 @@ var DownloadersBase = new Class({
var setting_page = App.getPage('Settings');
setting_page.addEvent('create', function(){
Object.each(setting_page.tabs.downloaders.groups, self.addTestButton.bind(self))
})
Object.each(setting_page.tabs.downloaders.groups, self.addTestButton.bind(self));
});
},
@ -27,7 +27,7 @@ var DownloadersBase = new Class({
if(button_name.contains('Downloaders')) return;
new Element('.ctrlHolder.test_button').adopt(
new Element('.ctrlHolder.test_button').grab(
new Element('a.button', {
'text': button_name,
'events': {
@ -44,19 +44,19 @@ var DownloadersBase = new Class({
if(json.success){
message = new Element('span.success', {
'text': 'Connection successful'
}).inject(button, 'after')
}).inject(button, 'after');
}
else {
var msg_text = 'Connection failed. Check logs for details.';
if(json.hasOwnProperty('msg')) msg_text = json.msg;
message = new Element('span.failed', {
'text': msg_text
}).inject(button, 'after')
}).inject(button, 'after');
}
(function(){
message.destroy();
}).delay(3000)
}).delay(3000);
}
});
}
@ -67,7 +67,7 @@ var DownloadersBase = new Class({
},
testButtonName: function(fieldset){
var name = String(fieldset.getElement('h2').innerHTML).substring(0,String(fieldset.getElement('h2').innerHTML).indexOf("<span"));
var name = fieldset.getElement('h2 .group_label').get('text');
return 'Test '+name;
}

1
couchpotato/core/_base/updater/main.py

@ -163,7 +163,6 @@ class BaseUpdater(Plugin):
update_failed = False
update_version = None
last_check = 0
auto_register_static = False
def doUpdate(self):
pass

10
couchpotato/core/_base/updater/static/updater.js

@ -27,7 +27,7 @@ var UpdaterBase = new Class({
App.trigger('message', ['No updates available']);
}
}
})
});
},
@ -50,8 +50,8 @@ var UpdaterBase = new Class({
self.message.destroy();
}
}
})
}, (timeout || 0))
});
}, (timeout || 0));
},
@ -84,7 +84,7 @@ var UpdaterBase = new Class({
'click': self.doUpdate.bind(self)
}
})
).inject(document.body)
).inject(document.body);
},
doUpdate: function(){
@ -96,7 +96,7 @@ var UpdaterBase = new Class({
if(json.success)
self.updating();
else
App.unBlockPage()
App.unBlockPage();
}
});
},

2
couchpotato/core/database.py

@ -272,7 +272,7 @@ class Database(object):
prop_name = 'last_db_compact'
last_check = int(Env.prop(prop_name, default = 0))
if size > 26214400 and last_check < time.time()-604800: # 25MB / 7 days
if last_check < time.time()-604800: # 7 days
self.compact()
Env.prop(prop_name, value = int(time.time()))

4
couchpotato/core/downloaders/putio/static/putio.js

@ -17,7 +17,7 @@ var PutIODownloader = new Class({
var putio_set = 0;
fieldset.getElements('input[type=text]').each(function(el){
putio_set += +(el.get('value') != '');
putio_set += +(el.get('value') !== '');
});
new Element('.ctrlHolder').adopt(
@ -57,7 +57,7 @@ var PutIODownloader = new Class({
}
})
).inject(fieldset.getElement('.test_button'), 'before');
})
});
}

5
couchpotato/core/downloaders/sabnzbd.py

@ -73,10 +73,11 @@ class Sabnzbd(DownloaderBase):
return False
log.debug('Result from SAB: %s', sab_data)
if sab_data.get('status') and not sab_data.get('error'):
nzo_ids = sab_data.get('nzo_ids', [])
if sab_data.get('status') and not sab_data.get('error') and isinstance(nzo_ids, list) and len(nzo_ids) > 0:
log.info('NZB sent to SAB successfully.')
if filedata:
return self.downloadReturnId(sab_data.get('nzo_ids')[0])
return self.downloadReturnId(nzo_ids[0])
else:
return True
else:

4
couchpotato/core/downloaders/transmission.py

@ -68,7 +68,7 @@ class Transmission(DownloaderBase):
if self.conf('directory'):
if os.path.isdir(self.conf('directory')):
params['download-dir'] = self.conf('directory')
params['download-dir'] = self.conf('directory').rstrip(os.path.sep)
else:
log.error('Download directory from Transmission settings: %s doesn\'t exist', self.conf('directory'))
@ -147,7 +147,7 @@ class Transmission(DownloaderBase):
status = 'failed'
elif torrent['status'] == 0 and torrent['percentDone'] == 1:
status = 'completed'
elif torrent['status'] == 16 and torrent['percentDone'] == 1:
elif torrent['status'] == 16 and torrent['percentDone'] == 1:
status = 'completed'
elif torrent['status'] in [5, 6]:
status = 'seeding'

7
couchpotato/core/media/__init__.py

@ -88,8 +88,13 @@ class MediaBase(Plugin):
if len(existing_files) == 0:
del existing_files[file_type]
images = image_urls.get(image_type, [])
for y in ['SX300', 'tmdb']:
initially_try = [x for x in images if y in x]
images[:-1] = initially_try
# Loop over type
for image in image_urls.get(image_type, []):
for image in images:
if not isinstance(image, (str, unicode)):
continue

2
couchpotato/core/media/_base/providers/nzb/nzbclub.py

@ -15,7 +15,7 @@ log = CPLog(__name__)
class Base(NZBProvider, RSS):
urls = {
'search': 'https://www.nzbclub.com/nzbfeeds.aspx?%s',
'search': 'https://www.nzbclub.com/nzbrss.aspx?%s',
}
http_time_between_calls = 4 # seconds

131
couchpotato/core/media/_base/providers/torrent/hd4free.py

@ -0,0 +1,131 @@
import re
import json
import traceback
from couchpotato.core.helpers.variable import tryInt, getIdentifier
from couchpotato.core.logger import CPLog
from couchpotato.core.media._base.providers.torrent.base import TorrentProvider
log = CPLog(__name__)
class Base(TorrentProvider):
urls = {
'test': 'https://hd4free.xyz/',
'detail': 'https://hd4free.xyz/details.php?id=%s',
'search': 'https://hd4free.xyz/searchapi.php?apikey=%s&username=%s&imdbid=%s&internal=%s',
'download': 'https://hd4free.xyz/download.php?torrent=%s&torrent_pass=%s',
}
http_time_between_calls = 1 # Seconds
def _search(self, movie, quality, results):
data = self.getJsonData(self.urls['search'] % (self.conf('apikey'), self.conf('username'), getIdentifier(movie), self.conf('internal_only')))
if data:
try:
#for result in data[]:
for key, result in data.iteritems():
if tryInt(result['total_results']) == 0:
return
torrentscore = self.conf('extra_score')
releasegroup = result['releasegroup']
resolution = result['resolution']
encoding = result['encoding']
freeleech = tryInt(result['freeleech'])
seeders = tryInt(result['seeders'])
torrent_desc = '/ %s / %s / %s / %s seeders' % (releasegroup, resolution, encoding, seeders)
if freeleech > 0 and self.conf('prefer_internal'):
torrent_desc += '/ Internal'
torrentscore += 200
if seeders == 0:
torrentscore = 0
name = result['release_name']
year = tryInt(result['year'])
results.append({
'id': tryInt(result['torrentid']),
'name': re.sub('[^A-Za-z0-9\-_ \(\).]+', '', '%s (%s) %s' % (name, year, torrent_desc)),
'url': self.urls['download'] % (result['torrentid'], result['torrentpass']),
'detail_url': self.urls['detail'] % result['torrentid'],
'size': tryInt(result['size']),
'seeders': tryInt(result['seeders']),
'leechers': tryInt(result['leechers']),
'age': tryInt(result['age']),
'score': torrentscore
})
except:
log.error('Failed getting results from %s: %s', (self.getName(), traceback.format_exc()))
config = [{
'name': 'hd4free',
'groups': [
{
'tab': 'searcher',
'list': 'torrent_providers',
'name': 'HD4Free',
'wizard': True,
'description': '<a href="https://hd4free.xyz">HD4Free</a>',
'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABX1BMVEUF6nsH33cJ03EJ1XIJ1nMKzXIKz28Lym4MxGsMxWsMx2wNvmgNv2kNwGkNwWwOuGgOuWYOuWcOumcOu2cOvmgPtWQPtmUPt2UPt2YQr2IQsGIQsGMQsmMQs2QRqmARq2ARrmERrmISpV4SpmASp14SqF8ToFsToFwToVwTo10TpV0UnFoUn1sVllcVmFgWkFUWklYXjVQXjlMXkFUYh1EYilIYi1MZhlEafk0af04agE4agU4beEobeUsbe0wcdUkeaUQebUYfZEMfZ0QgX0AgYEAgYUEhWj4iVz0iWD0jTzkkSzcmQTMmQzQnPTInPjInPzIoNy8oOC8oODAoOTAoOjApMi0pNC4pNS4qLCoqLSsqLisqMCwrJygrKCgrKCkrKSkrKikrKiorKyosIyYsIycsJCcsJScsJigtHyUuGCIuGiMuGyMuHCMuHCQvEyAvFSEvFiEvFyE0ABU0ABY5lYz4AAAA3ElEQVR4AWNIQAMMiYmJCYkIkMCQnpKWkZ4KBGlARlpaLEOor194kI+Pj6+PT0CET0AYg46Alr22NDeHkBinnq6SkitDrolDgYtaapajdpGppoFfGkMhv2GxE0uuPwNfsk6mhHMOQ54isxmbUJKCtWx+tIZQcDpDtqSol7qIMqsRu3dIhJxxFkOBoF2JG5O7lSqjh5S/tkkWQ5SBTbqnfkymv2WGLa95YCSDhZiMvKIwj4GJCpesuDivK0N6VFRUYlRyfHJUchQQJDMkxsfHJcTHAxEIxMVj+BZDAACjwkqhYgsTAAAAAABJRU5ErkJggg==',
'options': [
{
'name': 'enabled',
'type': 'enabler',
'default': False,
},
{
'name': 'username',
'default': '',
'description': 'Enter your site username.',
},
{
'name': 'apikey',
'default': '',
'label': 'API Key',
'description': 'Enter your site api key. This can be find on <a href="https://hd4free.xyz/usercp.php?action=security">Profile Security</a>',
},
{
'name': 'seed_ratio',
'label': 'Seed ratio',
'type': 'float',
'default': 0,
'description': 'Will not be (re)moved until this seed ratio is met. HD4Free minimum is 1:1.',
},
{
'name': 'seed_time',
'label': 'Seed time',
'type': 'int',
'default': 0,
'description': 'Will not be (re)moved until this seed time (in hours) is met. HD4Free minimum is 72 hours.',
},
{
'name': 'prefer_internal',
'advanced': True,
'type': 'bool',
'default': 1,
'description': 'Favors internal releases over non-internal releases.',
},
{
'name': 'internal_only',
'advanced': True,
'label': 'Internal Only',
'type': 'bool',
'default': False,
'description': 'Only download releases marked as HD4Free internal',
},
{
'name': 'extra_score',
'advanced': True,
'label': 'Extra Score',
'type': 'int',
'default': 0,
'description': 'Starting score for each release found via this provider.',
}
],
},
],
}]

5
couchpotato/core/media/_base/providers/torrent/kickasstorrents.py

@ -31,7 +31,8 @@ class Base(TorrentMagnetProvider):
proxy_list = [
'https://kat.cr',
'http://katproxy.com',
'https://kickass.unblocked.pw/',
'https://katproxy.com',
]
def _search(self, media, quality, results):
@ -66,7 +67,7 @@ class Base(TorrentMagnetProvider):
link = td.find('div', {'class': 'torrentname'}).find_all('a')[2]
new['id'] = temp.get('id')[-7:]
new['name'] = link.text
new['url'] = td.find('a', 'imagnet')['href']
new['url'] = td.find('a', {'href': re.compile('magnet:*')})['href']
new['detail_url'] = self.urls['detail'] % (self.getDomain(), link['href'][1:])
new['verified'] = True if td.find('a', 'iverify') else False
new['score'] = 100 if new['verified'] else 0

2
couchpotato/core/media/_base/providers/torrent/yify.py

@ -18,8 +18,6 @@ class Base(TorrentProvider):
http_time_between_calls = 1 # seconds
proxy_list = [
'https://yts.re',
'https://yts.wf',
'https://yts.im',
'https://yts.to',
'https://yify.ml',

277
couchpotato/core/media/_base/search/static/search.css

@ -1,277 +0,0 @@
.search_form {
display: inline-block;
vertical-align: middle;
position: absolute;
right: 105px;
top: 0;
text-align: right;
height: 100%;
transition: all .4s cubic-bezier(0.9,0,0.1,1);
z-index: 20;
border: 0 solid transparent;
border-bottom-width: 4px;
}
.search_form:hover {
border-color: #047792;
}
@media all and (max-width: 480px) {
.search_form {
right: 44px;
}
}
.search_form.focused,
.search_form.shown {
border-color: #04bce6;
}
.search_form .input {
height: 100%;
overflow: hidden;
width: 45px;
transition: all .4s cubic-bezier(0.9,0,0.1,1);
}
.search_form.focused .input,
.search_form.shown .input {
width: 380px;
background: #4e5969;
}
.search_form .input input {
border-radius: 0;
display: block;
border: 0;
background: none;
color: #FFF;
font-size: 25px;
height: 100%;
width: 100%;
opacity: 0;
padding: 0 40px 0 10px;
transition: all .4s ease-in-out .2s;
}
.search_form.focused .input input,
.search_form.shown .input input {
opacity: 1;
}
.search_form input::-ms-clear {
width : 0;
height: 0;
}
@media all and (max-width: 480px) {
.search_form .input input {
font-size: 15px;
}
.search_form.focused .input,
.search_form.shown .input {
width: 277px;
}
}
.search_form .input a {
position: absolute;
top: 0;
right: 0;
width: 44px;
height: 100%;
cursor: pointer;
vertical-align: middle;
text-align: center;
line-height: 66px;
font-size: 15px;
color: #FFF;
}
.search_form .input a:after {
content: "\e03e";
}
.search_form.shown.filled .input a:after {
content: "\e04e";
}
@media all and (max-width: 480px) {
.search_form .input a {
line-height: 44px;
}
}
.search_form .results_container {
text-align: left;
position: absolute;
background: #5c697b;
margin: 4px 0 0;
width: 470px;
min-height: 50px;
box-shadow: 0 20px 20px -10px rgba(0,0,0,0.55);
display: none;
}
@media all and (max-width: 480px) {
.search_form .results_container {
width: 320px;
}
}
.search_form.focused.filled .results_container,
.search_form.shown.filled .results_container {
display: block;
}
.search_form .results {
max-height: 570px;
overflow-x: hidden;
}
.media_result {
overflow: hidden;
height: 50px;
position: relative;
}
.media_result .options {
position: absolute;
height: 100%;
top: 0;
left: 30px;
right: 0;
padding: 13px;
border: 1px solid transparent;
border-width: 1px 0;
border-radius: 0;
box-shadow: inset 0 1px 8px rgba(0,0,0,0.25);
}
.media_result .options > .in_library_wanted {
margin-top: -7px;
}
.media_result .options > div {
border: 0;
}
.media_result .options .thumbnail {
vertical-align: middle;
}
.media_result .options select {
vertical-align: middle;
display: inline-block;
margin-right: 10px;
}
.media_result .options select[name=title] { width: 170px; }
.media_result .options select[name=profile] { width: 90px; }
.media_result .options select[name=category] { width: 80px; }
@media all and (max-width: 480px) {
.media_result .options select[name=title] { width: 90px; }
.media_result .options select[name=profile] { width: 50px; }
.media_result .options select[name=category] { width: 50px; }
}
.media_result .options .button {
vertical-align: middle;
display: inline-block;
}
.media_result .options .message {
height: 100%;
font-size: 20px;
color: #fff;
line-height: 20px;
}
.media_result .data {
position: absolute;
height: 100%;
top: 0;
left: 30px;
right: 0;
background: #5c697b;
cursor: pointer;
border-top: 1px solid rgba(255,255,255, 0.08);
transition: all .4s cubic-bezier(0.9,0,0.1,1);
}
.media_result .data.open {
left: 100% !important;
}
.media_result:last-child .data { border-bottom: 0; }
.media_result .in_wanted, .media_result .in_library {
position: absolute;
bottom: 2px;
left: 14px;
font-size: 11px;
}
.media_result .thumbnail {
width: 34px;
min-height: 100%;
display: block;
margin: 0;
vertical-align: top;
}
.media_result .info {
position: absolute;
top: 20%;
left: 15px;
right: 7px;
vertical-align: middle;
}
.media_result .info h2 {
margin: 0;
font-weight: normal;
font-size: 20px;
padding: 0;
}
.search_form .info h2 {
position: absolute;
width: 100%;
}
.media_result .info h2 .title {
display: block;
margin: 0;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.search_form .info h2 .title {
position: absolute;
width: 88%;
}
.media_result .info h2 .year {
padding: 0 5px;
text-align: center;
position: absolute;
width: 12%;
right: 0;
}
@media all and (max-width: 480px) {
.search_form .info h2 .year {
font-size: 12px;
margin-top: 7px;
}
}
.search_form .mask,
.media_result .mask {
position: absolute;
height: 100%;
width: 100%;
left: 0;
top: 0;
}

128
couchpotato/core/media/_base/search/static/search.js

@ -1,7 +1,11 @@
Block.Search = new Class({
var BlockSearch = new Class({
Extends: BlockBase,
options: {
'animate': true
},
cache: {},
create: function(){
@ -9,49 +13,47 @@ Block.Search = new Class({
var focus_timer = 0;
self.el = new Element('div.search_form').adopt(
new Element('div.input').adopt(
self.input = new Element('input', {
'placeholder': 'Search & add a new media',
new Element('a.icon-search', {
'events': {
'click': self.clear.bind(self)
}
}),
self.wrapper = new Element('div.wrapper').adopt(
self.result_container = new Element('div.results_container', {
'events': {
'input': self.keyup.bind(self),
'paste': self.keyup.bind(self),
'change': self.keyup.bind(self),
'keyup': self.keyup.bind(self),
'focus': function(){
if(focus_timer) clearTimeout(focus_timer);
self.el.addClass('focused');
if(this.get('value'))
self.hideResults(false)
},
'blur': function(){
focus_timer = (function(){
self.el.removeClass('focused')
}).delay(100);
'mousewheel': function(e){
(e).stopPropagation();
}
}
}),
new Element('a.icon2', {
'events': {
'click': self.clear.bind(self),
'touchend': self.clear.bind(self)
}
})
),
self.result_container = new Element('div.results_container', {
'tween': {
'duration': 200
},
'events': {
'mousewheel': function(e){
(e).stopPropagation();
}
}
}).adopt(
self.results = new Element('div.results')
}).grab(
self.results = new Element('div.results')
),
new Element('div.input').grab(
self.input = new Element('input', {
'placeholder': 'Search & add a new media',
'events': {
'input': self.keyup.bind(self),
'paste': self.keyup.bind(self),
'change': self.keyup.bind(self),
'keyup': self.keyup.bind(self),
'focus': function(){
if(focus_timer) clearTimeout(focus_timer);
if(this.get('value'))
self.hideResults(false);
},
'blur': function(){
focus_timer = (function(){
self.el.removeClass('focused');
self.last_q = null;
}).delay(100);
}
}
})
)
)
);
self.mask = new Element('div.mask').inject(self.result_container).fade('hide');
self.mask = new Element('div.mask').inject(self.result_container);
},
@ -67,11 +69,32 @@ Block.Search = new Class({
self.last_q = '';
self.input.set('value', '');
self.el.addClass('focused');
self.input.focus();
self.media = {};
self.results.empty();
self.el.removeClass('filled')
self.el.removeClass('filled');
// Animate in
if(self.options.animate){
dynamics.css(self.wrapper, {
opacity: 0,
scale: 0.1
});
dynamics.animate(self.wrapper, {
opacity: 1,
scale: 1
}, {
type: dynamics.spring,
frequency: 200,
friction: 270,
duration: 800
});
}
}
},
@ -105,7 +128,7 @@ Block.Search = new Class({
self.api_request.cancel();
if(self.autocomplete_timer) clearTimeout(self.autocomplete_timer);
self.autocomplete_timer = self.autocomplete.delay(300, self)
self.autocomplete_timer = self.autocomplete.delay(300, self);
}
},
@ -115,10 +138,10 @@ Block.Search = new Class({
if(!self.q()){
self.hideResults(true);
return
return;
}
self.list()
self.list();
},
list: function(){
@ -129,7 +152,9 @@ Block.Search = new Class({
self.hideResults(false);
if(!cache){
self.mask.fade('in');
setTimeout(function(){
self.mask.addClass('show');
}, 10);
if(!self.spinner)
self.spinner = createSpinner(self.mask);
@ -139,7 +164,7 @@ Block.Search = new Class({
'q': q
},
'onComplete': self.fill.bind(self, q)
})
});
}
else
self.fill(q, cache);
@ -158,30 +183,25 @@ Block.Search = new Class({
Object.each(json, function(media){
if(typeOf(media) == 'array'){
Object.each(media, function(m){
Object.each(media, function(me){
var m = new Block.Search[m.type.capitalize() + 'Item'](m);
var m = new window['BlockSearch' + me.type.capitalize() + 'Item'](me);
$(m).inject(self.results);
self.media[m.imdb || 'r-'+Math.floor(Math.random()*10000)] = m;
if(q == m.imdb)
m.showOptions()
m.showOptions();
});
}
});
// Calculate result heights
var w = window.getSize(),
rc = self.result_container.getCoordinates();
self.results.setStyle('max-height', (w.y - rc.top - 50) + 'px');
self.mask.fade('out')
self.mask.removeClass('show');
},
loading: function(bool){
this.el[bool ? 'addClass' : 'removeClass']('loading')
this.el[bool ? 'addClass' : 'removeClass']('loading');
},
q: function(){

503
couchpotato/core/media/_base/search/static/search.scss

@ -0,0 +1,503 @@
@import "_mixins";
.search_form {
display: inline-block;
z-index: 11;
width: 44px;
position: relative;
* {
transform: translateZ(0);
}
.icon-search {
position: absolute;
z-index: 2;
top: 50%;
left: 0;
height: 100%;
text-align: center;
color: #FFF;
font-size: 20px;
transform: translateY(-50%);
}
.wrapper {
position: absolute;
left: 44px;
bottom: 0;
background: $primary_color;
border-radius: $border_radius 0 0 $border_radius;
display: none;
box-shadow: 0 0 15px 2px rgba(0,0,0,.15);
&:before {
transform: rotate(45deg);
content: '';
display: block;
position: absolute;
height: 10px;
width: 10px;
background: $primary_color;
left: -6px;
bottom: 16px;
z-index: 1;
}
}
.input {
background: $background_color;
border-radius: $border_radius 0 0 $border_radius;
position: relative;
left: 4px;
height: 44px;
overflow: hidden;
width: 100%;
input {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
z-index: 1;
&::-ms-clear {
width : 0;
height: 0;
}
&:focus {
background: rgba($theme_off, .2);
&::-webkit-input-placeholder {
color: $text_color;
opacity: .7;
}
&::-moz-placeholder {
color: $text_color;
opacity: .7;
}
&:-ms-input-placeholder {
color: $text_color;
opacity: .7;
}
}
}
}
&.filled {
&.focused .icon-search:before,
.page.home & .icon-search:before {
content: '\e80e';
}
.input input {
background: rgba($theme_off, .4);
}
}
&.focused,
&.shown,
.page.home & {
border-color: #04bce6;
.wrapper {
display: block;
width: 380px;
transform-origin: 0 90%;
@include media-phablet {
width: 260px;
}
}
.input {
input {
opacity: 1;
}
}
}
.results_container {
min-height: 50px;
text-align: left;
position: relative;
left: 4px;
display: none;
background: $background_color;
border-radius: $border_radius 0 0 0;
overflow: hidden;
.results {
max-height: 280px;
overflow-x: hidden;
.media_result {
overflow: hidden;
height: 50px;
position: relative;
@include media-phablet {
font-size: 12px;
}
.options {
position: absolute;
height: 100%;
top: 0;
left: 30px;
right: 0;
background: rgba(0,0,0,.3);
display: flex;
align-items: center;
@include media-phablet {
left: 0;
}
> .in_library_wanted {
margin-top: -7px;
}
> div {
border: 0;
display: flex;
padding: 10px;
align-items: stretch;
justify-content: space-between;
@include media-phablet {
padding: 3px;
}
}
select {
display: block;
height: 100%;
width: 100%;
@include media-phablet {
min-width: 0;
margin-right: 2px;
}
}
.title {
margin-right: 5px;
width: 210px;
@include media-phablet {
width: 140px;
margin-right: 2px;
}
}
.profile, .category {
margin: 0 5px 0 0;
@include media-phablet {
margin-right: 2px;
}
}
.add {
width: 42px;
flex: 1 auto;
a {
color: #FFF;
}
}
.button {
display: block;
background: $primary_color;
text-align: center;
margin: 0;
}
.message {
font-size: 20px;
color: #fff;
}
}
.thumbnail {
width: 30px;
min-height: 100%;
display: block;
margin: 0;
vertical-align: top;
@include media-phablet {
display: none;
}
}
.data {
position: absolute;
height: 100%;
top: 0;
left: 30px;
right: 0;
cursor: pointer;
border-top: 1px solid rgba(255,255,255, 0.08);
transition: all .4s cubic-bezier(0.9,0,0.1,1);
transform: translateX(0);
background: $background_color;
@include media-phablet {
left: 0;
}
&:hover {
transform: translateX(2%);
}
&.open {
transform: translateX(100%);
}
.info {
position: absolute;
top: 20%;
left: 15px;
right: 7px;
vertical-align: middle;
h2 {
margin: 0;
font-weight: 300;
font-size: 1.25em;
padding: 0;
position: absolute;
width: 100%;
display: flex;
.title {
display: inline-block;
margin: 0;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
flex: 1 auto;
}
.year {
opacity: .4;
padding: 0 5px;
width: auto;
display: none;
}
.in_wanted,
.in_library {
position: absolute;
top: 15px;
left: 0;
font-size: 11px;
color: $primary_color;
}
&.in_library_wanted {
.title {
margin-top: -7px;
}
}
}
}
}
&:hover .info h2 .year {
display: inline-block;
}
&:last-child .data {
border-bottom: 0;
}
}
}
}
&.focused.filled,
&.shown.filled {
.results_container {
display: block;
}
.input {
border-radius: 0 0 0 $border_radius;
}
}
.page.home & {
$input_height: 66px;
$input_height_mobile: 44px;
display: block;
padding: $padding;
width: 100%;
max-width: 500px;
margin: 0 auto;
height: $input_height + 2*$padding;
position: relative;
margin-top: $padding;
@include media-phablet {
margin-top: $padding/2;
height: $input_height_mobile + $padding;
}
.icon-search {
display: block;
color: #000;
right: $padding;
top: $padding;
width: $input_height;
height: $input_height;
line-height: $input_height;
left: auto;
transform: none;
font-size: 2em;
opacity: .5;
@include media-phablet {
right: $padding/2;
width: $input_height_mobile;
height: $input_height_mobile;
line-height: $input_height_mobile;
right: $padding/2;
top: $padding/2;
font-size: 1.5em;
}
}
.wrapper {
border-radius: 0;
box-shadow: none;
bottom: auto;
top: $padding;
left: $padding;
right: $padding;
position: absolute;
width: auto;
@include media-phablet {
right: $padding/2;
top: $padding/2;
left: $padding/2;
}
&:before {
display: none;
}
.input {
border-radius: 0;
left: 0;
position: absolute;
top: 0;
height: $input_height;
@include media-phablet {
height: $input_height_mobile;
}
input {
box-shadow: 0;
font-size: 2em;
font-weight: 400;
@include media-phablet {
font-size: 1em;
}
}
}
.results_container {
min-height: $input_height;
position: absolute;
top: $input_height;
left: 0;
right: 0;
border: 1px solid #b7b7b7;
border-top: 0;
@include media-phablet {
top: $input_height_mobile;
min-height: $input_height_mobile;
}
@include media-phablet-and-up {
.results {
max-height: 400px;
.media_result {
height: $input_height;
@include media-phablet {
height: $input_height_mobile;
}
.thumbnail {
width: 40px;
}
.options {
left: 40px;
.title {
margin-right: 5px;
width: 320px;
@include media-phablet {
width: 140px;
margin-right: 2px;
}
}
}
.data {
left: 40px;
}
}
}
}
@include media-phablet {
.results {
.media_result {
height: $input_height_mobile;
.options {
.title {
width: 140px;
margin-right: 2px;
}
}
}
}
}
}
}
}
}
.big_search {
background: $theme_off;
}

11
couchpotato/core/media/movie/_base/main.py

@ -34,6 +34,7 @@ class MovieBase(MovieTypeBase):
'params': {
'identifier': {'desc': 'IMDB id of the movie your want to add.'},
'profile_id': {'desc': 'ID of quality profile you want the add the movie in. If empty will use the default profile.'},
'force_readd': {'desc': 'Force re-add even if movie already in wanted or manage. Default: True'},
'category_id': {'desc': 'ID of category you want the add the movie in. If empty will use no category.'},
'title': {'desc': 'Movie title to use for searches. Has to be one of the titles returned by movie.search.'},
}
@ -78,6 +79,11 @@ class MovieBase(MovieTypeBase):
if not info or (info and len(info.get('titles', [])) == 0):
info = fireEvent('movie.info', merge = True, extended = False, identifier = params.get('identifier'))
# Allow force re-add overwrite from param
if 'force_readd' in params:
fra = params.get('force_readd')
force_readd = fra.lower() not in ['0', '-1'] if not isinstance(fra, bool) else fra
# Set default title
default_title = toUnicode(info.get('title'))
titles = info.get('titles', [])
@ -224,11 +230,11 @@ class MovieBase(MovieTypeBase):
try:
m = db.get('id', media_id)
m['profile_id'] = kwargs.get('profile_id')
m['profile_id'] = kwargs.get('profile_id') or m['profile_id']
cat_id = kwargs.get('category_id')
if cat_id is not None:
m['category_id'] = cat_id if len(cat_id) > 0 else None
m['category_id'] = cat_id if len(cat_id) > 0 else m['category_id']
# Remove releases
for rel in fireEvent('release.for_media', m['_id'], single = True):
@ -249,6 +255,7 @@ class MovieBase(MovieTypeBase):
fireEventAsync('movie.searcher.single', movie_dict, on_complete = self.createNotifyFront(media_id))
except:
print traceback.format_exc()
log.error('Can\'t edit non-existing media')
return {

154
couchpotato/core/media/movie/_base/static/details.js

@ -0,0 +1,154 @@
var MovieDetails = new Class({
Extends: BlockBase,
sections: null,
buttons: null,
initialize: function(parent, options){
var self = this;
self.sections = {};
var category = parent.get('category'),
profile = parent.profile;
self.el = new Element('div',{
'class': 'page active movie_details level_' + (options.level || 0)
}).adopt(
self.overlay = new Element('div.overlay', {
'events': {
'click': self.close.bind(self)
}
}).grab(
new Element('a.close.icon-left-arrow')
),
self.content = new Element('div.scroll_content').grab(
new Element('div.head').adopt(
new Element('h1').grab(
self.title_dropdown = new BlockMenu(self, {
'class': 'title',
'button_text': parent.getTitle() + (parent.get('year') ? ' (' + parent.get('year') + ')' : ''),
'button_class': 'icon-dropdown'
})
),
self.buttons = new Element('div.buttons')
)
)
);
self.addSection('description', new Element('div', {
'text': parent.get('plot')
}));
// Title dropdown
var titles = parent.get('info').titles;
$(self.title_dropdown).addEvents({
'click:relay(li a)': function(e, el){
(e).stopPropagation();
// Update category
Api.request('movie.edit', {
'data': {
'id': parent.get('_id'),
'default_title': el.get('text')
}
});
$(self.title_dropdown).getElements('.icon-ok').removeClass('icon-ok');
el.addClass('icon-ok');
self.title_dropdown.button.set('text', el.get('text') + (parent.get('year') ? ' (' + parent.get('year') + ')' : ''));
}
});
titles.each(function(t){
self.title_dropdown.addLink(new Element('a', {
'text': t,
'class': parent.get('title') == t ? 'icon-ok' : ''
}));
});
},
addSection: function(name, section_el){
var self = this;
name = name.toLowerCase();
self.content.grab(
self.sections[name] = new Element('div', {
'class': 'section section_' + name
}).grab(section_el)
);
},
addButton: function(button){
var self = this;
self.buttons.grab(button);
},
open: function(){
var self = this;
self.el.addClass('show');
if(!App.mobile_screen){
$(self.content).getElements('> .head, > .section').each(function(section, nr){
dynamics.css(section, {
opacity: 0,
translateY: 100
});
dynamics.animate(section, {
opacity: 1,
translateY: 0
}, {
type: dynamics.spring,
frequency: 200,
friction: 300,
duration: 1200,
delay: 500 + (nr * 100)
});
});
}
},
close: function(){
var self = this;
var ended = function() {
self.el.dispose();
self.overlay.removeEventListener('transitionend', ended);
};
self.overlay.addEventListener('transitionend', ended, false);
// animate out
if(!App.mobile_screen){
$(self.content).getElements('> .head, > .section').reverse().each(function(section, nr){
dynamics.animate(section, {
opacity: 0,
translateY: 100
}, {
type: dynamics.spring,
frequency: 200,
friction: 300,
duration: 1200,
delay: (nr * 50)
});
});
dynamics.setTimeout(function(){
self.el.removeClass('show');
}, 200);
}
else {
self.el.removeClass('show');
}
}
});

207
couchpotato/core/media/movie/_base/static/list.js

@ -3,6 +3,7 @@ var MovieList = new Class({
Implements: [Events, Options],
options: {
api_call: 'media.list',
navigation: true,
limit: 50,
load_more: true,
@ -37,7 +38,28 @@ var MovieList = new Class({
'html': self.options.description,
'styles': {'display': 'none'}
}) : null,
self.movie_list = new Element('div'),
self.movie_list = new Element('div', {
'events': {
'click:relay(.movie)': function(e, el){
el.retrieve('klass').onClick(e);
},
'mouseenter:relay(.movie)': function(e, el){
(e).stopPropagation();
el.retrieve('klass').onMouseenter(e);
},
'mouseleave:relay(.movie)': function(e, el){
(e).stopPropagation();
el.retrieve('klass').onMouseleave(e);
},
'change:relay(.movie input)': function(e, el){
(e).stopPropagation();
el = el.getParent();
var klass = el.retrieve('klass');
klass.fireEvent('select');
klass.select(klass.select_checkbox.get('checked'));
}
}
}),
self.load_more = self.options.load_more ? new Element('a.load_more', {
'events': {
'click': self.loadMore.bind(self)
@ -45,15 +67,17 @@ var MovieList = new Class({
}) : null
);
if($(window).getSize().x <= 480 && !self.options.force_view)
self.changeView('list');
else
self.changeView(self.getSavedView() || self.options.view || 'details');
self.changeView(self.getSavedView() || self.options.view || 'thumb');
self.getMovies();
// Create the alphabet nav
if(self.options.navigation)
self.createNavigation();
if(self.options.api_call)
self.getMovies();
App.on('movie.added', self.movieAdded.bind(self));
App.on('movie.deleted', self.movieDeleted.bind(self))
App.on('movie.deleted', self.movieDeleted.bind(self));
},
movieDeleted: function(notification){
@ -67,7 +91,7 @@ var MovieList = new Class({
self.setCounter(self.counter_count-1);
self.total_movies--;
}
})
});
}
self.checkIfEmpty();
@ -89,18 +113,15 @@ var MovieList = new Class({
create: function(){
var self = this;
// Create the alphabet nav
if(self.options.navigation)
self.createNavigation();
if(self.options.load_more)
if(self.options.load_more){
self.scrollspy = new ScrollSpy({
container: self.el.getParent(),
min: function(){
var c = self.load_more.getCoordinates();
return c.top - window.document.getSize().y - 300
return self.load_more.getCoordinates().top;
},
onEnter: self.loadMore.bind(self)
});
}
self.created = true;
},
@ -108,6 +129,7 @@ var MovieList = new Class({
addMovies: function(movies, total){
var self = this;
if(!self.created) self.create();
// do scrollspy
@ -116,13 +138,12 @@ var MovieList = new Class({
self.scrollspy.stop();
}
Object.each(movies, function(movie){
self.createMovie(movie);
});
self.createMovie(movies, 'bottom');
self.total_movies += total;
self.setCounter(total);
self.calculateSelected();
},
setCounter: function(count){
@ -138,7 +159,7 @@ var MovieList = new Class({
self.empty_message = null;
}
if(self.total_movies && count == 0 && !self.empty_message){
if(self.total_movies && count === 0 && !self.empty_message){
var message = (self.filter.search ? 'for "'+self.filter.search+'"' : '') +
(self.filter.starts_with ? ' in <strong>'+self.filter.starts_with+'</strong>' : '');
@ -167,20 +188,37 @@ var MovieList = new Class({
},
createMovie: function(movie, inject_at){
var self = this;
var m = new Movie(self, {
'actions': self.options.actions,
'view': self.current_view,
'onSelect': self.calculateSelected.bind(self)
}, movie);
createMovie: function(movie, inject_at, nr){
var self = this,
movies = Array.isArray(movie) ? movie : [movie],
movie_els = [];
inject_at = inject_at || 'bottom';
movies.each(function(movie, nr){
var m = new Movie(self, {
'actions': self.options.actions,
'view': self.current_view,
'onSelect': self.calculateSelected.bind(self)
}, movie);
$(m).inject(self.movie_list, inject_at || 'bottom');
var el = $(m);
m.fireEvent('injected');
if(inject_at === 'bottom'){
movie_els.push(el);
}
else {
el.inject(self.movie_list, inject_at);
}
self.movies.include(m);
self.movies_added[movie._id] = true;
});
if(movie_els.length > 0){
$(self.movie_list).adopt(movie_els);
}
self.movies.include(m);
self.movies_added[movie._id] = true;
},
createNavigation: function(){
@ -192,7 +230,7 @@ var MovieList = new Class({
self.navigation = new Element('div.alph_nav').adopt(
self.mass_edit_form = new Element('div.mass_edit_form').adopt(
new Element('span.select').adopt(
self.mass_edit_select = new Element('input[type=checkbox].inlay', {
self.mass_edit_select = new Element('input[type=checkbox]', {
'events': {
'change': self.massEditToggleAll.bind(self)
}
@ -230,38 +268,40 @@ var MovieList = new Class({
),
new Element('div.menus').adopt(
self.navigation_counter = new Element('span.counter[title=Total]'),
self.filter_menu = new Block.Menu(self, {
'class': 'filter'
self.filter_menu = new BlockMenu(self, {
'class': 'filter',
'button_class': 'icon-filter'
}),
self.navigation_actions = new Element('ul.actions', {
self.navigation_actions = new Element('div.actions', {
'events': {
'click:relay(li)': function(e, el){
'click': function(e, el){
(e).preventDefault();
var new_view = self.current_view == 'list' ? 'thumb' : 'list';
var a = 'active';
self.navigation_actions.getElements('.'+a).removeClass(a);
self.changeView(el.get('data-view'));
this.addClass(a);
el.inject(el.getParent(), 'top');
el.getSiblings().hide();
setTimeout(function(){
el.getSiblings().setStyle('display', null);
}, 100)
self.changeView(new_view);
self.navigation_actions.getElement('[data-view='+new_view+']')
.addClass(a);
}
}
}),
self.navigation_menu = new Block.Menu(self, {
'class': 'extra'
self.navigation_menu = new BlockMenu(self, {
'class': 'extra',
'button_class': 'icon-dots'
})
)
).inject(self.el, 'top');
);
// Mass edit
self.mass_edit_select_class = new Form.Check(self.mass_edit_select);
Quality.getActiveProfiles().each(function(profile){
new Element('option', {
'value': profile.get('_id'),
'text': profile.get('label')
}).inject(self.mass_edit_quality)
}).inject(self.mass_edit_quality);
});
self.filter_menu.addLink(
@ -273,7 +313,7 @@ var MovieList = new Class({
'change': self.search.bind(self)
}
})
).addClass('search');
).addClass('search icon-search');
var available_chars;
self.filter_menu.addEvent('open', function(){
@ -289,8 +329,8 @@ var MovieList = new Class({
available_chars = json.chars;
available_chars.each(function(c){
self.letters[c.capitalize()].addClass('available')
})
self.letters[c.capitalize()].addClass('available');
});
}
});
@ -301,23 +341,23 @@ var MovieList = new Class({
'events': {
'click:relay(li.available)': function(e, el){
self.activateLetter(el.get('data-letter'));
self.getMovies(true)
self.getMovies(true);
}
}
})
);
// Actions
['mass_edit', 'details', 'list'].each(function(view){
['thumb', 'list'].each(function(view){
var current = self.current_view == view;
new Element('li', {
'class': 'icon2 ' + view + (current ? ' active ' : ''),
new Element('a', {
'class': 'icon-' + view + (current ? ' active ' : ''),
'data-view': view
}).inject(self.navigation_actions, current ? 'top' : 'bottom');
});
// All
self.letters['all'] = new Element('li.letter_all.available.active', {
self.letters.all = new Element('li.letter_all.available.active', {
'text': 'ALL'
}).inject(self.navigation_alpha);
@ -346,24 +386,26 @@ var MovieList = new Class({
var selected = 0,
movies = self.movies.length;
self.movies.each(function(movie){
selected += movie.isSelected() ? 1 : 0
selected += movie.isSelected() ? 1 : 0;
});
var indeterminate = selected > 0 && selected < movies,
checked = selected == movies && selected > 0;
self.mass_edit_select.set('indeterminate', indeterminate);
document.body[selected > 0 ? 'addClass' : 'removeClass']('mass_editing');
self.mass_edit_select_class[checked ? 'check' : 'uncheck']();
self.mass_edit_select_class.element[indeterminate ? 'addClass' : 'removeClass']('indeterminate');
if(self.mass_edit_select){
self.mass_edit_select.set('checked', checked);
self.mass_edit_select.indeterminate = indeterminate;
self.mass_edit_selected.set('text', selected);
self.mass_edit_selected.set('text', selected);
}
},
deleteSelected: function(){
var self = this,
ids = self.getSelectedMovies(),
help_msg = self.identifier == 'wanted' ? 'If you do, you won\'t be able to watch them, as they won\'t get downloaded!' : 'Your files will be safe, this will only delete the reference from the CouchPotato manage list';
help_msg = self.identifier == 'wanted' ? 'If you do, you won\'t be able to watch them, as they won\'t get downloaded!' : 'Your files will be safe, this will only delete the references in CouchPotato';
var qObj = new Question('Are you sure you want to delete '+ids.length+' movie'+ (ids.length != 1 ? 's' : '') +'?', help_msg, [{
'text': 'Yes, delete '+(ids.length != 1 ? 'them' : 'it'),
@ -441,10 +483,10 @@ var MovieList = new Class({
var ids = [];
self.movies.each(function(movie){
if (movie.isSelected())
ids.include(movie.get('_id'))
ids.include(movie.get('_id'));
});
return ids
return ids;
},
massEditToggleAll: function(){
@ -453,10 +495,10 @@ var MovieList = new Class({
var select = self.mass_edit_select.get('checked');
self.movies.each(function(movie){
movie.select(select)
movie.select(select);
});
self.calculateSelected()
self.calculateSelected();
},
reset: function(){
@ -493,12 +535,12 @@ var MovieList = new Class({
.addClass(new_view+'_list');
self.current_view = new_view;
Cookie.write(self.options.identifier+'_view2', new_view, {duration: 1000});
Cookie.write(self.options.identifier+'_view', new_view, {duration: 1000});
},
getSavedView: function(){
var self = this;
return Cookie.read(self.options.identifier+'_view2');
return self.options.force_view ? self.options.view : Cookie.read(self.options.identifier+'_view');
},
search: function(){
@ -537,23 +579,24 @@ var MovieList = new Class({
self.load_more.set('text', 'loading...');
}
if(self.movies.length == 0 && self.options.loader){
var loader_timeout;
if(self.movies.length === 0 && self.options.loader){
self.loader_first = new Element('div.loading').adopt(
self.loader_first = new Element('div.mask.loading.with_message').grab(
new Element('div.message', {'text': self.options.title ? 'Loading \'' + self.options.title + '\'' : 'Loading...'})
).inject(self.el, 'top');
createSpinner(self.loader_first);
createSpinner(self.loader_first, {
radius: 4,
length: 4,
width: 1
});
var lfc = self.loader_first;
loader_timeout = setTimeout(function(){
lfc.addClass('show');
}, 10);
self.el.setStyle('min-height', 93);
self.el.setStyle('min-height', 220);
}
Api.request(self.options.api_call || 'media.list', {
Api.request(self.options.api_call, {
'data': Object.merge({
'type': self.options.type || 'movie',
'status': self.options.status,
@ -564,13 +607,15 @@ var MovieList = new Class({
if(reset)
self.movie_list.empty();
if(loader_timeout) clearTimeout(loader_timeout);
if(self.loader_first){
var lf = self.loader_first;
self.loader_first.addClass('hide');
self.loader_first = null;
lf.removeClass('show');
setTimeout(function(){
lf.destroy();
}, 20000);
}, 1000);
self.el.setStyle('min-height', null);
}
@ -590,7 +635,7 @@ var MovieList = new Class({
loadMore: function(){
var self = this;
if(self.offset >= self.options.limit)
self.getMovies()
self.getMovies();
},
store: function(movies){
@ -603,7 +648,7 @@ var MovieList = new Class({
checkIfEmpty: function(){
var self = this;
var is_empty = self.movies.length == 0 && (self.total_movies == 0 || self.total_movies === undefined);
var is_empty = self.movies.length === 0 && (self.total_movies === 0 || self.total_movies === undefined);
if(self.title)
self.title[is_empty ? 'hide' : 'show']();

26
couchpotato/core/media/movie/_base/static/manage.js

@ -1,4 +1,4 @@
Page.Manage = new Class({
var MoviesManage = new Class({
Extends: PageBase,
@ -33,15 +33,12 @@ Page.Manage = new Class({
'release_status': 'done',
'status_or': 1
},
'actions': [MA.IMDB, MA.Trailer, MA.Files, MA.Readd, MA.Edit, MA.Delete],
'actions': [MA.IMDB, MA.Files, MA.Trailer, MA.Readd, MA.Delete],
'menu': [self.refresh_button, self.refresh_quick],
'on_empty_element': new Element('div.empty_manage').adopt(
new Element('div', {
'text': 'Seems like you don\'t have anything in your library yet.'
}),
new Element('div', {
'text': 'Add your existing movie folders in '
}).adopt(
'text': 'Seems like you don\'t have anything in your library yet. Add your existing movie folders in '
}).grab(
new Element('a', {
'text': 'Settings > Manage',
'href': App.createUrl('settings/manage')
@ -49,7 +46,7 @@ Page.Manage = new Class({
),
new Element('div.after_manage', {
'text': 'When you\'ve done that, hit this button → '
}).adopt(
}).grab(
new Element('a.button.green', {
'text': 'Hit me, but not too hard',
'events':{
@ -59,7 +56,7 @@ Page.Manage = new Class({
)
)
});
$(self.list).inject(self.el);
$(self.list).inject(self.content);
// Check if search is in progress
self.startProgressInterval();
@ -113,7 +110,8 @@ Page.Manage = new Class({
return;
if(!self.progress_container)
self.progress_container = new Element('div.progress').inject(self.list.navigation, 'after');
self.progress_container = new Element('div.progress')
.inject(self.list, 'top');
self.progress_container.empty();
@ -126,12 +124,12 @@ Page.Manage = new Class({
(folder_progress.eta > 0 ? ', ' + new Date ().increment('second', folder_progress.eta).timeDiffInWords().replace('from now', 'to go') : '')
}),
new Element('span.percentage', {'text': folder_progress.total ? Math.round(((folder_progress.total-folder_progress.to_go)/folder_progress.total)*100) + '%' : '0%'})
).inject(self.progress_container)
).inject(self.progress_container);
});
}
}
})
});
}, 1000);
},
@ -141,10 +139,10 @@ Page.Manage = new Class({
for (folder in progress_object) {
if (progress_object.hasOwnProperty(folder)) {
temp_array.push(folder)
temp_array.push(folder);
}
}
return temp_array.stableSort()
return temp_array.stableSort();
}
});

900
couchpotato/core/media/movie/_base/static/movie.actions.js

File diff suppressed because it is too large

1074
couchpotato/core/media/movie/_base/static/movie.css

File diff suppressed because it is too large

316
couchpotato/core/media/movie/_base/static/movie.js

@ -1,23 +1,61 @@
var Movie = new Class({
Extends: BlockBase,
Implements: [Options, Events],
action: {},
actions: null,
details: null,
initialize: function(list, options, data){
var self = this;
self.actions = [];
self.data = data;
self.view = options.view || 'details';
self.list = list;
self.el = new Element('div.movie');
self.buttons = [];
self.el = new Element('a.movie');
self.el.store('klass', self);
self.profile = Quality.getProfile(data.profile_id) || {};
self.category = CategoryList.getCategory(data.category_id) || {};
self.parent(self, options);
self.addEvents();
//if(data.identifiers.imdb == 'tt3181822'){
// self.el.fireEvent('mouseenter');
// self.openDetails();
//}
},
openDetails: function(){
var self = this;
if(!self.details){
self.details = new MovieDetails(self, {
'level': 3
});
// Add action items
self.actions.each(function(action, nr){
var details = action.getDetails();
if(details){
self.details.addSection(action.getLabel(), details);
}
else {
var button = action.getDetailButton();
if(button){
self.details.addButton(button);
}
}
});
}
App.getPageContainer().grab(self.details);
self.details.open.delay(10, self.details);
},
addEvents: function(){
@ -30,7 +68,6 @@ var Movie = new Class({
if(self.data._id != notification.data._id) return;
self.busy(false);
self.removeView();
self.update.delay(2000, self, notification);
};
App.on('movie.update', self.global_events['movie.update']);
@ -47,7 +84,7 @@ var Movie = new Class({
// Remove spinner
self.global_events['movie.searcher.ended'] = function(notification){
if(notification.data && self.data._id == notification.data._id)
self.busy(false)
self.busy(false);
};
App.on('movie.searcher.ended', self.global_events['movie.searcher.ended']);
@ -62,7 +99,7 @@ var Movie = new Class({
var updated = false;
self.data.releases.each(function(release){
if(release._id == data._id){
release['status'] = data.status;
release.status = data.status;
updated = true;
}
});
@ -85,6 +122,9 @@ var Movie = new Class({
self.list.checkIfEmpty();
if(self.details)
self.details.close();
// Remove events
Object.each(self.global_events, function(handle, listener){
App.off(listener, handle);
@ -102,12 +142,12 @@ var Movie = new Class({
if(self.mask)
self.mask.destroy();
if(self.spinner)
self.spinner.el.destroy();
self.spinner.destroy();
self.spinner = null;
self.mask = null;
}, timeout || 400);
}
}, timeout || 1000)
}, timeout || 1000);
}
else if(!self.spinner) {
self.createMask();
@ -128,94 +168,121 @@ var Movie = new Class({
update: function(notification){
var self = this;
self.actions = [];
self.data = notification.data;
self.el.empty();
self.removeView();
self.profile = Quality.getProfile(self.data.profile_id) || {};
self.category = CategoryList.getCategory(self.data.category_id) || {};
self.create();
self.select(self.select_checkbox.get('checked'));
self.busy(false);
},
create: function(){
var self = this;
var self = this,
d = new Date();
self.el.addClass('status_'+self.get('status'));
var eta = null,
eta_date = null,
now = Math.round(+new Date()/1000);
now = Math.round(+d/1000);
if(self.data.info.release_date)
[self.data.info.release_date.dvd, self.data.info.release_date.theater].each(function(timestamp){
if (timestamp > 0 && (eta == null || Math.abs(timestamp - now) < Math.abs(eta - now)))
if (timestamp > 0 && (eta === null || Math.abs(timestamp - now) < Math.abs(eta - now)))
eta = timestamp;
});
if(eta){
eta_date = new Date(eta * 1000);
eta_date = eta_date.toLocaleString('en-us', { month: "long" }) + ' ' + eta_date.getFullYear();
if(+eta_date/1000 < now){
eta_date = null;
}
else {
eta_date = eta_date.format('%b') + (d.getFullYear() != eta_date.getFullYear() ? ' ' + eta_date.getFullYear() : '');
}
}
self.el.adopt(
self.select_checkbox = new Element('input[type=checkbox].inlay', {
'events': {
'change': function(){
self.fireEvent('select')
}
var rating, stars;
if(['suggested','chart'].indexOf(self.data.status) > -1 && self.data.info && self.data.info.rating && self.data.info.rating.imdb){
rating = self.data.info.rating.imdb;
stars = [];
var half_rating = rating[0]/2;
for(var i = 1; i <= 5; i++){
if(half_rating >= 1)
stars.push(new Element('span.icon-star'));
else if(half_rating > 0)
stars.push(new Element('span.icon-star-half'));
else
stars.push(new Element('span.icon-star-empty'));
half_rating -= 1;
}
}
var thumbnail = new Element('div.poster');
if(self.data.files && self.data.files.image_poster && self.data.files.image_poster.length > 0){
thumbnail = new Element('div', {
'class': 'type_image poster',
'styles': {
'background-image': 'url(' + Api.createUrl('file.cache') + self.data.files.image_poster[0].split(Api.getOption('path_sep')).pop() +')'
}
}),
self.thumbnail = (self.data.files && self.data.files.image_poster && self.data.files.image_poster.length > 0) ? new Element('img', {
});
}
else if(self.data.info && self.data.info.images && self.data.info.images.poster && self.data.info.images.poster.length > 0){
thumbnail = new Element('div', {
'class': 'type_image poster',
'src': Api.createUrl('file.cache') + self.data.files.image_poster[0].split(Api.getOption('path_sep')).pop()
}): null,
self.data_container = new Element('div.data.inlay.light').adopt(
self.info_container = new Element('div.info').adopt(
new Element('div.title').adopt(
self.title = new Element('span', {
'text': self.getTitle() || 'n/a'
}),
self.year = new Element('div.year', {
'text': self.data.info.year || 'n/a'
})
),
self.description = new Element('div.description.tiny_scroll', {
'text': self.data.info.plot
'styles': {
'background-image': 'url(' + self.data.info.images.poster[0] +')'
}
});
}
self.el.adopt(
self.select_checkbox = new Element('input[type=checkbox]'),
new Element('div.poster_container').adopt(
thumbnail,
self.actions_el = new Element('div.actions')
),
new Element('div.info').adopt(
new Element('div.title').adopt(
new Element('span', {
'text': self.getTitle() || 'n/a'
}),
self.eta = eta_date && (now+8035200 > eta) ? new Element('div.eta', {
'text': eta_date,
'title': 'ETA'
}) : null,
self.quality = new Element('div.quality', {
'events': {
'click': function(e){
var releases = self.el.getElement('.actions .releases');
if(releases.isVisible())
releases.fireEvent('click', [e])
}
}
new Element('div.year', {
'text': self.data.info.year || 'n/a'
})
),
self.actions = new Element('div.actions')
eta_date && (now+8035200 > eta) ? new Element('div.eta', {
'text': eta_date,
'title': 'ETA'
}) : null,
self.quality = new Element('div.quality'),
rating ? new Element('div.rating[title='+rating[0]+']').adopt(
stars,
new Element('span.votes[text=('+rating.join(' / ')+')][title=Votes]')
) : null
)
);
if(!self.thumbnail)
if(!thumbnail)
self.el.addClass('no_thumbnail');
//self.changeView(self.view);
self.select_checkbox_class = new Form.Check(self.select_checkbox);
// Add profile
if(self.profile.data)
self.profile.getTypes().each(function(type){
var q = self.addQuality(type.get('quality'), type.get('3d'));
if((type.finish == true || type.get('finish')) && !q.hasClass('finish')){
if((type.finish === true || type.get('finish')) && !q.hasClass('finish')){
q.addClass('finish');
q.set('title', q.get('title') + ' Will finish searching for this movie if this quality is found.')
q.set('title', q.get('title') + ' Will finish searching for this movie if this quality is found.');
}
});
@ -223,17 +290,84 @@ var Movie = new Class({
// Add releases
self.updateReleases();
Object.each(self.options.actions, function(action, key){
self.action[key.toLowerCase()] = action = new self.options.actions[key](self);
if(action.el)
self.actions.adopt(action)
});
},
onClick: function(e){
var self = this;
if(e.target.getParents('.actions').length == 0 && e.target != self.select_checkbox){
(e).stopPropagation();
self.openDetails();
}
},
onMouseenter: function(){
var self = this;
if(self.actions.length <= 0){
self.options.actions.each(function(a){
var action = new a(self),
button = action.getButton();
if(button){
self.actions_el.grab(button);
self.buttons.push(button);
}
self.actions.push(action);
});
}
if(App.mobile_screen) return;
if(self.list.current_view == 'thumb'){
dynamics.css(self.el, {
scale: 1,
opacity: 1
});
dynamics.animate(self.el, {
scale: 0.9
}, { type: dynamics.bounce });
self.buttons.each(function(el, nr){
dynamics.css(el, {
opacity: 0,
translateY: 50
});
dynamics.animate(el, {
opacity: 1,
translateY: 0
}, {
type: dynamics.spring,
frequency: 200,
friction: 300,
duration: 800,
delay: 100 + (nr * 40)
});
});
}
},
onMouseleave: function(){
var self = this;
if(App.mobile_screen) return;
if(self.list.current_view == 'thumb'){
dynamics.animate(self.el, {
scale: 1
}, { type: dynamics.spring });
}
},
updateReleases: function(){
var self = this;
if(!self.data.releases || self.data.releases.length == 0) return;
if(!self.data.releases || self.data.releases.length === 0) return;
self.data.releases.each(function(release){
@ -245,7 +379,7 @@ var Movie = new Class({
if (q && !q.hasClass(status)){
q.addClass(status);
q.set('title', (q.get('title') ? q.get('title') : '') + ' status: '+ status)
q.set('title', (q.get('title') ? q.get('title') : '') + ' status: '+ status);
}
});
@ -263,15 +397,15 @@ var Movie = new Class({
},
getTitle: function(){
getTitle: function(prefixed){
var self = this;
if(self.data.title)
return self.getUnprefixedTitle(self.data.title);
else if(self.data.info.titles.length > 0)
return self.getUnprefixedTitle(self.data.info.titles[0]);
return prefixed ? self.data.title : self.getUnprefixedTitle(self.data.title);
else if(self.data.info && self.data.info.titles && self.data.info.titles.length > 0)
return prefixed ? self.data.info.titles[0] : self.getUnprefixedTitle(self.data.info.titles[0]);
return 'Unknown movie'
return 'Unknown movie';
},
getUnprefixedTitle: function(t){
@ -284,49 +418,6 @@ var Movie = new Class({
return t;
},
slide: function(direction, el){
var self = this;
if(direction == 'in'){
self.temp_view = self.view;
self.changeView('details');
self.el.addEvent('outerClick', function(){
self.removeView();
self.slide('out')
});
el.show();
self.data_container.addClass('hide_right');
}
else {
self.el.removeEvents('outerClick');
setTimeout(function(){
if(self.el)
self.el.getElements('> :not(.data):not(.poster):not(.movie_container)').hide();
}, 600);
self.data_container.removeClass('hide_right');
}
},
changeView: function(new_view){
var self = this;
if(self.el)
self.el
.removeClass(self.view+'_view')
.addClass(new_view+'_view');
self.view = new_view;
},
removeView: function(){
var self = this;
self.el.removeClass(self.view+'_view')
},
getIdentifier: function(){
var self = this;
@ -339,12 +430,13 @@ var Movie = new Class({
},
get: function(attr){
return this.data[attr] || this.data.info[attr]
return this.data[attr] || this.data.info[attr];
},
select: function(bool){
select: function(select){
var self = this;
self.select_checkbox_class[bool ? 'check' : 'uncheck']()
self.select_checkbox.set('checked', select);
self.el[self.select_checkbox.get('checked') ? 'addClass' : 'removeClass']('checked');
},
isSelected: function(){

1248
couchpotato/core/media/movie/_base/static/movie.scss

File diff suppressed because it is too large

50
couchpotato/core/media/movie/_base/static/page.js

@ -0,0 +1,50 @@
Page.Movies = new Class({
Extends: PageBase,
name: 'movies',
icon: 'movie',
sub_pages: ['Wanted', 'Manage'],
default_page: 'Wanted',
current_page: null,
initialize: function(parent, options){
var self = this;
self.parent(parent, options);
self.navigation = new BlockNavigation();
$(self.navigation).inject(self.content, 'top');
},
defaultAction: function(action, params){
var self = this;
if(self.current_page){
self.current_page.hide();
if(self.current_page.list && self.current_page.list.navigation)
self.current_page.list.navigation.dispose();
}
var route = new Route();
route.parse(action);
var page_name = route.getPage() != 'index' ? route.getPage().capitalize() : self.default_page;
var page = self.sub_pages.filter(function(page){
return page.name == page_name;
}).pick()['class'];
page.open(route.getAction() || 'index', params);
page.show();
if(page.list && page.list.navigation)
page.list.navigation.inject(self.navigation);
self.current_page = page;
self.navigation.activate(page_name.toLowerCase());
}
});

125
couchpotato/core/media/movie/_base/static/search.js

@ -1,4 +1,4 @@
Block.Search.MovieItem = new Class({
var BlockSearchMovieItem = new Class({
Implements: [Options, Events],
@ -16,28 +16,45 @@ Block.Search.MovieItem = new Class({
var self = this,
info = self.info;
var in_library;
if(info.in_library){
in_library = [];
(info.in_library.releases || []).each(function(release){
in_library.include(release.quality);
});
}
self.el = new Element('div.media_result', {
'id': info.imdb
'id': info.imdb,
'events': {
'click': self.showOptions.bind(self)//,
//'mouseenter': self.showOptions.bind(self),
//'mouseleave': self.closeOptions.bind(self)
}
}).adopt(
self.thumbnail = info.images && info.images.poster.length > 0 ? new Element('img.thumbnail', {
'src': info.images.poster[0],
'height': null,
'width': null
}) : null,
self.options_el = new Element('div.options.inlay'),
self.data_container = new Element('div.data', {
'events': {
'click': self.showOptions.bind(self)
}
}).adopt(
self.info_container = new Element('div.info').adopt(
new Element('h2').adopt(
self.options_el = new Element('div.options'),
self.data_container = new Element('div.data').grab(
self.info_container = new Element('div.info').grab(
new Element('h2', {
'class': info.in_wanted && info.in_wanted.profile_id || in_library ? 'in_library_wanted' : '',
'title': self.getTitle()
}).adopt(
self.title = new Element('span.title', {
'text': info.titles && info.titles.length > 0 ? info.titles[0] : 'Unknown'
'text': self.getTitle()
}),
self.year = info.year ? new Element('span.year', {
'text': info.year
}) : null
}) : null,
info.in_wanted && info.in_wanted.profile_id ? new Element('span.in_wanted', {
'text': 'Already in wanted list: ' + Quality.getProfile(info.in_wanted.profile_id).get('label')
}) : (in_library ? new Element('span.in_library', {
'text': 'Already in library: ' + in_library.join(', ')
}) : null)
)
)
)
@ -48,7 +65,7 @@ Block.Search.MovieItem = new Class({
self.alternativeTitle({
'title': title
});
})
});
},
alternativeTitle: function(alternative){
@ -68,7 +85,7 @@ Block.Search.MovieItem = new Class({
},
get: function(key){
return this.info[key]
return this.info[key];
},
showOptions: function(){
@ -77,7 +94,7 @@ Block.Search.MovieItem = new Class({
self.createOptions();
self.data_container.addClass('open');
self.el.addEvent('outerClick', self.closeOptions.bind(self))
self.el.addEvent('outerClick', self.closeOptions.bind(self));
},
@ -85,7 +102,7 @@ Block.Search.MovieItem = new Class({
var self = this;
self.data_container.removeClass('open');
self.el.removeEvents('outerClick')
self.el.removeEvents('outerClick');
},
add: function(e){
@ -105,7 +122,7 @@ Block.Search.MovieItem = new Class({
},
'onComplete': function(json){
self.options_el.empty();
self.options_el.adopt(
self.options_el.grab(
new Element('div.message', {
'text': json.success ? 'Movie successfully added.' : 'Movie didn\'t add properly. Check logs'
})
@ -116,7 +133,7 @@ Block.Search.MovieItem = new Class({
},
'onFailure': function(){
self.options_el.empty();
self.options_el.adopt(
self.options_el.grab(
new Element('div.message', {
'text': 'Something went wrong, check the logs for more info.'
})
@ -132,56 +149,50 @@ Block.Search.MovieItem = new Class({
if(!self.options_el.hasClass('set')){
if(info.in_library){
var in_library = [];
(info.in_library.releases || []).each(function(release){
in_library.include(release.quality)
});
}
self.options_el.grab(
new Element('div', {
'class': info.in_wanted && info.in_wanted.profile_id || in_library ? 'in_library_wanted' : ''
}).adopt(
info.in_wanted && info.in_wanted.profile_id ? new Element('span.in_wanted', {
'text': 'Already in wanted list: ' + Quality.getProfile(info.in_wanted.profile_id).get('label')
}) : (in_library ? new Element('span.in_library', {
'text': 'Already in library: ' + in_library.join(', ')
}) : null),
self.title_select = new Element('select', {
'name': 'title'
}),
self.profile_select = new Element('select', {
'name': 'profile'
}),
self.category_select = new Element('select', {
'name': 'category'
}).grab(
new Element('option', {'value': -1, 'text': 'None'})
new Element('div').adopt(
new Element('div.title').grab(
self.title_select = new Element('select', {
'name': 'title'
})
),
self.add_button = new Element('a.button', {
'text': 'Add',
'events': {
'click': self.add.bind(self)
}
})
new Element('div.profile').grab(
self.profile_select = new Element('select', {
'name': 'profile'
})
),
self.category_select_container = new Element('div.category').grab(
self.category_select = new Element('select', {
'name': 'category'
}).grab(
new Element('option', {'value': -1, 'text': 'None'})
)
),
new Element('div.add').grab(
self.add_button = new Element('a.button', {
'text': 'Add',
'events': {
'click': self.add.bind(self)
}
})
)
)
);
Array.each(self.alternative_titles, function(alt){
new Element('option', {
'text': alt.title
}).inject(self.title_select)
}).inject(self.title_select);
});
// Fill categories
var categories = CategoryList.getAll();
if(categories.length == 0)
self.category_select.hide();
if(categories.length === 0)
self.category_select_container.hide();
else {
self.category_select.show();
self.category_select_container.show();
categories.each(function(category){
new Element('option', {
'value': category.data._id,
@ -199,12 +210,12 @@ Block.Search.MovieItem = new Class({
new Element('option', {
'value': profile.get('_id'),
'text': profile.get('label')
}).inject(self.profile_select)
}).inject(self.profile_select);
});
self.options_el.addClass('set');
if(categories.length == 0 && self.title_select.getElements('option').length == 1 && profiles.length == 1 &&
if(categories.length === 0 && self.title_select.getElements('option').length == 1 && profiles.length == 1 &&
!(self.info.in_wanted && self.info.in_wanted.profile_id || in_library))
self.add();
@ -218,12 +229,12 @@ Block.Search.MovieItem = new Class({
self.mask = new Element('div.mask').inject(self.el).fade('hide');
createSpinner(self.mask);
self.mask.fade('in')
self.mask.fade('in');
},
toElement: function(){
return this.el
return this.el;
}
});

107
couchpotato/core/media/movie/_base/static/wanted.js

@ -1,4 +1,4 @@
Page.Wanted = new Class({
var MoviesWanted = new Class({
Extends: PageBase,
@ -10,7 +10,7 @@ Page.Wanted = new Class({
indexAction: function(){
var self = this;
if(!self.wanted){
if(!self.list){
self.manual_search = new Element('a', {
'title': 'Force a search for the full wanted list',
@ -20,25 +20,24 @@ Page.Wanted = new Class({
}
});
self.scan_folder = new Element('a', {
'title': 'Scan a folder and rename all movies in it',
'text': 'Manual folder scan',
'events':{
'click': self.scanFolder.bind(self)
}
});
self.scan_folder = new Element('a', {
'title': 'Scan a folder and rename all movies in it',
'text': 'Manual folder scan',
'events':{
'click': self.scanFolder.bind(self)
}
});
// Wanted movies
self.wanted = new MovieList({
self.list = new MovieList({
'identifier': 'wanted',
'status': 'active',
'actions': [MA.IMDB, MA.Trailer, MA.Release, MA.Edit, MA.Refresh, MA.Readd, MA.Delete],
'actions': [MA.IMDB, MA.Release, MA.Trailer, MA.Refresh, MA.Readd, MA.Delete, MA.Category, MA.Profile],
'add_new': true,
'menu': [self.manual_search, self.scan_folder],
'on_empty_element': App.createUserscriptButtons().addClass('empty_wanted')
});
$(self.wanted).inject(self.el);
$(self.list).inject(self.content);
// Check if search is in progress
self.startProgressInterval.delay(4000, self);
@ -82,43 +81,55 @@ Page.Wanted = new Class({
},
scanFolder: function(e) {
(e).stop();
var self = this;
var options = {
'name': 'Scan_folder'
};
scanFolder: function(e) {
(e).stop();
if(!self.folder_browser){
self.folder_browser = new Option['Directory']("Scan", "folder", "", options);
self.folder_browser.save = function() {
var folder = self.folder_browser.getValue();
Api.request('renamer.scan', {
'data': {
'base_folder': folder
var self = this;
var options = {
'name': 'Scan_folder'
};
if(!self.folder_browser){
self.folder_browser = new Option.Directory("Scan", "folder", "", options);
self.folder_browser.save = function() {
var folder = self.folder_browser.getValue();
Api.request('renamer.scan', {
'data': {
'base_folder': folder
}
});
};
self.folder_browser.inject(self.el, 'top');
self.folder_browser.fireEvent('injected');
// Hide the settings box
self.folder_browser.directory_inlay.hide();
self.folder_browser.el.removeChild(self.folder_browser.el.firstChild);
self.folder_browser.showBrowser();
// Make adjustments to the browser
self.folder_browser.browser.getElements('.clear.button').hide();
self.folder_browser.save_button.text = "Select";
self.folder_browser.browser.style.zIndex=1000;
}
else{
self.folder_browser.showBrowser();
}
}
};
self.folder_browser.inject(self.content, 'top');
self.folder_browser.fireEvent('injected');
// Hide the settings box
self.folder_browser.directory_inlay.hide();
self.folder_browser.el.removeChild(self.folder_browser.el.firstChild);
self.folder_browser.showBrowser();
// Make adjustments to the browser
self.folder_browser.browser.getElements('.clear.button').hide();
self.folder_browser.save_button.text = "Select";
self.folder_browser.browser.setStyles({
'z-index': 1000,
'right': 20,
'top': 0,
'margin': 0
});
self.folder_browser.pointer.setStyles({
'right': 20
});
}
else{
self.folder_browser.showBrowser();
}
self.list.navigation_menu.hide();
}
});

14
couchpotato/core/media/movie/charts/__init__.py

@ -21,20 +21,6 @@ config = [{
'type': 'int',
'description': 'Maximum number of items displayed from each chart.',
},
{
'name': 'hide_wanted',
'default': False,
'type': 'bool',
'advanced': True,
'description': 'Hide the chart movies that are already in your wanted list.',
},
{
'name': 'hide_library',
'default': False,
'type': 'bool',
'advanced': True,
'description': 'Hide the chart movies that are already in your library.',
},
],
},
],

101
couchpotato/core/media/movie/charts/main.py

@ -1,8 +1,10 @@
import time
from CodernityDB.database import RecordNotFound
from couchpotato import Env, get_db
from couchpotato.core.helpers.variable import getTitle, splitString
from couchpotato.core.logger import CPLog
from couchpotato.api import addApiView
from couchpotato.core.event import addEvent,fireEvent
from couchpotato.core.event import fireEvent
from couchpotato.core.plugins.base import Plugin
@ -11,51 +13,72 @@ log = CPLog(__name__)
class Charts(Plugin):
update_in_progress = False
update_interval = 72 # hours
def __init__(self):
addApiView('charts.view', self.automationView)
addEvent('app.load', self.setCrons)
def setCrons(self):
fireEvent('schedule.interval', 'charts.update_cache', self.updateViewCache, hours = self.update_interval)
addApiView('charts.ignore', self.ignoreView)
def automationView(self, force_update = False, **kwargs):
if force_update:
charts = self.updateViewCache()
else:
charts = self.getCache('charts_cached')
if not charts:
charts = self.updateViewCache()
db = get_db()
charts = fireEvent('automation.get_chart_list', merge = True)
ignored = splitString(Env.prop('charts_ignore', default = ''))
# Create a list the movie/list.js can use
for chart in charts:
medias = []
for media in chart.get('list', []):
identifier = media.get('imdb')
if identifier in ignored:
continue
try:
try:
in_library = db.get('media', 'imdb-%s' % identifier)
if in_library:
continue
except RecordNotFound:
pass
except:
pass
# Cache poster
posters = media.get('images', {}).get('poster', [])
poster = [x for x in posters if 'tmdb' in x]
posters = poster if len(poster) > 0 else posters
cached_poster = fireEvent('file.download', url = posters[0], single = True) if len(posters) > 0 else False
files = {'image_poster': [cached_poster] } if cached_poster else {}
medias.append({
'status': 'chart',
'title': getTitle(media),
'type': 'movie',
'info': media,
'files': files,
'identifiers': {
'imdb': identifier
}
})
chart['list'] = medias
return {
'success': True,
'count': len(charts),
'charts': charts
'charts': charts,
'ignored': ignored,
}
def updateViewCache(self):
if self.update_in_progress:
while self.update_in_progress:
time.sleep(1)
catched_charts = self.getCache('charts_cached')
if catched_charts:
return catched_charts
charts = []
try:
self.update_in_progress = True
charts = fireEvent('automation.get_chart_list', merge = True)
for chart in charts:
chart['hide_wanted'] = self.conf('hide_wanted')
chart['hide_library'] = self.conf('hide_library')
self.setCache('charts_cached', charts, timeout = self.update_interval * 3600)
except:
log.error('Failed refreshing charts')
self.update_in_progress = False
return charts
def ignoreView(self, imdb = None, **kwargs):
ignored = splitString(Env.prop('charts_ignore', default = ''))
if imdb:
ignored.append(imdb)
Env.prop('charts_ignore', ','.join(set(ignored)))
return {
'result': True
}

124
couchpotato/core/media/movie/charts/static/charts.js

@ -42,12 +42,7 @@ var Charts = new Class({
)
);
if( Cookie.read('suggestions_charts_menu_selected') === 'charts'){
self.show();
}
else
self.el.hide();
self.show();
self.fireEvent.delay(0, self, 'created');
},
@ -59,94 +54,39 @@ var Charts = new Class({
self.el_refreshing_text.hide();
self.el_refresh_link.show();
if(!json || json.count == 0){
if(!json || json.count === 0){
self.el_no_charts_enabled.show();
self.el_refresh_link.show();
self.el_refreshing_text.hide();
self.el_refresh_link.show();
self.el_refreshing_text.hide();
}
else {
self.el_no_charts_enabled.hide();
json.charts.sort(function(a, b) {
json.charts.sort(function(a, b) {
return a.order - b.order;
});
Object.each(json.charts, function(chart){
var c = new Element('div.chart.tiny_scroll').grab(
new Element('h3').grab( new Element('a', {
'text': chart.name,
'href': chart.url
}))
);
var it = 1;
Object.each(chart.list, function(movie){
var m = new Block.Search.MovieItem(movie, {
'onAdded': function(){
self.afterAdded(m, movie)
}
});
var in_database_class = (chart.hide_wanted && movie.in_wanted) ? 'hidden' : (movie.in_wanted ? 'chart_in_wanted' : ((chart.hide_library && movie.in_library) ? 'hidden': (movie.in_library ? 'chart_in_library' : ''))),
in_database_title = movie.in_wanted ? 'Movie in wanted list' : (movie.in_library ? 'Movie in library' : '');
m.el
.addClass(in_database_class)
.grab(
new Element('div.chart_number', {
'text': it++,
'title': in_database_title
})
);
m.data_container.grab(
new Element('div.actions').adopt(
new Element('a.add.icon2', {
'title': 'Add movie with your default quality',
'data-add': movie.imdb,
'events': {
'click': m.showOptions.bind(m)
}
}),
$(new MA.IMDB(m)),
$(new MA.Trailer(m, {
'height': 150
}))
)
);
m.data_container.removeEvents('click');
var plot = false;
if(m.info.plot && m.info.plot.length > 0)
plot = m.info.plot;
// Add rating
m.info_container.adopt(
m.rating = m.info.rating && m.info.rating.imdb && m.info.rating.imdb.length == 2 && parseFloat(m.info.rating.imdb[0]) > 0 ? new Element('span.rating', {
'text': parseFloat(m.info.rating.imdb[0]),
'title': parseInt(m.info.rating.imdb[1]) + ' votes'
}) : null,
m.genre = m.info.genres && m.info.genres.length > 0 ? new Element('span.genres', {
'text': m.info.genres.slice(0, 3).join(', ')
}) : null,
m.plot = plot ? new Element('span.plot', {
'text': plot,
'events': {
'click': function(){
this.toggleClass('full')
}
}
}) : null
);
$(m).inject(c);
var chart_list = new MovieList({
'navigation': false,
'identifier': chart.name.toLowerCase().replace(/[^a-z0-9]+/g, '_'),
'title': chart.name,
'description': '<a href="'+chart.url+'">See source</a>',
'actions': [MA.Add, MA.ChartIgnore, MA.IMDB, MA.Trailer],
'load_more': false,
'view': 'thumb',
'force_view': true,
'api_call': null
});
c.inject(self.el);
// Load movies in manually
chart_list.store(chart.list);
chart_list.addMovies(chart.list, chart.list.length);
chart_list.checkIfEmpty();
chart_list.fireEvent('loaded');
$(chart_list).inject(self.el);
});
@ -162,26 +102,16 @@ var Charts = new Class({
self.el.show();
if(!self.shown_once){
self.api_request = Api.request('charts.view', {
'onComplete': self.fill.bind(self)
});
setTimeout(function(){
self.api_request = Api.request('charts.view', {
'onComplete': self.fill.bind(self)
});
}, 100);
self.shown_once = true;
}
},
hide: function(){
this.el.hide();
},
afterAdded: function(m){
$(m).getElement('div.chart_number')
.addClass('chart_in_wanted')
.set('title', 'Movie in wanted list');
},
toElement: function(){
return this.el;
}

0
couchpotato/core/media/movie/charts/static/charts.css → couchpotato/core/media/movie/charts/static/charts.scss

58
couchpotato/core/media/movie/providers/automation/bluray.py

@ -105,41 +105,49 @@ class Bluray(Automation, RSS):
return movies
def getChartList(self):
# Nearly identical to 'getIMDBids', but we don't care about minimalMovie and return all movie data (not just id)
movie_list = {'name': 'Blu-ray.com - New Releases', 'url': self.display_url, 'order': self.chart_order, 'list': []}
movie_ids = []
max_items = int(self.conf('max_items', section='charts', default=5))
rss_movies = self.getRSSData(self.rss_url)
cache_key = 'bluray.charts'
movie_list = {
'name': 'Blu-ray.com - New Releases',
'url': self.display_url,
'order': self.chart_order,
'list': self.getCache(cache_key) or []
}
for movie in rss_movies:
name = self.getTextElement(movie, 'title').lower().split('blu-ray')[0].strip('(').rstrip()
year = self.getTextElement(movie, 'description').split('|')[1].strip('(').strip()
if not movie_list['list']:
movie_ids = []
max_items = int(self.conf('max_items', section='charts', default=5))
rss_movies = self.getRSSData(self.rss_url)
if not name.find('/') == -1: # make sure it is not a double movie release
continue
for movie in rss_movies:
name = self.getTextElement(movie, 'title').lower().split('blu-ray')[0].strip('(').rstrip()
year = self.getTextElement(movie, 'description').split('|')[1].strip('(').strip()
movie = self.search(name, year)
if not name.find('/') == -1: # make sure it is not a double movie release
continue
if movie:
movie = self.search(name, year)
if movie.get('imdb') in movie_ids:
continue
if movie:
is_movie = fireEvent('movie.is_movie', identifier = movie.get('imdb'), single = True)
if not is_movie:
continue
if movie.get('imdb') in movie_ids:
continue
movie_ids.append(movie.get('imdb'))
movie_list['list'].append( movie )
if len(movie_list['list']) >= max_items:
break
is_movie = fireEvent('movie.is_movie', identifier = movie.get('imdb'), single = True)
if not is_movie:
continue
if not movie_list['list']:
return
movie_ids.append(movie.get('imdb'))
movie_list['list'].append( movie )
if len(movie_list['list']) >= max_items:
break
if not movie_list['list']:
return
self.setCache(cache_key, movie_list['list'], timeout = 259200)
return [ movie_list ]
return [movie_list]
config = [{

68
couchpotato/core/media/movie/providers/automation/imdb.py

@ -19,7 +19,7 @@ autoload = 'IMDB'
class IMDB(MultiProvider):
def getTypes(self):
return [IMDBWatchlist, IMDBAutomation]
return [IMDBWatchlist, IMDBAutomation, IMDBCharts]
class IMDBBase(Automation, RSS):
@ -126,30 +126,6 @@ class IMDBAutomation(IMDBBase):
enabled_option = 'automation_providers_enabled'
charts = {
'theater': {
'order': 1,
'name': 'IMDB - Movies in Theaters',
'url': 'http://www.imdb.com/movies-in-theaters/',
},
'boxoffice': {
'order': 2,
'name': 'IMDB - Box Office',
'url': 'http://www.imdb.com/boxoffice/',
},
'rentals': {
'order': 3,
'name': 'IMDB - Top DVD rentals',
'url': 'http://www.imdb.com/boxoffice/rentals',
'type': 'json',
},
'top250': {
'order': 4,
'name': 'IMDB - Top 250 Movies',
'url': 'http://www.imdb.com/chart/top',
},
}
def getIMDBids(self):
movies = []
@ -175,20 +151,53 @@ class IMDBAutomation(IMDBBase):
return movies
def getChartList(self):
class IMDBCharts(IMDBBase):
charts = {
'theater': {
'order': 1,
'name': 'IMDB - Movies in Theaters',
'url': 'http://www.imdb.com/movies-in-theaters/',
},
'boxoffice': {
'order': 2,
'name': 'IMDB - Box Office',
'url': 'http://www.imdb.com/boxoffice/',
},
'rentals': {
'order': 3,
'name': 'IMDB - Top DVD rentals',
'url': 'http://www.imdb.com/boxoffice/rentals',
'type': 'json',
},
'top250': {
'order': 4,
'name': 'IMDB - Top 250 Movies',
'url': 'http://www.imdb.com/chart/top',
},
}
def getChartList(self):
# Nearly identical to 'getIMDBids', but we don't care about minimalMovie and return all movie data (not just id)
movie_lists = []
max_items = int(self.conf('max_items', section = 'charts', default=5))
for name in self.charts:
chart = self.charts[name].copy()
url = chart.get('url')
cache_key = 'imdb.chart_display_%s' % name
if self.conf('chart_display_%s' % name):
chart['list'] = []
cached = self.getCache(cache_key)
if cached:
chart['list'] = cached
movie_lists.append(chart)
continue
url = chart.get('url')
chart['list'] = []
imdb_ids = self.getFromURL(url)
try:
@ -206,10 +215,11 @@ class IMDBAutomation(IMDBBase):
except:
log.error('Failed loading IMDB chart results from %s: %s', (url, traceback.format_exc()))
self.setCache(cache_key, chart['list'], timeout = 259200)
if chart['list']:
movie_lists.append(chart)
return movie_lists

11
couchpotato/core/media/movie/providers/automation/popularmovies.py

@ -17,11 +17,12 @@ class PopularMovies(Automation):
movies = []
retrieved_movies = self.getJsonData(self.url)
for movie in retrieved_movies.get('movies'):
imdb_id = movie.get('imdb_id')
info = fireEvent('movie.info', identifier = imdb_id, extended = False, merge = True)
if self.isMinimalMovie(info):
movies.append(imdb_id)
if retrieved_movies:
for movie in retrieved_movies.get('movies'):
imdb_id = movie.get('imdb_id')
info = fireEvent('movie.info', identifier = imdb_id, extended = False, merge = True)
if self.isMinimalMovie(info):
movies.append(imdb_id)
return movies

95
couchpotato/core/media/movie/providers/automation/rottentomatoes.py

@ -1,95 +0,0 @@
from xml.etree.ElementTree import QName
import datetime
import re
from couchpotato.core.helpers.rss import RSS
from couchpotato.core.helpers.variable import tryInt, splitString
from couchpotato.core.logger import CPLog
from couchpotato.core.media.movie.providers.automation.base import Automation
log = CPLog(__name__)
autoload = 'Rottentomatoes'
class Rottentomatoes(Automation, RSS):
interval = 1800
def getIMDBids(self):
movies = []
rotten_tomatoes_namespace = 'http://www.rottentomatoes.com/xmlns/rtmovie/'
urls = dict(zip(splitString(self.conf('automation_urls')), [tryInt(x) for x in splitString(self.conf('automation_urls_use'))]))
for url in urls:
if not urls[url]:
continue
rss_movies = self.getRSSData(url)
rating_tag = str(QName(rotten_tomatoes_namespace, 'tomatometer_percent'))
for movie in rss_movies:
value = self.getTextElement(movie, "title")
result = re.search('(?<=%\s).*', value)
if result:
rating = tryInt(self.getTextElement(movie, rating_tag))
name = result.group(0)
print rating, tryInt(self.conf('tomatometer_percent'))
if rating < tryInt(self.conf('tomatometer_percent')):
log.info2('%s seems to be rotten...', name)
else:
log.info2('Found %s with fresh rating %s', (name, rating))
year = datetime.datetime.now().strftime("%Y")
imdb = self.search(name, year)
if imdb and self.isMinimalMovie(imdb):
movies.append(imdb['imdb'])
return movies
config = [{
'name': 'rottentomatoes',
'groups': [
{
'tab': 'automation',
'list': 'automation_providers',
'name': 'rottentomatoes_automation',
'label': 'Rottentomatoes',
'description': 'Imports movies from rottentomatoes rss feeds specified below.',
'options': [
{
'name': 'automation_enabled',
'default': False,
'type': 'enabler',
},
{
'name': 'automation_urls_use',
'label': 'Use',
'default': '1',
},
{
'name': 'automation_urls',
'label': 'url',
'type': 'combined',
'combine': ['automation_urls_use', 'automation_urls'],
'default': 'http://www.rottentomatoes.com/syndication/rss/in_theaters.xml',
},
{
'name': 'tomatometer_percent',
'default': '80',
'label': 'Tomatometer',
'description': 'Use as extra scoring requirement',
},
],
},
],
}]

4
couchpotato/core/media/movie/providers/automation/trakt/static/trakt.js

@ -17,7 +17,7 @@ var TraktAutomation = new Class({
var trakt_set = 0;
fieldset.getElements('input[type=text]').each(function(el){
trakt_set += +(el.get('value') != '');
trakt_set += +(el.get('value') !== '');
});
new Element('.ctrlHolder').adopt(
@ -58,7 +58,7 @@ var TraktAutomation = new Class({
})
).inject(fieldset);
})
});
}

2
couchpotato/core/media/movie/providers/info/themoviedb.py

@ -197,7 +197,7 @@ class TheMovieDb(MovieProvider):
params = tryUrlencode(params)
try:
url = 'http://api.themoviedb.org/3/%s?api_key=%s%s' % (call, self.conf('api_key'), '&%s' % params if params else '')
url = 'https://api.themoviedb.org/3/%s?api_key=%s%s' % (call, self.conf('api_key'), '&%s' % params if params else '')
data = self.getJsonData(url, show_error = False)
except:
log.debug('Movie not found: %s, %s', (call, params))

11
couchpotato/core/media/movie/providers/torrent/hd4free.py

@ -0,0 +1,11 @@
from couchpotato.core.logger import CPLog
from couchpotato.core.media._base.providers.torrent.hd4free import Base
from couchpotato.core.media.movie.providers.base import MovieProvider
log = CPLog(__name__)
autoload = 'HD4Free'
class HD4Free(MovieProvider, Base):
pass

55
couchpotato/core/media/movie/suggestion/main.py → couchpotato/core/media/movie/suggestion.py

@ -1,6 +1,7 @@
import time
from couchpotato.api import addApiView
from couchpotato.core.event import fireEvent
from couchpotato.core.helpers.variable import splitString, removeDuplicate, getIdentifier
from couchpotato.core.event import fireEvent, addEvent
from couchpotato.core.helpers.variable import splitString, removeDuplicate, getIdentifier, getTitle
from couchpotato.core.plugins.base import Plugin
from couchpotato.environment import Env
@ -15,6 +16,12 @@ class Suggestion(Plugin):
addApiView('suggestion.view', self.suggestView)
addApiView('suggestion.ignore', self.ignoreView)
def test():
time.sleep(1)
self.suggestView()
addEvent('app.load', test)
def suggestView(self, limit = 6, **kwargs):
movies = splitString(kwargs.get('movies', ''))
@ -38,10 +45,31 @@ class Suggestion(Plugin):
suggestions = fireEvent('movie.suggest', movies = movies, ignore = ignored, single = True)
self.setCache('suggestion_cached', suggestions, timeout = 6048000) # Cache for 10 weeks
medias = []
for suggestion in suggestions[:int(limit)]:
# Cache poster
posters = suggestion.get('images', {}).get('poster', [])
poster = [x for x in posters if 'tmdb' in x]
posters = poster if len(poster) > 0 else posters
cached_poster = fireEvent('file.download', url = posters[0], single = True) if len(posters) > 0 else False
files = {'image_poster': [cached_poster] } if cached_poster else {}
medias.append({
'status': 'suggested',
'title': getTitle(suggestion),
'type': 'movie',
'info': suggestion,
'files': files,
'identifiers': {
'imdb': suggestion.get('imdb')
}
})
return {
'success': True,
'count': len(suggestions),
'suggestions': suggestions[:int(limit)]
'movies': medias
}
def ignoreView(self, imdb = None, limit = 6, remove_only = False, mark_seen = False, **kwargs):
@ -60,10 +88,25 @@ class Suggestion(Plugin):
new_suggestions = self.updateSuggestionCache(ignore_imdb = imdb, limit = limit, ignored = ignored, seen = seen)
if len(new_suggestions) <= limit:
return {
'result': False
}
# Only return new (last) item
media = {
'status': 'suggested',
'title': getTitle(new_suggestions[limit]),
'type': 'movie',
'info': new_suggestions[limit],
'identifiers': {
'imdb': new_suggestions[limit].get('imdb')
}
}
return {
'result': True,
'ignore_count': len(ignored),
'suggestions': new_suggestions[limit - 1:limit]
'movie': media
}
def updateSuggestionCache(self, ignore_imdb = None, limit = 6, ignored = None, seen = None):

0
couchpotato/core/media/movie/suggestion/__init__.py

162
couchpotato/core/media/movie/suggestion/static/suggest.css

@ -1,162 +0,0 @@
.suggestions {
clear: both;
padding-top: 10px;
margin-bottom: 30px;
}
.suggestions > h2 {
height: 40px;
}
.suggestions .media_result {
display: inline-block;
width: 33.333%;
height: 150px;
}
@media all and (max-width: 960px) {
.suggestions .media_result {
width: 50%;
}
}
@media all and (max-width: 600px) {
.suggestions .media_result {
width: 100%;
}
}
.suggestions .media_result .data {
left: 100px;
background: #4e5969;
border: none;
}
.suggestions .media_result .data .info {
top: 10px;
left: 15px;
right: 15px;
bottom: 10px;
overflow: hidden;
}
.suggestions .media_result .data .info h2 {
white-space: normal;
max-height: 120px;
font-size: 18px;
line-height: 18px;
}
.suggestions .media_result .data .info .rating,
.suggestions .media_result .data .info .genres,
.suggestions .media_result .data .info .year {
position: static;
display: block;
padding: 0;
opacity: .6;
}
.suggestions .media_result .data .info .year {
margin: 10px 0 0;
}
.suggestions .media_result .data .info .rating {
font-size: 20px;
float: right;
margin-top: -20px;
}
.suggestions .media_result .data .info .rating:before {
content: "\e031";
font-family: 'Elusive-Icons';
font-size: 14px;
margin: 0 5px 0 0;
vertical-align: bottom;
}
.suggestions .media_result .data .info .genres {
font-size: 11px;
font-style: italic;
text-align: right;
}
.suggestions .media_result .data .info .plot {
display: block;
font-size: 11px;
overflow: hidden;
text-align: justify;
height: 100%;
z-index: 2;
top: 64px;
position: absolute;
background: #4e5969;
cursor: pointer;
transition: all .4s ease-in-out;
padding: 0 3px 10px 0;
}
.suggestions .media_result .data:before {
content: '';
display: block;
height: 10px;
right: 0;
left: 0;
bottom: 10px;
position: absolute;
background: linear-gradient(
0deg,
rgba(78, 89, 105, 1) 0%,
rgba(78, 89, 105, 0) 100%
);
z-index: 3;
pointer-events: none;
}
.suggestions .media_result .data .info .plot.full {
top: 0;
overflow: auto;
}
.suggestions .media_result .data {
cursor: default;
}
.suggestions .media_result .options {
left: 100px;
}
.suggestions .media_result .options select[name=title] { width: 100%; }
.suggestions .media_result .options select[name=profile] { width: 100%; }
.suggestions .media_result .options select[name=category] { width: 100%; }
.suggestions .media_result .button {
position: absolute;
margin: 2px 0 0 0;
right: 15px;
bottom: 15px;
}
.suggestions .media_result .thumbnail {
width: 100px;
}
.suggestions .media_result .actions {
position: absolute;
top: 10px;
right: 10px;
display: none;
width: 140px;
}
.suggestions .media_result:hover .actions {
display: block;
}
.suggestions .media_result:hover h2 .title {
opacity: 0;
}
.suggestions .media_result .data.open .actions {
display: none;
}
.suggestions .media_result .actions a {
margin-left: 10px;
vertical-align: middle;
}

173
couchpotato/core/media/movie/suggestion/static/suggest.js

@ -1,173 +0,0 @@
var SuggestList = new Class({
Implements: [Options, Events],
shown_once: false,
initialize: function(options){
var self = this;
self.setOptions(options);
self.create();
},
create: function(){
var self = this;
self.el = new Element('div.suggestions', {
'events': {
'click:relay(a.delete)': function(e, el){
(e).stop();
$(el).getParent('.media_result').destroy();
Api.request('suggestion.ignore', {
'data': {
'imdb': el.get('data-ignore')
},
'onComplete': self.fill.bind(self)
});
},
'click:relay(a.eye-open)': function(e, el){
(e).stop();
$(el).getParent('.media_result').destroy();
Api.request('suggestion.ignore', {
'data': {
'imdb': el.get('data-seen'),
'mark_seen': 1
},
'onComplete': self.fill.bind(self)
});
}
}
});
var cookie_menu_select = Cookie.read('suggestions_charts_menu_selected') || 'suggestions';
if( cookie_menu_select === 'suggestions')
self.show();
else
self.hide();
self.fireEvent.delay(0, self, 'created');
},
fill: function(json){
var self = this;
if(!json || json.count == 0){
self.el.hide();
}
else {
Object.each(json.suggestions, function(movie){
var m = new Block.Search.MovieItem(movie, {
'onAdded': function(){
self.afterAdded(m, movie)
}
});
m.data_container.grab(
new Element('div.actions').adopt(
new Element('a.add.icon2', {
'title': 'Add movie with your default quality',
'data-add': movie.imdb,
'events': {
'click': m.showOptions.bind(m)
}
}),
$(new MA.IMDB(m)),
$(new MA.Trailer(m, {
'height': 150
})),
new Element('a.delete.icon2', {
'title': 'Don\'t suggest this movie again',
'data-ignore': movie.imdb
}),
new Element('a.eye-open.icon2', {
'title': 'Seen it, like it, don\'t add',
'data-seen': movie.imdb
})
)
);
m.data_container.removeEvents('click');
var plot = false;
if(m.info.plot && m.info.plot.length > 0)
plot = m.info.plot;
// Add rating
m.info_container.adopt(
m.rating = m.info.rating && m.info.rating.imdb && m.info.rating.imdb.length == 2 && parseFloat(m.info.rating.imdb[0]) > 0 ? new Element('span.rating', {
'text': parseFloat(m.info.rating.imdb[0]),
'title': parseInt(m.info.rating.imdb[1]) + ' votes'
}) : null,
m.genre = m.info.genres && m.info.genres.length > 0 ? new Element('span.genres', {
'text': m.info.genres.slice(0, 3).join(', ')
}) : null,
m.plot = plot ? new Element('span.plot', {
'text': plot,
'events': {
'click': function(){
this.toggleClass('full')
}
}
}) : null
);
$(m).inject(self.el);
});
}
self.fireEvent('loaded');
},
afterAdded: function(m, movie){
var self = this;
setTimeout(function(){
$(m).destroy();
Api.request('suggestion.ignore', {
'data': {
'imdb': movie.imdb,
'remove_only': true
},
'onComplete': self.fill.bind(self)
});
}, 3000);
},
show: function(){
var self = this;
self.el.show();
if(!self.shown_once){
self.api_request = Api.request('suggestion.view', {
'onComplete': self.fill.bind(self)
});
self.shown_once = true;
}
},
hide: function(){
this.el.hide();
},
toElement: function(){
return this.el;
}
});

78
couchpotato/core/notifications/core/static/notification.js

@ -20,8 +20,8 @@ var NotificationBase = new Class({
self.notifications = [];
App.addEvent('load', function(){
App.block.notification = new Block.Menu(self, {
'button_class': 'icon2.eye-open',
App.block.notification = new BlockMenu(self, {
'button_class': 'icon-notifications',
'class': 'notification_menu',
'onOpen': self.markAsRead.bind(self)
});
@ -32,7 +32,7 @@ var NotificationBase = new Class({
window.addEvent('load', function(){
self.startInterval.delay($(window).getSize().x <= 480 ? 2000 : 100, self);
})
});
},
@ -46,16 +46,15 @@ var NotificationBase = new Class({
new Element('span.'+(result.read ? 'read' : '' )).adopt(
new Element('span.message', {'html': result.message}),
new Element('span.added', {'text': added.timeDiffInWords(), 'title': added})
)
, 'top');
), 'top');
self.notifications.include(result);
if((result.important !== undefined || result.sticky !== undefined) && !result.read){
var sticky = true;
App.trigger('message', [result.message, sticky, result])
App.trigger('message', [result.message, sticky, result]);
}
else if(!result.read){
self.setBadge(self.notifications.filter(function(n){ return !n.read}).length)
self.setBadge(self.notifications.filter(function(n){ return !n.read; }).length);
}
},
@ -63,7 +62,7 @@ var NotificationBase = new Class({
setBadge: function(value){
var self = this;
self.badge.set('text', value);
self.badge[value ? 'show' : 'hide']()
self.badge[value ? 'show' : 'hide']();
},
markAsRead: function(force_ids){
@ -72,13 +71,13 @@ var NotificationBase = new Class({
if(!force_ids) {
var rn = self.notifications.filter(function(n){
return !n.read && n.important === undefined
return !n.read && n.important === undefined;
});
var ids = [];
ids = [];
rn.each(function(n){
ids.include(n._id)
})
ids.include(n._id);
});
}
if(ids.length > 0)
@ -87,9 +86,9 @@ var NotificationBase = new Class({
'ids': ids.join(',')
},
'onSuccess': function(){
self.setBadge('')
self.setBadge('');
}
})
});
},
@ -102,9 +101,9 @@ var NotificationBase = new Class({
}
self.request = Api.request('notification.listener', {
'data': {'init':true},
'onSuccess': function(json){
self.processData(json, true)
'data': {'init':true},
'onSuccess': function(json){
self.processData(json, true);
}
}).send();
@ -112,7 +111,7 @@ var NotificationBase = new Class({
if(self.request && self.request.isRunning()){
self.request.cancel();
self.startPoll()
self.startPoll();
}
}, 120000);
@ -129,16 +128,16 @@ var NotificationBase = new Class({
self.request.cancel();
self.request = Api.request('nonblock/notification.listener', {
'onSuccess': function(json){
self.processData(json, false)
'onSuccess': function(json){
self.processData(json, false);
},
'data': {
'last_id': self.last_id
},
'onFailure': function(){
self.startPoll.delay(2000, self)
}
}).send()
'data': {
'last_id': self.last_id
},
'onFailure': function(){
self.startPoll.delay(2000, self);
}
}).send();
},
@ -160,7 +159,7 @@ var NotificationBase = new Class({
});
if(json.result.length > 0)
self.last_id = json.result.getLast().message_id
self.last_id = json.result.getLast().message_id;
}
// Restart poll
@ -175,11 +174,11 @@ var NotificationBase = new Class({
var new_message = new Element('div', {
'class': 'message' + (sticky ? ' sticky' : ''),
'html': message
'html': '<div class="inner">' + message + '</div>'
}).inject(self.message_container, 'top');
setTimeout(function(){
new_message.addClass('show')
new_message.addClass('show');
}, 10);
var hide_message = function(){
@ -211,8 +210,8 @@ var NotificationBase = new Class({
var setting_page = App.getPage('Settings');
setting_page.addEvent('create', function(){
Object.each(setting_page.tabs.notifications.groups, self.addTestButton.bind(self))
})
Object.each(setting_page.tabs.notifications.groups, self.addTestButton.bind(self));
});
},
@ -222,7 +221,7 @@ var NotificationBase = new Class({
if(button_name.contains('Notifications')) return;
new Element('.ctrlHolder.test_button').adopt(
new Element('.ctrlHolder.test_button').grab(
new Element('a.button', {
'text': button_name,
'events': {
@ -235,20 +234,21 @@ var NotificationBase = new Class({
button.set('text', button_name);
var message;
if(json.success){
var message = new Element('span.success', {
message = new Element('span.success', {
'text': 'Notification successful'
}).inject(button, 'after')
}).inject(button, 'after');
}
else {
var message = new Element('span.failed', {
message = new Element('span.failed', {
'text': 'Notification failed. Check logs for details.'
}).inject(button, 'after')
}).inject(button, 'after');
}
(function(){
message.destroy();
}).delay(3000)
}).delay(3000);
}
});
}
@ -258,7 +258,7 @@ var NotificationBase = new Class({
},
testButtonName: function(fieldset){
var name = String(fieldset.getElement('h2').innerHTML).substring(0,String(fieldset.getElement('h2').innerHTML).indexOf("<span")); //.get('text');
var name = fieldset.getElement('h2 .group_label').get('text');
return 'Test '+name;
}

4
couchpotato/core/notifications/twitter/static/twitter.js

@ -16,7 +16,7 @@ var TwitterNotification = new Class({
var twitter_set = 0;
fieldset.getElements('input[type=text]').each(function(el){
twitter_set += +(el.get('value') != '');
twitter_set += +(el.get('value') !== '');
});
@ -57,7 +57,7 @@ var TwitterNotification = new Class({
}
})
).inject(fieldset.getElement('.test_button'), 'before');
})
});
}

28
couchpotato/core/notifications/xbmc.py

@ -83,7 +83,7 @@ class XBMC(Notification):
# v6 (as of XBMC v12(Frodo)) is required to send notifications
xbmc_rpc_version = str(result['result']['version'])
log.debug('XBMC JSON-RPC Version: %s ; Notifications by JSON-RPC only supported for v6 [as of XBMC v12(Frodo)]', xbmc_rpc_version)
log.debug('Kodi JSON-RPC Version: %s ; Notifications by JSON-RPC only supported for v6 [as of XBMC v12(Frodo)]', xbmc_rpc_version)
# disable JSON use
self.use_json_notifications[host] = False
@ -96,7 +96,7 @@ class XBMC(Notification):
success = True
break
elif r.get('error'):
log.error('XBMC error; %s: %s (%s)', (r['id'], r['error']['message'], r['error']['code']))
log.error('Kodi error; %s: %s (%s)', (r['id'], r['error']['message'], r['error']['code']))
break
elif result.get('result') and type(result['result']['version']).__name__ == 'dict':
@ -106,7 +106,7 @@ class XBMC(Notification):
xbmc_rpc_version += '.' + str(result['result']['version']['minor'])
xbmc_rpc_version += '.' + str(result['result']['version']['patch'])
log.debug('XBMC JSON-RPC Version: %s', xbmc_rpc_version)
log.debug('Kodie JSON-RPC Version: %s', xbmc_rpc_version)
# ok, XBMC version is supported
self.use_json_notifications[host] = True
@ -119,12 +119,12 @@ class XBMC(Notification):
success = True
break
elif r.get('error'):
log.error('XBMC error; %s: %s (%s)', (r['id'], r['error']['message'], r['error']['code']))
log.error('Kodi error; %s: %s (%s)', (r['id'], r['error']['message'], r['error']['code']))
break
# error getting version info (we do have contact with XBMC though)
elif result.get('error'):
log.error('XBMC error; %s: %s (%s)', (result['id'], result['error']['message'], result['error']['code']))
log.error('Kodi error; %s: %s (%s)', (result['id'], result['error']['message'], result['error']['code']))
log.debug('Use JSON notifications: %s ', self.use_json_notifications)
@ -173,10 +173,10 @@ class XBMC(Notification):
return [{'result': 'Error'}]
except (MaxRetryError, Timeout, ConnectionError):
log.info2('Couldn\'t send request to XBMC, assuming it\'s turned off')
log.info2('Couldn\'t send request to Kodi, assuming it\'s turned off')
return [{'result': 'Error'}]
except:
log.error('Failed sending non-JSON-type request to XBMC: %s', traceback.format_exc())
log.error('Failed sending non-JSON-type request to Kodi: %s', traceback.format_exc())
return [{'result': 'Error'}]
def request(self, host, do_requests):
@ -209,10 +209,10 @@ class XBMC(Notification):
return response
except (MaxRetryError, Timeout, ConnectionError):
log.info2('Couldn\'t send request to XBMC, assuming it\'s turned off')
log.info2('Couldn\'t send request to Kodi, assuming it\'s turned off')
return []
except:
log.error('Failed sending request to XBMC: %s', traceback.format_exc())
log.error('Failed sending request to Kodi: %s', traceback.format_exc())
return []
@ -223,8 +223,8 @@ config = [{
'tab': 'notifications',
'list': 'notification_providers',
'name': 'xbmc',
'label': 'XBMC',
'description': 'v11 (Eden), v12 (Frodo), v13 (Gotham)',
'label': 'Kodi',
'description': 'v14 (Helix), v15 (Isengard)',
'options': [
{
'name': 'enabled',
@ -249,7 +249,7 @@ config = [{
'default': 0,
'type': 'bool',
'advanced': True,
'description': 'Only update the first host when movie snatched, useful for synced XBMC',
'description': 'Only update the first host when movie snatched, useful for synced Kodi',
},
{
'name': 'remote_dir_scan',
@ -257,7 +257,7 @@ config = [{
'default': 0,
'type': 'bool',
'advanced': True,
'description': ('Only scan new movie folder at remote XBMC servers.', 'Useful if the XBMC path is different from the path CPS uses.'),
'description': ('Only scan new movie folder at remote Kodi servers.', 'Useful if the Kodi path is different from the path CPS uses.'),
},
{
'name': 'force_full_scan',
@ -265,7 +265,7 @@ config = [{
'default': 0,
'type': 'bool',
'advanced': True,
'description': ('Do a full scan instead of only the new movie.', 'Useful if the XBMC path is different from the path CPS uses.'),
'description': ('Do a full scan instead of only the new movie.', 'Useful if the Kodi path is different from the path CPS uses.'),
},
{
'name': 'on_snatch',

37
couchpotato/core/plugins/base.py

@ -1,17 +1,14 @@
import threading
from urllib import quote, getproxies
from urlparse import urlparse
import glob
import inspect
import os.path
import re
import time
import traceback
from couchpotato.core.event import fireEvent, addEvent
from couchpotato.core.helpers.encoding import ss, toSafeString, \
toUnicode, sp
from couchpotato.core.helpers.variable import getExt, md5, isLocalIP, scanForPassword, tryInt, getIdentifier, \
from couchpotato.core.helpers.variable import md5, isLocalIP, scanForPassword, tryInt, getIdentifier, \
randomString
from couchpotato.core.logger import CPLog
from couchpotato.environment import Env
@ -19,8 +16,6 @@ import requests
from requests.packages.urllib3 import Timeout
from requests.packages.urllib3.exceptions import MaxRetryError
from tornado import template
from tornado.web import StaticFileHandler
log = CPLog(__name__)
@ -32,7 +27,6 @@ class Plugin(object):
plugin_path = None
enabled_option = 'enabled'
auto_register_static = True
_needs_shutdown = False
_running = None
@ -57,9 +51,6 @@ class Plugin(object):
addEvent('plugin.running', self.isRunning)
self._running = []
if self.auto_register_static:
self.registerStatic(inspect.getfile(self.__class__))
# Setup database
if self._database:
addEvent('database.setup', self.databaseSetup)
@ -89,32 +80,6 @@ class Plugin(object):
t = template.Template(open(os.path.join(os.path.dirname(parent_file), templ), 'r').read())
return t.generate(**params)
def registerStatic(self, plugin_file, add_to_head = True):
# Register plugin path
self.plugin_path = os.path.dirname(plugin_file)
static_folder = toUnicode(os.path.join(self.plugin_path, 'static'))
if not os.path.isdir(static_folder):
return
# Get plugin_name from PluginName
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', self.__class__.__name__)
class_name = re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
# View path
path = 'static/plugin/%s/' % class_name
# Add handler to Tornado
Env.get('app').add_handlers(".*$", [(Env.get('web_base') + path + '(.*)', StaticFileHandler, {'path': static_folder})])
# Register for HTML <HEAD>
if add_to_head:
for f in glob.glob(os.path.join(self.plugin_path, 'static', '*')):
ext = getExt(f)
if ext in ['js', 'css']:
fireEvent('register_%s' % ('script' if ext in 'js' else 'style'), path + os.path.basename(f), f)
def createFile(self, path, content, binary = False):
path = sp(path)

34
couchpotato/core/plugins/category/static/category.js

@ -52,7 +52,7 @@ var CategoryListBase = new Class({
});
})
});
},
@ -71,7 +71,7 @@ var CategoryListBase = new Class({
'events': {
'click': function(){
var category = self.createCategory();
$(category).inject(self.category_container)
$(category).inject(self.category_container);
}
}
})
@ -79,15 +79,15 @@ var CategoryListBase = new Class({
// Add categories, that aren't part of the core (for editing)
Array.each(self.categories, function(category){
$(category).inject(self.category_container)
$(category).inject(self.category_container);
});
},
getCategory: function(id){
return this.categories.filter(function(category){
return category.data._id == id
}).pick()
return category.data._id == id;
}).pick();
},
getAll: function(){
@ -97,7 +97,7 @@ var CategoryListBase = new Class({
createCategory: function(data){
var self = this;
var data = data || {'id': randomString()};
data = data || {'id': randomString()};
var category = new Category(data);
self.categories.include(category);
@ -125,7 +125,7 @@ var CategoryListBase = new Class({
new Element('span.category_label', {
'text': category.data.label
}),
new Element('span.handle')
new Element('span.handle.icon-handle')
).inject(category_list);
});
@ -192,7 +192,7 @@ var Category = new Class({
}),
new Element('.category_label.ctrlHolder').adopt(
new Element('label', {'text':'Name'}),
new Element('input.inlay', {
new Element('input', {
'type':'text',
'value': data.label,
'placeholder': 'Example: Kids, Horror or His'
@ -201,7 +201,7 @@ var Category = new Class({
),
new Element('.category_preferred.ctrlHolder').adopt(
new Element('label', {'text':'Preferred'}),
new Element('input.inlay', {
new Element('input', {
'type':'text',
'value': data.preferred,
'placeholder': 'Blu-ray, DTS'
@ -209,7 +209,7 @@ var Category = new Class({
),
new Element('.category_required.ctrlHolder').adopt(
new Element('label', {'text':'Required'}),
new Element('input.inlay', {
new Element('input', {
'type':'text',
'value': data.required,
'placeholder': 'Example: DTS, AC3 & English'
@ -217,7 +217,7 @@ var Category = new Class({
),
new Element('.category_ignored.ctrlHolder').adopt(
new Element('label', {'text':'Ignored'}),
new Element('input.inlay', {
new Element('input', {
'type':'text',
'value': data.ignored,
'placeholder': 'Example: dubbed, swesub, french'
@ -225,7 +225,7 @@ var Category = new Class({
)
);
self.makeSortable()
self.makeSortable();
},
@ -248,7 +248,7 @@ var Category = new Class({
}
});
}).delay(delay || 0, self)
}).delay(delay || 0, self);
},
@ -262,13 +262,13 @@ var Category = new Class({
'preferred' : self.el.getElement('.category_preferred input').get('value'),
'ignored' : self.el.getElement('.category_ignored input').get('value'),
'destination': self.data.destination
}
};
},
del: function(){
var self = this;
if(self.data.label == undefined){
if(self.data.label === undefined){
self.el.destroy();
return;
}
@ -318,11 +318,11 @@ var Category = new Class({
},
get: function(attr){
return this.data[attr]
return this.data[attr];
},
toElement: function(){
return this.el
return this.el;
}
});

19
couchpotato/core/plugins/category/static/category.css → couchpotato/core/plugins/category/static/category.scss

@ -1,13 +1,14 @@
@import "_mixins";
.add_new_category {
padding: 20px;
display: block;
text-align: center;
font-size: 20px;
border-bottom: 1px solid rgba(255,255,255,0.2);
}
.category {
border-bottom: 1px solid rgba(255,255,255,0.2);
margin-bottom: 20px;
position: relative;
}
@ -28,8 +29,6 @@
}
.category .formHint {
width: 250px !important;
margin: 0 !important;
opacity: 0.1;
}
.category:hover .formHint {
@ -48,11 +47,10 @@
}
#category_ordering li {
cursor: -webkit-grab;
cursor: -moz-grab;
cursor: grab;
border-bottom: 1px solid rgba(255,255,255,0.2);
padding: 0 5px;
border-bottom: 1px solid $theme_off;
padding: 5px;
list-style: none;
}
#category_ordering li:last-child { border: 0; }
@ -69,14 +67,9 @@
}
#category_ordering li .handle {
background: url('../../images/handle.png') center;
width: 20px;
float: right;
}
#category_ordering .formHint {
clear: none;
float: right;
width: 250px;
margin: 0;
}

4
couchpotato/core/plugins/dashboard.py

@ -64,7 +64,7 @@ class Dashboard(Plugin):
except RecordDeleted:
log.debug('Record already deleted: %s', media_id)
continue
except RecordNotFound:
log.debug('Record not found: %s', media_id)
continue
@ -96,7 +96,7 @@ class Dashboard(Plugin):
if late:
media['releases'] = fireEvent('release.for_media', media['_id'], single = True)
for release in media.get('releases'):
for release in media.get('releases', []):
if release.get('status') in ['snatched', 'available', 'seeding', 'downloaded']:
add = False
break

7
couchpotato/core/plugins/log/main.py

@ -131,12 +131,13 @@ class Logging(Plugin):
def toList(self, log_content = ''):
logs_raw = toUnicode(log_content).split('[0m\n')
logs_raw = re.split(r'\[0m\n', toUnicode(log_content))
logs = []
re_split = r'\x1b'
for log_line in logs_raw:
split = splitString(log_line, '\x1b')
if split:
split = re.split(re_split, log_line)
if split and len(split) == 3:
try:
date, time, log_type = splitString(split[0], ' ')
timestamp = '%s %s' % (date, time)

199
couchpotato/core/plugins/log/static/log.css

@ -1,199 +0,0 @@
.page.log .nav {
display: block;
text-align: center;
padding: 0 0 30px;
margin: 0;
font-size: 20px;
position: fixed;
width: 100%;
bottom: 0;
left: 0;
background: #4E5969;
z-index: 100;
}
.page.log .nav li {
display: inline-block;
padding: 5px 10px;
margin: 0;
}
.page.log .nav li.select,
.page.log .nav li.clear {
cursor: pointer;
}
.page.log .nav li:hover:not(.active):not(.filter) {
background: rgba(255, 255, 255, 0.1);
}
.page.log .nav li.active {
font-weight: bold;
cursor: default;
background: rgba(255,255,255,.1);
}
@media all and (max-width: 480px) {
.page.log .nav {
font-size: 14px;
}
.page.log .nav li {
padding: 5px;
}
}
.page.log .nav li.hint {
text-align: center;
width: 400px;
left: 50%;
margin-left: -200px;
font-style: italic;
font-size: 11px;
position: absolute;
right: 20px;
opacity: .5;
bottom: 5px;
}
.page.log .loading {
text-align: center;
font-size: 20px;
padding: 50px;
}
.page.log .container {
padding: 30px 0 60px;
overflow: hidden;
line-height: 150%;
font-size: 11px;
color: #FFF;
}
.page.log .container select {
vertical-align: top;
}
.page.log .container .time {
clear: both;
color: lightgrey;
font-size: 10px;
border-top: 1px solid rgba(255, 255, 255, 0.1);
position: relative;
overflow: hidden;
padding: 0 3px;
font-family: Lucida Console, Monaco, Nimbus Mono L, monospace, serif;
}
.page.log .container .time.highlight {
background: rgba(255, 255, 255, 0.1);
}
.page.log .container .time span {
padding: 5px 0 3px;
display: inline-block;
vertical-align: middle;
}
.page.log[data-filter=INFO] .error,
.page.log[data-filter=INFO] .debug,
.page.log[data-filter=ERROR] .debug,
.page.log[data-filter=ERROR] .info,
.page.log[data-filter=DEBUG] .info,
.page.log[data-filter=DEBUG] .error {
display: none;
}
.page.log .container .type {
margin-left: 10px;
}
.page.log .container .message {
float: right;
width: 86%;
white-space: pre-wrap;
}
.page.log .container .error { color: #FFA4A4; }
.page.log .container .debug span { opacity: .6; }
.do_report {
position: absolute;
padding: 10px;
}
.page.log .report {
position: fixed;
width: 100%;
height: 100%;
background: rgba(0,0,0,.7);
left: 0;
top: 0;
z-index: 99999;
font-size: 14px;
}
.page.log .report .button {
display: inline-block;
margin: 10px 0;
padding: 10px;
}
.page.log .report .bug {
width: 800px;
height: 80%;
position: absolute;
left: 50%;
top: 50%;
margin: 0 0 0 -400px;
transform: translate(0, -50%);
}
.page.log .report .bug textarea {
display: block;
width: 100%;
background: #FFF;
padding: 20px;
overflow: auto;
color: #666;
height: 70%;
font-size: 12px;
}
.page.log .container .time ::-webkit-selection {
background-color: #000;
color: #FFF;
}
.page.log .container .time ::-moz-selection {
background-color: #000;
color: #FFF;
}
.page.log .container .time ::-ms-selection {
background-color: #000;
color: #FFF;
}
.page.log .container .time.highlight ::selection {
background-color: transparent;
color: inherit;
}
.page.log .container .time.highlight ::-webkit-selection {
background-color: transparent;
color: inherit;
}
.page.log .container .time.highlight ::-moz-selection {
background-color: transparent;
color: inherit;
}
.page.log .container .time.highlight ::-ms-selection {
background-color: transparent;
color: inherit;
}
.page.log .container .time.highlight ::selection {
background-color: transparent;
color: inherit;
}

157
couchpotato/core/plugins/log/static/log.js

@ -7,21 +7,21 @@ Page.Log = new Class({
title: 'Show recent logs.',
has_tab: false,
navigation: null,
log_items: [],
report_text: '\
### Steps to reproduce:\n\
1. ..\n\
2. ..\n\
\n\
### Information:\n\
Movie(s) I have this with: ...\n\
Quality of the movie being searched: ...\n\
Providers I use: ...\n\
Version of CouchPotato: {version}\n\
Running on: ...\n\
\n\
### Logs:\n\
```\n{issue}```',
report_text: '### Steps to reproduce:\n'+
'1. ..\n'+
'2. ..\n'+
'\n'+
'### Information:\n'+
'Movie(s) I have this with: ...\n'+
'Quality of the movie being searched: ...\n'+
'Providers I use: ...\n'+
'Version of CouchPotato: {version}\n'+
'Running on: ...\n'+
'\n'+
'### Logs:\n'+
'```\n{issue}```',
indexAction: function () {
var self = this;
@ -34,6 +34,7 @@ Running on: ...\n\
var self = this;
if (self.log) self.log.destroy();
self.log = new Element('div.container.loading', {
'text': 'loading...',
'events': {
@ -41,9 +42,17 @@ Running on: ...\n\
self.showSelectionButton.delay(100, self, e);
}
}
}).inject(self.el);
}).inject(self.content);
if(self.navigation){
var nav = self.navigation.getElement('.nav');
nav.getElements('.active').removeClass('active');
self.navigation.getElements('li')[nr+1].addClass('active');
}
Api.request('logging.get', {
if(self.request && self.request.running) self.request.cancel();
self.request = Api.request('logging.get', {
'data': {
'nr': nr
},
@ -52,65 +61,68 @@ Running on: ...\n\
self.log_items = self.createLogElements(json.log);
self.log.adopt(self.log_items);
self.log.removeClass('loading');
self.scrollToBottom();
var nav = new Element('ul.nav', {
'events': {
'click:relay(li.select)': function (e, el) {
self.getLogs(parseInt(el.get('text')) - 1);
}
}
});
if(!self.navigation){
self.navigation = new Element('div.navigation').adopt(
new Element('h2[text=Logs]'),
new Element('div.hint', {
'text': 'Select multiple lines & report an issue'
})
);
// Type selection
new Element('li.filter').grab(
new Element('select', {
var nav = new Element('ul.nav', {
'events': {
'change': function () {
var type_filter = this.getSelected()[0].get('value');
self.el.set('data-filter', type_filter);
self.scrollToBottom();
'click:relay(li.select)': function (e, el) {
self.getLogs(parseInt(el.get('text')) - 1);
}
}
}).adopt(
new Element('option', {'value': 'ALL', 'text': 'Show all logs'}),
new Element('option', {'value': 'INFO', 'text': 'Show only INFO'}),
new Element('option', {'value': 'DEBUG', 'text': 'Show only DEBUG'}),
new Element('option', {'value': 'ERROR', 'text': 'Show only ERROR'})
)
).inject(nav);
// Selections
for (var i = 0; i <= json.total; i++) {
new Element('li', {
'text': i + 1,
'class': 'select ' + (nr == i ? 'active' : '')
}).inject(nav);
}
// Clear button
new Element('li.clear', {
'text': 'clear',
'events': {
'click': function () {
Api.request('logging.clear', {
'onComplete': function () {
self.getLogs(0);
}).inject(self.navigation);
// Type selection
new Element('li.filter').grab(
new Element('select', {
'events': {
'change': function () {
var type_filter = this.getSelected()[0].get('value');
self.content.set('data-filter', type_filter);
self.scrollToBottom();
}
});
}
}
}).adopt(
new Element('option', {'value': 'ALL', 'text': 'Show all logs'}),
new Element('option', {'value': 'INFO', 'text': 'Show only INFO'}),
new Element('option', {'value': 'DEBUG', 'text': 'Show only DEBUG'}),
new Element('option', {'value': 'ERROR', 'text': 'Show only ERROR'})
)
).inject(nav);
// Selections
for (var i = 0; i <= json.total; i++) {
new Element('li', {
'text': i + 1,
'class': 'select ' + (nr == i ? 'active' : '')
}).inject(nav);
}
}).inject(nav);
// Hint
new Element('li.hint', {
'text': 'Select multiple lines & report an issue'
}).inject(nav);
// Clear button
new Element('li.clear', {
'text': 'clear',
'events': {
'click': function () {
Api.request('logging.clear', {
'onComplete': function () {
self.getLogs(0);
}
});
// Add to page
nav.inject(self.log, 'top');
}
}
}).inject(nav);
self.scrollToBottom();
// Add to page
self.navigation.inject(self.content, 'top');
}
}
});
@ -133,14 +145,14 @@ Running on: ...\n\
new Element('span.message', {
'text': log.message
})
))
));
});
return elements;
},
scrollToBottom: function () {
new Fx.Scroll(window, {'duration': 0}).toBottom();
new Fx.Scroll(this.content, {'duration': 0}).toBottom();
},
showSelectionButton: function(e){
@ -213,7 +225,7 @@ Running on: ...\n\
.replace('{version}', version ? version.version.repr : '...'),
textarea;
var overlay = new Element('div.report', {
var overlay = new Element('div.mask.report_popup', {
'method': 'post',
'events': {
'click': function(e){
@ -245,12 +257,7 @@ Running on: ...\n\
})
),
textarea = new Element('textarea', {
'text': body,
'events': {
'click': function(){
this.select();
}
}
'text': body
}),
new Element('a.button', {
'target': '_blank',
@ -270,7 +277,7 @@ Running on: ...\n\
)
);
overlay.inject(self.log);
overlay.inject(document.body);
},
getSelected: function(){

159
couchpotato/core/plugins/log/static/log.scss

@ -0,0 +1,159 @@
@import "_mixins";
.page.log {
.nav {
text-align: right;
padding: 0;
margin: 0;
li {
display: inline-block;
padding: 5px 10px;
margin: 0;
&.select, &.clear {
cursor: pointer;
}
&:hover:not(.active):not(.filter) {
background: rgba(255, 255, 255, 0.1);
}
&.active {
font-weight: bold;
cursor: default;
background: rgba(255,255,255,.1);
}
}
}
.hint {
font-style: italic;
opacity: .5;
margin-top: 3px;
}
.container {
padding: $padding;
overflow: hidden;
line-height: 150%;
&.loading {
text-align: center;
font-size: 20px;
padding: 100px 50px;
}
select {
vertical-align: top;
}
.time {
clear: both;
font-size: .75em;
border-top: 1px solid rgba(255, 255, 255, 0.1);
overflow: hidden;
padding: 0 3px;
font-family: Lucida Console, Monaco, Nimbus Mono L, monospace, serif;
display: flex;
&.highlight {
background: $theme_off;
}
span {
padding: 5px 0 3px;
display: inline-block;
vertical-align: middle;
width: 90px;
}
::selection {
background-color: #000;
color: #FFF;
}
}
.type.type {
margin-left: 10px;
width: 40px;
}
.message {
white-space: pre-wrap;
flex: 1 auto;
}
.error { color: #FFA4A4; }
.debug span { opacity: .6; }
}
[data-filter=INFO] .error,
[data-filter=INFO] .debug,
[data-filter=ERROR] .debug,
[data-filter=ERROR] .info,
[data-filter=DEBUG] .info,
[data-filter=DEBUG] .error {
display: none;
}
}
.report_popup.report_popup {
position: fixed;
left: 0;
right: 0;
bottom: 0;
top: 0;
z-index: 99999;
font-size: 14px;
display: flex;
justify-content: center;
align-items: center;
opacity: 1;
color: #FFF;
pointer-events: auto;
.button {
margin: 10px 0;
padding: 10px;
color: $background_color;
background: $primary_color;
}
.bug {
width: 80%;
height: 80%;
max-height: 800px;
max-width: 800px;
display: flex;
flex-flow: column nowrap;
> span {
margin: $padding/2 0 $padding 0;
}
textarea {
display: block;
width: 100%;
background: #FFF;
padding: 20px;
overflow: auto;
color: #666;
height: 70%;
font-size: 12px;
}
}
}
.do_report.do_report {
z-index: 10000;
position: absolute;
padding: 10px;
background: $primary_color;
color: #FFF;
}

197
couchpotato/core/plugins/profile/static/profile.css

@ -1,197 +0,0 @@
.add_new_profile {
padding: 20px;
display: block;
text-align: center;
font-size: 20px;
border-bottom: 1px solid rgba(255,255,255,0.2);
}
.profile {
border-bottom: 1px solid rgba(255,255,255,0.2);
position: relative;
}
.profile > .delete {
position: absolute;
padding: 16px;
right: 0;
cursor: pointer;
opacity: 0.6;
color: #fd5353;
}
.profile > .delete:hover {
opacity: 1;
}
.profile .ctrlHolder:hover {
background: none;
}
.profile .qualities {
min-height: 80px;
}
.profile .formHint {
width: 210px !important;
vertical-align: top !important;
margin: 0 !important;
padding-left: 3px !important;
opacity: 0.1;
}
.profile:hover .formHint {
opacity: 1;
}
.profile .wait_for {
padding-top: 0;
padding-bottom: 20px;
}
.profile .wait_for input {
margin: 0 5px !important;
}
.profile .wait_for .minimum_score_input {
width: 40px !important;
text-align: left;
}
.profile .types {
padding: 0;
margin: 0 20px 0 -4px;
display: inline-block;
}
.profile .types li {
padding: 3px 5px;
border-bottom: 1px solid rgba(255,255,255,0.2);
list-style: none;
}
.profile .types li:last-child { border: 0; }
.profile .types li > * {
display: inline-block;
vertical-align: middle;
line-height: 0;
margin-right: 10px;
}
.profile .type .check {
margin-top: -1px;
}
.profile .quality_type select {
width: 120px;
margin-left: -1px;
}
.profile .types li.is_empty .check,
.profile .types li.is_empty .delete,
.profile .types li.is_empty .handle,
.profile .types li.is_empty .check_label {
visibility: hidden;
}
.profile .types .type label {
display: inline-block;
width: auto;
float: none;
text-transform: uppercase;
font-size: 11px;
font-weight: normal;
margin-right: 20px;
text-shadow: none;
vertical-align: bottom;
padding: 0;
height: 17px;
}
.profile .types .type label .check {
margin-right: 5px;
}
.profile .types .type label .check_label {
display: inline-block;
vertical-align: top;
height: 16px;
line-height: 13px;
}
.profile .types .type .threed {
display: none;
}
.profile .types .type.allow_3d .threed {
display: inline-block;
}
.profile .types .type .handle {
background: url('../../images/handle.png') center;
display: inline-block;
height: 20px;
width: 20px;
cursor: -moz-grab;
cursor: -webkit-grab;
cursor: grab;
margin: 0;
}
.profile .types .type .delete {
height: 20px;
width: 20px;
line-height: 20px;
visibility: hidden;
cursor: pointer;
font-size: 13px;
color: #fd5353;
}
.profile .types .type:not(.allow_3d) .delete {
margin-left: 55px;
}
.profile .types .type:hover:not(.is_empty) .delete {
visibility: visible;
}
#profile_ordering {
}
#profile_ordering ul {
float: left;
margin: 0;
width: 275px;
padding: 0;
}
#profile_ordering li {
border-bottom: 1px solid rgba(255,255,255,0.2);
padding: 0 5px;
}
#profile_ordering li:last-child { border: 0; }
#profile_ordering li .check {
margin: 2px 10px 0 0;
vertical-align: top;
}
#profile_ordering li > span {
display: inline-block;
height: 20px;
vertical-align: top;
line-height: 20px;
}
#profile_ordering li .handle {
background: url('../../images/handle.png') center;
width: 20px;
float: right;
cursor: -webkit-grab;
cursor: -moz-grab;
cursor: grab;
}
#profile_ordering .formHint {
clear: none;
float: right;
width: 250px;
margin: 0;
}

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

@ -31,7 +31,7 @@ var Profile = new Class({
}),
new Element('.quality_label.ctrlHolder').adopt(
new Element('label', {'text':'Name'}),
new Element('input.inlay', {
new Element('input', {
'type':'text',
'value': data.label,
'placeholder': 'Profile name'
@ -47,7 +47,7 @@ var Profile = new Class({
new Element('div.wait_for.ctrlHolder').adopt(
// "Wait the entered number of days for a checked quality, before downloading a lower quality release."
new Element('span', {'text':'Wait'}),
new Element('input.inlay.wait_for_input.xsmall', {
new Element('input.wait_for_input.xsmall', {
'type':'text',
'value': data.wait_for && data.wait_for.length > 0 ? data.wait_for[0] : 0
}),
@ -55,7 +55,7 @@ var Profile = new Class({
new Element('span.advanced', {'text':'and keep searching'}),
// "After a checked quality is found and downloaded, continue searching for even better quality releases for the entered number of days."
new Element('input.inlay.xsmall.stop_after_input.advanced', {
new Element('input.xsmall.stop_after_input.advanced', {
'type':'text',
'value': data.stop_after && data.stop_after.length > 0 ? data.stop_after[0] : 0
}),
@ -63,7 +63,7 @@ var Profile = new Class({
// Minimum score of
new Element('span.advanced', {'html':'<br/>Releases need a minimum score of'}),
new Element('input.advanced.inlay.xsmall.minimum_score_input', {
new Element('input.advanced.xsmall.minimum_score_input', {
'size': 4,
'type':'text',
'value': data.minimum_score || 1
@ -81,7 +81,7 @@ var Profile = new Class({
'quality': quality,
'finish': data.finish[nr] || false,
'3d': data['3d'] ? data['3d'][nr] || false : false
})
});
});
}
@ -123,7 +123,7 @@ var Profile = new Class({
}
});
}).delay(delay, self)
}).delay(delay, self);
},
@ -148,7 +148,7 @@ var Profile = new Class({
});
});
return data
return data;
},
addType: function(data){
@ -177,7 +177,7 @@ var Profile = new Class({
var self = this;
return self.types.filter(function(type){
return type.get('quality')
return type.get('quality');
});
},
@ -231,15 +231,15 @@ var Profile = new Class({
},
get: function(attr){
return this.data[attr]
return this.data[attr];
},
isCore: function(){
return this.data.core
return this.data.core;
},
toElement: function(){
return this.el
return this.el;
}
});
@ -270,47 +270,42 @@ Profile.Type = new Class({
var data = self.data;
self.el = new Element('li.type').adopt(
new Element('span.quality_type').grab(
new Element('span.quality_type.select_wrapper.icon-dropdown').grab(
self.fillQualities()
),
self.finish_container = new Element('label.finish').adopt(
new Element('span.finish').grab(
self.finish = new Element('input.inlay.finish[type=checkbox]', {
'checked': data.finish !== undefined ? data.finish : 1,
'events': {
'change': function(){
if(self.el == self.el.getParent().getElement(':first-child')){
self.finish_class.check();
alert('Top quality always finishes the search');
return;
}
self.fireEvent('change');
self.finish = new Element('input.finish[type=checkbox]', {
'checked': data.finish !== undefined ? data.finish : 1,
'events': {
'change': function(){
if(self.el == self.el.getParent().getElement(':first-child')){
alert('Top quality always finishes the search');
return;
}
self.fireEvent('change');
}
})
),
}
}),
new Element('span.check_label[text=finish]')
),
self['3d_container'] = new Element('label.threed').adopt(
new Element('span.3d').grab(
self['3d'] = new Element('input.inlay.3d[type=checkbox]', {
'checked': data['3d'] !== undefined ? data['3d'] : 0,
'events': {
'change': function(){
self.fireEvent('change');
}
self['3d'] = new Element('input.3d[type=checkbox]', {
'checked': data['3d'] !== undefined ? data['3d'] : 0,
'events': {
'change': function(){
self.fireEvent('change');
}
})
),
}
}),
new Element('span.check_label[text=3D]')
),
new Element('span.delete.icon2', {
new Element('span.delete.icon-cancel', {
'events': {
'click': self.del.bind(self)
}
}),
new Element('span.handle')
new Element('span.handle.icon-handle')
);
self.el[self.data.quality ? 'removeClass' : 'addClass']('is_empty');
@ -318,9 +313,6 @@ Profile.Type = new Class({
if(self.data.quality && Quality.getQuality(self.data.quality).allow_3d)
self.el.addClass('allow_3d');
self.finish_class = new Form.Check(self.finish);
self['3d_class'] = new Form.Check(self['3d']);
},
fillQualities: function(){
@ -342,7 +334,7 @@ Profile.Type = new Class({
'text': q.label,
'value': q.identifier,
'data-allow_3d': q.allow_3d
}).inject(self.qualities)
}).inject(self.qualities);
});
self.qualities.set('value', self.data.quality);
@ -358,7 +350,7 @@ Profile.Type = new Class({
'quality': self.qualities.get('value'),
'finish': +self.finish.checked,
'3d': +self['3d'].checked
}
};
},
get: function(key){

150
couchpotato/core/plugins/profile/static/profile.scss

@ -0,0 +1,150 @@
@import "_mixins";
.add_new_profile {
padding: 20px;
display: block;
text-align: center;
font-size: 20px;
border-bottom: 1px solid $theme_off;
}
.profile {
margin-bottom: 20px;
.quality_label input {
font-weight: bold;
}
.ctrlHolder {
.types {
flex: 1 1 auto;
min-width: 360px;
.type {
display: flex;
flex-row: row nowrap;
align-items: center;
padding: 2px 0;
label {
min-width: 0;
margin-left: $padding/2;
span {
font-size: .9em;
}
}
input[type=checkbox] {
margin-right: 3px;
}
.delete, .handle {
margin-left: $padding/4;
width: 20px;
font-size: 20px;
opacity: .1;
text-align: center;
cursor: pointer;
&.handle {
cursor: move;
cursor: grab;
}
&:hover {
opacity: 1;
}
}
&.is_empty {
.delete, .handle {
display: none;
}
}
}
}
&.wait_for.wait_for {
display: block;
input {
min-width: 0;
width: 40px;
text-align: center;
margin: 0 2px;
}
.advanced {
display: none;
color: $primary_color;
.show_advanced & {
display: inline;
}
}
}
.formHint {
}
}
}
#profile_ordering {
ul {
list-style: none;
margin: 0;
width: 275px;
padding: 0;
}
li {
border-bottom: 1px solid $theme_off;
padding: 5px;
display: flex;
align-items: center;
&:hover {
background: $theme_off;
}
&:last-child { border: 0; }
input[type=checkbox] {
margin: 2px 10px 0 0;
vertical-align: top;
}
> span {
display: inline-block;
height: 20px;
vertical-align: top;
line-height: 20px;
&.profile_label {
flex: 1 1 auto;
}
}
.handle {
font-size: 20px;
width: 20px;
float: right;
cursor: move;
cursor: grab;
opacity: .5;
text-align: center;
&:hover {
opacity: 1;
}
}
}
.formHint {
}
}

26
couchpotato/core/plugins/quality/static/quality.css

@ -1,26 +0,0 @@
.group_sizes {
}
.group_sizes .head {
font-weight: bold;
}
.group_sizes .ctrlHolder {
padding-top: 4px !important;
padding-bottom: 4px !important;
font-size: 12px;
}
.group_sizes .label {
max-width: 120px;
}
.group_sizes .min, .group_sizes .max {
text-align: center;
width: 50px;
max-width: 50px;
margin: 0 5px !important;
padding: 0 3px;
display: inline-block;
}

42
couchpotato/core/plugins/quality/static/quality.js

@ -12,20 +12,20 @@ var QualityBase = new Class({
self.profiles = [];
Array.each(data.profiles, self.createProfilesClass.bind(self));
App.addEvent('loadSettings', self.addSettings.bind(self))
App.addEvent('loadSettings', self.addSettings.bind(self));
},
getProfile: function(id){
return this.profiles.filter(function(profile){
return profile.data._id == id
}).pick()
return profile.data._id == id;
}).pick();
},
// Hide items when getting profiles
getActiveProfiles: function(){
return Array.filter(this.profiles, function(profile){
return !profile.data.hide
return !profile.data.hide;
});
},
@ -37,7 +37,7 @@ var QualityBase = new Class({
}
catch(e){}
return {}
return {};
},
addSettings: function(){
@ -58,7 +58,7 @@ var QualityBase = new Class({
self.createProfileOrdering();
self.createSizes();
})
});
},
@ -68,7 +68,7 @@ var QualityBase = new Class({
createProfiles: function(){
var self = this;
var non_core_profiles = Array.filter(self.profiles, function(profile){ return !profile.isCore() });
var non_core_profiles = Array.filter(self.profiles, function(profile){ return !profile.isCore(); });
var count = non_core_profiles.length;
self.settings.createGroup({
@ -81,7 +81,7 @@ var QualityBase = new Class({
'events': {
'click': function(){
var profile = self.createProfilesClass();
$(profile).inject(self.profile_container)
$(profile).inject(self.profile_container);
}
}
})
@ -89,7 +89,7 @@ var QualityBase = new Class({
// Add profiles, that aren't part of the core (for editing)
Array.each(non_core_profiles, function(profile){
$(profile).inject(self.profile_container)
$(profile).inject(self.profile_container);
});
},
@ -97,7 +97,7 @@ var QualityBase = new Class({
createProfilesClass: function(data){
var self = this;
var data = data || {'id': randomString()};
data = data || {'id': randomString()};
var profile = new Profile(data);
self.profiles.include(profile);
@ -110,7 +110,7 @@ var QualityBase = new Class({
self.settings.createGroup({
'label': 'Profile Defaults',
'description': '(Needs refresh \'' +(App.isMac() ? 'CMD+R' : 'F5')+ '\' after editing)'
}).adopt(
}).grab(
new Element('.ctrlHolder#profile_ordering').adopt(
new Element('label[text=Order]'),
self.profiles_list = new Element('ul'),
@ -123,7 +123,7 @@ var QualityBase = new Class({
Array.each(self.profiles, function(profile){
var check;
new Element('li', {'data-id': profile.data._id}).adopt(
check = new Element('input.inlay[type=checkbox]', {
check = new Element('input[type=checkbox]', {
'checked': !profile.data.hide,
'events': {
'change': self.saveProfileOrdering.bind(self)
@ -132,11 +132,8 @@ var QualityBase = new Class({
new Element('span.profile_label', {
'text': profile.data.label
}),
new Element('span.handle')
new Element('span.handle.icon-handle')
).inject(self.profiles_list);
new Form.Check(check);
});
// Sortable
@ -190,7 +187,6 @@ var QualityBase = new Class({
'name': 'sizes'
}).inject(self.content);
new Element('div.item.head.ctrlHolder').adopt(
new Element('span.label', {'text': 'Quality'}),
new Element('span.min', {'text': 'Min'}),
@ -200,23 +196,23 @@ var QualityBase = new Class({
Array.each(self.qualities, function(quality){
new Element('div.ctrlHolder.item').adopt(
new Element('span.label', {'text': quality.label}),
new Element('input.min.inlay[type=text]', {
new Element('input.min[type=text]', {
'value': quality.size_min,
'events': {
'keyup': function(e){
self.changeSize(quality.identifier, 'size_min', e.target.get('value'))
self.changeSize(quality.identifier, 'size_min', e.target.get('value'));
}
}
}),
new Element('input.max.inlay[type=text]', {
new Element('input.max[type=text]', {
'value': quality.size_max,
'events': {
'keyup': function(e){
self.changeSize(quality.identifier, 'size_max', e.target.get('value'))
self.changeSize(quality.identifier, 'size_max', e.target.get('value'));
}
}
})
).inject(group)
).inject(group);
});
},
@ -235,7 +231,7 @@ var QualityBase = new Class({
'value': value
}
});
}).delay(300)
}).delay(300);
}

19
couchpotato/core/plugins/quality/static/quality.scss

@ -0,0 +1,19 @@
@import "_mixins";
.group_sizes {
.item {
.label {
min-width: 150px;
}
.min, .max {
display: inline-block;
width: 70px !important;
min-width: 0 !important;
margin-right: $padding/2;
text-align: center;
}
}
}

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

@ -555,6 +555,8 @@ class Release(Plugin):
releases.append(doc)
except RecordDeleted:
pass
except (ValueError, EOFError):
fireEvent('database.delete_corrupted', r.get('_id'), traceback_error = traceback.format_exc(0))
releases = sorted(releases, key = lambda k: k.get('info', {}).get('score', 0), reverse = True)
@ -563,4 +565,4 @@ class Release(Plugin):
if download_preference != 'both':
releases = sorted(releases, key = lambda k: k.get('info', {}).get('protocol', '')[:3], reverse = (download_preference == 'torrent'))
return releases
return releases or []

5
couchpotato/core/plugins/renamer.py

@ -966,6 +966,7 @@ Remove it if you want it to be renamed (again, or at least let it try again)
try:
for rel in rels:
if not rel.get('media_id'): continue
movie_dict = db.get('id', rel.get('media_id'))
download_info = rel.get('download_info')
@ -1348,12 +1349,12 @@ config = [{
'options': rename_options
},
{
'advanced': True,
'advanced': True,
'name': 'replace_doubles',
'type': 'bool',
'label': 'Clean Name',
'description': ('Attempt to clean up double separaters due to missing data for fields.','Sometimes this eliminates wanted white space (see <a href="https://github.com/RuudBurger/CouchPotatoServer/issues/2782">#2782</a>).'),
'default': True
'default': True
},
{
'name': 'unrar',

19
couchpotato/core/plugins/userscript/static/userscript.js

@ -16,7 +16,7 @@ Page.Userscript = new Class({
indexAction: function(){
var self = this;
self.el.adopt(
self.content.grab(
self.frame = new Element('div.frame.loading', {
'text': 'Loading...'
})
@ -35,7 +35,7 @@ Page.Userscript = new Class({
if(json.error)
self.frame.set('html', json.error);
else {
var item = new Block.Search.MovieItem(json.movie);
var item = new BlockSearchMovieItem(json.movie);
self.frame.adopt(item);
item.showOptions();
}
@ -54,7 +54,7 @@ var UserscriptSettingTab = new Class({
initialize: function(){
var self = this;
App.addEvent('loadSettings', self.addSettings.bind(self))
App.addEvent('loadSettings', self.addSettings.bind(self));
},
@ -80,25 +80,28 @@ var UserscriptSettingTab = new Class({
new Element('span.bookmarklet').adopt(
new Element('a.button.green', {
'text': '+CouchPotato',
/* jshint ignore:start */
'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)})());",
/* jshint ignore:end */
'target': '',
'events': {
'click': function(e){
(e).stop();
alert('Drag it to your bookmark ;)')
alert('Drag it to your bookmark ;)');
}
}
}),
new Element('span', {
'text': '⇽ Drag this to your bookmarks'
})
)
).setStyles({
'background-image': "url('https://couchpota.to/media/images/userscript.gif')"
});
),
new Element('img', {
'src': 'https://couchpota.to/media/images/userscript.gif'
})
);
});

0
couchpotato/core/plugins/userscript/static/userscript.css → couchpotato/core/plugins/userscript/static/userscript.scss

84
couchpotato/core/plugins/wizard/static/wizard.css

@ -1,84 +0,0 @@
.page.wizard .uniForm {
margin: 0 0 30px;
width: 83%;
}
.page.wizard h1 {
padding: 10px 0;
display: block;
font-size: 30px;
margin: 80px 5px 0;
}
.page.wizard .description {
padding: 10px 5px;
font-size: 1.45em;
line-height: 1.4em;
display: block;
}
.page.wizard .tab_wrapper {
background: #5c697b;
height: 65px;
font-size: 1.75em;
position: fixed;
top: 0;
margin: 0;
width: 100%;
left: 0;
z-index: 2;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
.page.wizard .tab_wrapper .tabs {
padding: 0;
margin: 0 auto;
display: block;
height: 100%;
width: 100%;
max-width: 960px;
}
.page.wizard .tabs li {
display: inline-block;
height: 100%;
}
.page.wizard .tabs li a {
padding: 20px 10px;
height: 100%;
display: block;
color: #FFF;
font-weight: normal;
border-bottom: 4px solid transparent;
}
.page.wizard .tabs li:hover a { border-color: #047792; }
.page.wizard .tabs li.done a { border-color: #04bce6; }
.page.wizard .tab_wrapper .pointer {
border-right: 10px solid transparent;
border-left: 10px solid transparent;
border-top: 10px solid #5c697b;
display: block;
position: absolute;
top: 44px;
}
.page.wizard .tab_content {
margin: 20px 0 160px;
}
.page.wizard form > div {
min-height: 300px;
}
.page.wizard .button.green {
padding: 20px;
font-size: 25px;
margin: 10px 0 80px;
display: block;
}
.page.wizard .tab_nzb_providers {
margin: 20px 0 0 0;
}

447
couchpotato/core/plugins/wizard/static/wizard.js

@ -1,245 +1,202 @@
Page.Wizard = new Class({
Extends: Page.Settings,
order: 70,
name: 'wizard',
has_tab: false,
wizard_only: true,
headers: {
'welcome': {
'title': 'Welcome to the new CouchPotato',
'description': 'To get started, fill in each of the following settings as much as you can.',
'content': new Element('div', {
'styles': {
'margin': '0 0 0 30px'
}
})
},
'general': {
'title': 'General',
'description': 'If you want to access CP from outside your local network, you better secure it a bit with a username & password.'
},
'downloaders': {
'title': 'What download apps are you using?',
'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 the default Blackhole.'
},
'searcher': {
'label': 'Providers',
'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 more.'
},
'renamer': {
'title': 'Move & rename the movies after downloading?',
'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 extension or drag the bookmarklet to your 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('https://couchpota.to/media/images/userscript.gif')"
})
}
},
'finish': {
'title': 'Finishing Up',
'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(
new Element('a.button.green', {
'styles': {
'margin-top': 20
},
'text': 'I\'m ready to start the awesomeness, wow this button is big and green!',
'events': {
'click': function(e){
(e).preventDefault();
Api.request('settings.save', {
'data': {
'section': 'core',
'name': 'show_wizard',
'value': 0
},
'useSpinner': true,
'spinnerOptions': {
'target': self.el
},
'onComplete': function(){
window.location = App.createUrl('wanted');
}
});
}
}
})
)
}
},
groups: ['welcome', 'general', 'downloaders', 'searcher', 'renamer', 'automation', 'finish'],
open: function(action, params){
var self = this;
if(!self.initialized){
App.fireEvent('unload');
App.getBlock('header').hide();
self.parent(action, params);
self.addEvent('create', function(){
self.orderGroups();
});
self.initialized = true;
self.scroll = new Fx.Scroll(document.body, {
'transition': 'quint:in:out'
});
}
else
(function(){
var sc = self.el.getElement('.wgroup_'+action);
self.scroll.start(0, sc.getCoordinates().top-80);
}).delay(1)
},
orderGroups: function(){
var self = this;
var form = self.el.getElement('.uniForm');
var tabs = self.el.getElement('.tabs');
self.groups.each(function(group){
if(self.headers[group]){
var group_container = new Element('.wgroup_'+group, {
'styles': {
'opacity': 0.2
},
'tween': {
'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(
new Element('h1', {
'text': self.headers[group].title
}),
self.headers[group].description ? new Element('span.description', {
'html': self.headers[group].description
}) : null,
content ? (typeOf(content) == 'function' ? content() : content) : null
).inject(form);
}
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){
tabs.adopt(tab_navigation); // Tab navigation
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');
a.set('text', (self.headers[group].label || group).capitalize());
var url_split = a.get('href').split('wizard')[1].split('/');
if(url_split.length > 3)
a.set('href', a.get('href').replace(url_split[url_split.length-3]+'/', ''));
}
}
else {
new Element('li.t_'+group).adopt(
new Element('a', {
'href': App.createUrl('wizard/'+group),
'text': (self.headers[group].label || group).capitalize()
})
).inject(tabs);
}
if(self.headers[group] && self.headers[group].event)
self.headers[group].event.call()
});
// Remove toggle
self.el.getElement('.advanced_toggle').destroy();
// Hide retention
self.el.getElement('.section_nzb').hide();
// Add pointer
new Element('.tab_wrapper').wraps(tabs);
// Add nav
var minimum = self.el.getSize().y-window.getSize().y;
self.groups.each(function(group, nr){
var g = self.el.getElement('.wgroup_'+group);
if(!g || !g.isVisible()) return;
var t = self.el.getElement('.t_'+group);
if(!t) return;
var func = function(){
// Activate all previous ones
self.groups.each(function(groups2, nr2){
var t2 = self.el.getElement('.t_'+groups2);
t2[nr2 > nr ? 'removeClass' : 'addClass' ]('done');
});
g.tween('opacity', 1);
};
if(nr == 0)
func();
new ScrollSpy( {
min: function(){
var c = g.getCoordinates();
var top = c.top-(window.getSize().y/2);
return top > minimum ? minimum : top
},
max: function(){
var c = g.getCoordinates();
return c.top+(c.height/2)
},
onEnter: func,
onLeave: function(){
g.tween('opacity', 0.2)
}
});
});
}
});
Page.Wizard = new Class({
Extends: Page.Settings,
order: 70,
name: 'wizard',
current: 'welcome',
has_tab: false,
wizard_only: true,
headers: {
'welcome': {
'title': 'Welcome to the new CouchPotato',
'description': 'To get started, fill in each of the following settings as much as you can.',
'content': new Element('div', {
'styles': {
'margin': '0 0 0 30px'
}
})
},
'general': {
'title': 'General',
'description': 'If you want to access CP from outside your local network, you better secure it a bit with a username & password.'
},
'downloaders': {
'title': 'What download apps are you using?',
'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 the default Blackhole.'
},
'searcher': {
'label': 'Providers',
'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 more.'
},
'renamer': {
'title': 'Move & rename the movies after downloading?',
'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 extension or drag the bookmarklet to your 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('https://couchpota.to/media/images/userscript.gif')"
});
}
},
'finish': {
'title': 'Finishing Up',
'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').grab(
new Element('a.button.green', {
'styles': {
'margin-top': 20
},
'text': 'I\'m ready to start the awesomeness!',
'events': {
'click': function(e){
(e).preventDefault();
Api.request('settings.save', {
'data': {
'section': 'core',
'name': 'show_wizard',
'value': 0
},
'useSpinner': true,
'spinnerOptions': {
'target': self.el
},
'onComplete': function(){
window.location = App.createUrl('wanted');
}
});
}
}
})
)
}
},
groups: ['welcome', 'general', 'downloaders', 'searcher', 'renamer', 'automation', 'finish'],
open: function(action, params){
var self = this;
if(!self.initialized){
App.fireEvent('unload');
App.getBlock('header').hide();
self.parent(action, params);
self.el.addClass('settings');
self.addEvent('create', function(){
self.orderGroups();
});
self.initialized = true;
self.scroll = new Fx.Scroll(document.body, {
'transition': 'quint:in:out'
});
}
else
(function(){
var sc = self.el.getElement('.wgroup_'+action);
self.scroll.start(0, sc.getCoordinates().top-80);
}).delay(1);
},
orderGroups: function(){
var self = this;
var form = self.el.getElement('.uniForm');
var tabs = self.el.getElement('.tabs').hide();
self.groups.each(function(group){
var group_container;
if(self.headers[group]){
group_container = new Element('.wgroup_'+group);
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(
new Element('h1', {
'text': self.headers[group].title
}),
self.headers[group].description ? new Element('span.description', {
'html': self.headers[group].description
}) : null,
content ? (typeOf(content) == 'function' ? content() : content) : null
).inject(form);
}
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){
tabs.adopt(tab_navigation); // Tab navigation
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).grab(
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');
a.set('text', (self.headers[group].label || group).capitalize());
var url_split = a.get('href').split('wizard')[1].split('/');
if(url_split.length > 3)
a.set('href', a.get('href').replace(url_split[url_split.length-3]+'/', ''));
}
}
else {
new Element('li.t_'+group).grab(
new Element('a', {
'href': App.createUrl('wizard/'+group),
'text': (self.headers[group].label || group).capitalize()
})
).inject(tabs);
}
if(self.headers[group] && self.headers[group].event)
self.headers[group].event.call();
});
// Remove toggle
self.el.getElement('.advanced_toggle').destroy();
// Hide retention
self.el.getElement('.section_nzb').hide();
}
});

62
couchpotato/core/plugins/wizard/static/wizard.scss

@ -0,0 +1,62 @@
@import "_mixins";
.page.wizard {
.navigation.navigation {
display: none;
}
.tab_content.tab_content {
display: block;
fieldset {
.ctrlHolder, h2 {
padding: $padding/4;
}
}
}
h1 {
padding: 10px 0;
display: block;
font-size: 30px;
margin: 80px 5px 0;
font-weight: 300;
}
.description {
padding: $padding/2 $padding/4;
font-size: 1.45em;
line-height: 1.4em;
display: block;
}
form.uniForm.containers {
margin: 0;
}
form > div {
min-height: 300px;
max-width: $mq-desktop;
padding: $padding;
margin: 0 auto;
@include media-phablet {
padding: $padding/2;
}
}
.button.green {
padding: 20px;
font-size: 25px;
margin: 10px 0 80px;
display: inline-block;
}
.tab_nzb_providers {
margin: 20px 0 0 0;
}
}

BIN
couchpotato/static/fonts/Elusive-Icons.eot

Binary file not shown.

298
couchpotato/static/fonts/Elusive-Icons.svg

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 213 KiB

BIN
couchpotato/static/fonts/Elusive-Icons.ttf

Binary file not shown.

BIN
couchpotato/static/fonts/Elusive-Icons.woff

Binary file not shown.

BIN
couchpotato/static/fonts/Lobster-webfont.eot

Binary file not shown.

246
couchpotato/static/fonts/Lobster-webfont.svg

@ -3,242 +3,36 @@
<svg xmlns="http://www.w3.org/2000/svg">
<metadata></metadata>
<defs>
<font id="lobster_1.4regular" horiz-adv-x="1034" >
<font id="lobster_14regular" horiz-adv-x="2048" >
<font-face units-per-em="2048" ascent="1638" descent="-410" />
<missing-glyph horiz-adv-x="444" />
<glyph unicode="&#xfb01;" horiz-adv-x="1093" d="M-424 -283q0 53 21 96.5t51.5 72t82 55t93.5 41.5t106 34l228 1078q93 440 479 440q367 0 367 -236q0 -86 -46 -125.5t-116 -39.5q-52 0 -87.5 25t-35.5 85q0 37 19.5 68.5t49.5 31.5q15 0 17 -2q-1 39 -32 60.5t-81 21.5q-168 0 -217 -231l-35 -168h164l-16 -82h-164 l-234 -1106q-21 -101 -62 -173t-93 -108t-101.5 -51.5t-103.5 -15.5q-114 0 -184 62t-70 167zM-311 -248q0 -32 17.5 -52t34 -25t32.5 -5q35 0 68 39.5t50 120.5l25 119q-102 -32 -164.5 -83.5t-62.5 -113.5zM530 233q0 51 17 134l139 657h295l-147 -696q-9 -40 -9 -66 q0 -42 20 -59t64 -17q59 0 110 51.5t75 129.5h86q-33 -95 -79 -167t-90.5 -111t-95.5 -63t-88.5 -31t-76.5 -7q-98 0 -159 61t-61 184z" />
<glyph unicode="&#xfb02;" horiz-adv-x="1122" d="M-428 -291q0 55 19.5 99t48 73t79 55.5t94.5 42.5t113 37l246 1170q18 84 50 148t69 101t83 60.5t86.5 31t84.5 7.5q86 0 185.5 -22t170.5 -47.5t186 -71.5l-225 -1065q-8 -36 -8 -66q0 -42 20 -59t64 -17q59 0 109.5 51.5t74.5 129.5h86q-33 -95 -79 -167t-90.5 -111 t-95.5 -63t-88.5 -31t-76.5 -7q-98 0 -158.5 61t-60.5 184q0 56 16 134l213 1005q-35 15 -87.5 24t-79.5 9q-43 0 -82 -35t-58 -127l-45 -219h191l-17 -82h-190l-234 -1106q-18 -84 -49.5 -148t-68.5 -101.5t-83 -60.5t-86 -30.5t-85 -7.5q-97 0 -169.5 62t-72.5 159z M-315 -262q0 -23 25 -45.5t57 -22.5q36 0 69.5 38.5t50.5 121.5l25 119q-109 -36 -168 -85t-59 -126z" />
<glyph unicode="&#xfb03;" horiz-adv-x="1564" d="M-428 -291q0 55 19.5 99t48 73t79 55.5t94.5 42.5t113 37l246 1170q18 84 50 148t68.5 101.5t82.5 60.5t86.5 30.5t85.5 7.5q170 0 252 -107q119 107 309 107q367 0 367 -236q0 -86 -46 -125.5t-116 -39.5q-52 0 -87.5 25t-35.5 85q0 37 19.5 68.5t49.5 31.5q15 0 17 -2 q-1 39 -32 60.5t-81 21.5q-168 0 -217 -231l-35 -168h543l-147 -696q-9 -40 -9 -66q0 -42 20 -59t64 -17q59 0 110 51.5t75 129.5h86q-33 -95 -79 -167t-90.5 -111t-95.5 -63t-88.5 -31t-76.5 -7q-98 0 -159 61t-61 184q0 51 17 134l121 575h-246l-234 -1106 q-21 -101 -62 -173t-93 -108t-101.5 -51.5t-103.5 -15.5q-75 0 -133.5 29t-89.5 80q-99 -109 -262 -109q-97 0 -169.5 62t-72.5 159zM-303 -262q0 -23 25 -45.5t57 -22.5q36 0 70 38.5t51 121.5l24 119q-109 -36 -168 -85t-59 -126zM145 -293q5 -36 29 -50.5t47 -14.5 q45 0 81.5 45.5t57.5 142.5l48 223l-183 -37l-39 -180q-13 -65 -41 -129zM238 74l180 30l176 838h-172zM438 1024h174l15 70q32 153 102 256q-31 34 -82 34q-78 0 -119.5 -56t-56.5 -136z" />
<glyph unicode="&#xfb04;" horiz-adv-x="1597" d="M-428 -291q0 55 19.5 99t48 73t79 55.5t94.5 42.5t113 37l246 1170q18 84 50 148t68.5 101.5t82.5 60.5t86.5 30.5t85.5 7.5q152 0 235 -86q94 86 240 86q86 0 186 -22t171 -47.5t186 -71.5l-226 -1065q-8 -36 -8 -66q0 -42 20 -59t64 -17q59 0 109.5 51.5t74.5 129.5h86 q-33 -95 -79 -167t-90.5 -111t-95.5 -63t-88.5 -31t-76.5 -7q-98 0 -158.5 61t-60.5 184q0 51 17 134l213 1005q-35 15 -88 24t-80 9q-43 0 -82 -35t-58 -127l-45 -219h191l-17 -82h-190l-236 -1106q-21 -101 -62 -173t-93 -108t-101.5 -51.5t-103.5 -15.5q-76 0 -134 29 t-89 82q-98 -111 -262 -111q-97 0 -169.5 62t-72.5 159zM-303 -262q0 -23 25 -45.5t57 -22.5q36 0 70 38.5t51 121.5l24 119q-109 -36 -168 -85t-59 -126zM145 -291q4 -37 28.5 -52t47.5 -15q45 0 81.5 45.5t57.5 142.5l48 223l-183 -37l-39 -180q-13 -63 -41 -127zM238 74 l180 30l178 838h-174zM438 1024h174l35 162q19 99 66 178q-27 20 -66 20q-78 0 -119.5 -56t-56.5 -136z" />
<glyph horiz-adv-x="2048" />
<glyph horiz-adv-x="2048" />
<glyph unicode="&#xd;" horiz-adv-x="2048" />
<glyph />
<glyph />
<glyph unicode="&#xd;" />
<glyph unicode=" " horiz-adv-x="444" />
<glyph unicode="&#x09;" horiz-adv-x="444" />
<glyph unicode="&#xa0;" horiz-adv-x="444" />
<glyph unicode="!" horiz-adv-x="526" d="M70 164q0 67 47.5 114.5t115.5 47.5q67 0 114.5 -47t47.5 -115t-47.5 -116t-114.5 -48t-115 48t-48 116zM201 473l145 961h295l-266 -961h-174z" />
<glyph unicode="&#x22;" horiz-adv-x="860" d="M127 1149l125 387h215l-186 -387h-154zM449 1149l124 387h215l-186 -387h-153z" />
<glyph unicode="#" horiz-adv-x="1349" d="M92 227l43 209h213l43 232h-209l43 209h203l107 593h180l-133 -593h215l106 593h180l-133 -593h213l-41 -209h-217l-51 -232h219l-41 -209h-225l-62 -282h-116l51 282h-242l-61 -282h-117l51 282h-219zM485 436h232l43 232h-223z" />
<glyph unicode="$" horiz-adv-x="825" d="M49 455q0 78 43 127t105 49q41 0 64.5 -15t23.5 -36q-82 -14 -82 -152q0 -42 25 -75.5t61 -49.5l73 402q-16 14 -49 39.5t-51.5 41t-44 41t-39 46.5t-23.5 50.5t-10 61.5q0 109 98 186t218 82l39 217h118l-51 -223q178 -28 178 -170q0 -71 -26.5 -113t-71.5 -42 q-42 0 -80 47q49 28 49 106q0 26 -16.5 51.5t-48.5 38.5l-74 -329l46.5 -31t43.5 -31t46 -38t36.5 -41t33 -50t18 -55.5t8.5 -67.5q0 -142 -102 -221t-267 -82l-59 -274h-56l49 276q-103 8 -164 64t-61 170zM340 1024q0 -68 57 -125l49 277q-55 -11 -80.5 -55t-25.5 -97z M358 295q69 8 102.5 59.5t33.5 124.5q0 82 -60 156z" />
<glyph unicode="%" horiz-adv-x="1318" d="M219 999q0 187 91 313t241 126q87 0 127.5 -58.5t40.5 -173.5q0 -68 -20.5 -142.5t-57 -142t-96 -111.5t-129.5 -44q-113 0 -155 57t-42 176zM248 0l790 1536h148l-791 -1536h-147zM367 975q0 -133 55 -133q53 0 93 56t60.5 145t20.5 194q0 62 -10.5 95.5t-40.5 33.5 q-50 0 -106.5 -83.5t-67.5 -219.5q-4 -50 -4 -88zM727 233q0 187 91 313t241 126q90 0 139 -60t49 -172q0 -55 -10.5 -112.5t-35 -117t-60.5 -106t-92.5 -75.5t-124.5 -29q-113 0 -155 57t-42 176zM864 209q0 -133 56 -133q53 0 91.5 52.5t57 137.5t18.5 191q0 139 -57 139 q-49 0 -100 -81t-62 -218q-4 -50 -4 -88z" />
<glyph unicode="&#x26;" horiz-adv-x="1396" d="M23 401q0 102 39.5 193.5t125.5 163.5t205 96q-101 55 -152 137t-51 174q0 71 31 137t87 118.5t144 84t193 31.5q74 0 139.5 -15.5t120 -46.5t86 -85.5t31.5 -126.5q0 -87 -34.5 -138t-108.5 -51q-71 0 -117 53q35 10 62.5 67t27.5 101q0 15 -1 29t-9 38.5t-21 41.5 t-40 30t-64 13q-110 0 -180 -73.5t-70 -178.5q0 -96 66.5 -186.5t203.5 -151.5q-183 -75 -269.5 -185.5t-86.5 -226.5q0 -112 71 -192t169 -80q57 0 109.5 19t104 60.5t92.5 120t64 185.5q-18 1 -47.5 4.5t-53 5.5t-44.5 2q-134 0 -193 -92l-14 2q32 130 136.5 209.5 t258.5 79.5q29 0 80 -5t76 -5q61 0 115 22.5t79 65.5h13q0 -88 -93.5 -176t-218.5 -109q-25 -91 -56.5 -167t-63 -131.5t-71 -99.5t-73.5 -72t-78 -48.5t-76.5 -31t-77.5 -16t-73 -6.5t-70 -1q-103 0 -185 34.5t-133 93t-78 131.5t-27 154z" />
<glyph unicode="'" horiz-adv-x="548" d="M209 1149l125 387h215l-187 -387h-153z" />
<glyph unicode="(" horiz-adv-x="894" d="M283 205q0 200 48 406.5t133 386.5t211.5 323.5t274.5 214.5l27 -82q-148 -74 -275 -284t-198.5 -483t-71.5 -537q0 -381 150 -603l-68 -59q-116 128 -173.5 314t-57.5 403z" />
<glyph unicode=")" horiz-adv-x="845" d="M-59 -430q148 74 274.5 283t198 482t71.5 539q0 382 -149 603l67 59q116 -128 174 -314t58 -403q0 -270 -81 -538t-235.5 -483t-351.5 -310z" />
<glyph unicode="*" horiz-adv-x="1054" d="M176 1026l223 129l-223 129l62 107l219 -127v276h131v-276l219 127l61 -107l-223 -129l223 -129l-61 -106l-219 127v-277h-131v277l-219 -127z" />
<glyph unicode="+" horiz-adv-x="1054" d="M109 420l49 229h262l55 250h232l-56 -250h260l-47 -229h-262l-55 -252h-232l56 252h-262z" />
<glyph unicode="," horiz-adv-x="442" d="M49 154q0 68 47.5 115.5t114.5 47.5q66 0 102.5 -43t36.5 -112q0 -97 -72.5 -216.5t-193.5 -203.5q-18 13 -18 35q0 25 16.5 50t36.5 42.5t36.5 43t16.5 50.5q0 23 -27 41q-96 63 -96 150z" />
<glyph unicode="-" horiz-adv-x="593" d="M39 455l37 161h409l-34 -161h-412z" />
<glyph unicode="." horiz-adv-x="538" d="M63 154q0 68 47.5 115.5t114.5 47.5q68 0 116 -48t48 -115t-48 -114.5t-116 -47.5q-67 0 -114.5 47t-47.5 115z" />
<glyph unicode="/" horiz-adv-x="636" d="M23 -512l434 2048h147l-434 -2048h-147z" />
<glyph unicode="0" horiz-adv-x="1118" d="M61 520q0 167 31.5 320t92.5 279.5t146 219.5t198.5 145t242.5 52q188 0 276.5 -135.5t88.5 -399.5q0 -103 -19.5 -217t-56 -228.5t-93.5 -217.5t-127 -182.5t-162.5 -126.5t-193.5 -47q-104 0 -179 24t-122.5 66.5t-75 112t-37.5 148t-10 187.5zM375 463 q0 -309 121 -309q84 0 156 86t118 226t72 313.5t26 353.5q0 70 -4 118.5t-15 92t-33.5 65t-57.5 21.5q-47 0 -105.5 -56t-114 -152t-98.5 -244t-55 -312q-10 -138 -10 -203z" />
<glyph unicode="1" horiz-adv-x="649" d="M43 0l270 1278h-194l24 94q112 0 233.5 31t287.5 129l-326 -1532h-295z" />
<glyph unicode="2" horiz-adv-x="1007" d="M-23 61q0 91 37 178t96.5 160.5t131.5 147.5t144 151.5t131.5 159t96.5 184.5t37 213q0 72 -39 120t-86 48q-96 0 -131 -41t-35 -125q0 -43 19.5 -85.5t58.5 -53.5q-78 -69 -155 -69q-65 0 -106.5 48.5t-41.5 135.5q0 43 14 84.5t46 81.5t79.5 69.5t120.5 47.5t162 18 q389 0 389 -330q0 -94 -31 -180.5t-84 -157t-118 -134.5t-138 -123t-138.5 -112t-126 -113t-93.5 -114h10q56 0 183 -18.5t208 -18.5q30 0 54 2t47 11t36 13.5t35.5 23t30 24t35.5 33t37 35.5q2 -33 2 -90q0 -81 -10 -134t-36 -94.5t-74.5 -60.5t-123.5 -19q-113 0 -259 37 t-249 37q-21 0 -51 -10.5t-63.5 -26.5t-46.5 -20q-5 29 -5 67z" />
<glyph unicode="3" horiz-adv-x="1052" d="M12 338q0 132 64.5 212.5t183.5 80.5q138 0 160 -105q-180 -14 -180 -221q0 -106 43 -144t112 -38q127 0 206 103t79 243q0 126 -68.5 232.5t-203.5 154.5q83 23 151.5 68.5t110.5 101.5t65 115t23 114q0 74 -40.5 121t-115.5 47q-73 0 -117.5 -43.5t-44.5 -115.5 q0 -48 19.5 -91.5t58.5 -54.5q-75 -69 -156 -69q-64 0 -105.5 46.5t-41.5 127.5q0 138 121.5 224.5t302.5 86.5t281 -86t100 -213q0 -106 -72.5 -209.5t-208.5 -171.5q129 -42 193.5 -132.5t64.5 -205.5q0 -74 -26 -149.5t-77 -143t-119.5 -120t-160.5 -83t-194 -30.5 q-45 0 -89 5.5t-105 27t-105.5 56.5t-76.5 102.5t-32 156.5z" />
<glyph unicode="4" horiz-adv-x="974" d="M16 563q22 67 77 184.5t101 214.5t83.5 222.5t37.5 228.5q0 66 -14 123q95 0 161 -51.5t66 -143.5q0 -90 -33.5 -181.5t-75 -154t-101.5 -149t-89 -141.5h320l166 780l303 41l-176 -821h131l-41 -152h-123l-119 -563h-295l121 563h-500z" />
<glyph unicode="5" horiz-adv-x="1058" d="M31 285q0 77 24 135.5t63.5 91t84.5 48t94 15.5q125 0 145 -104q-84 -9 -134 -59t-50 -138q0 -42 15 -72.5t41 -46t53.5 -22t58.5 -6.5q81 0 142 58t89.5 142t28.5 177q0 145 -60 221t-165 76q-122 0 -305 -115l168 817q38 -4 100 -12t97.5 -12t83 -7.5t87.5 -3.5 q164 0 332 66q4 -46 4 -68q0 -107 -56 -172t-179 -65q-64 0 -195.5 24.5t-146.5 26.5l-82 -371q134 64 256 64q90 0 160.5 -34t113 -93t64.5 -134.5t22 -162.5q0 -110 -35 -207.5t-104.5 -177.5t-186.5 -127t-268 -47q-360 0 -360 295z" />
<glyph unicode="6" horiz-adv-x="1017" d="M33 395q0 49 2 76q12 187 47.5 347.5t96.5 293.5t144.5 226.5t196 145.5t246.5 52q109 0 172 -51.5t63 -118.5q0 -55 -46.5 -94t-135.5 -43q33 29 33 74q0 43 -29.5 76.5t-72.5 33.5q-11 0 -24.5 -2t-39 -12t-50.5 -26t-57.5 -48.5t-61.5 -76.5t-60.5 -112.5t-57 -152 t-48 -201t-36.5 -254.5q-10 -102 -10 -155q0 -74 11 -120t35.5 -68t50.5 -28.5t67 -6.5q65 0 130.5 61.5t108 163t42.5 207.5q0 49 -8 90t-34 74.5t-67 33.5q-104 0 -180 -155q-41 58 -41 118q0 88 85 146.5t204 58.5q70 0 125 -30t87 -79.5t48 -108t16 -120.5 q0 -130 -45.5 -246.5t-121 -197.5t-176.5 -128.5t-210 -47.5q-96 0 -167.5 22t-115 57.5t-70.5 89.5t-36.5 110t-9.5 126z" />
<glyph unicode="7" horiz-adv-x="950" d="M68 256q0 70 19 146t47.5 145t80.5 154.5t98.5 152.5t122.5 162t132 161t145 169q-89 12 -174 12q-292 0 -424 -146q-17 73 -17 119q0 103 66 154t213 51h672q-124 -185 -352 -545.5t-265 -447.5q-65 -147 -65 -264q0 -62 22.5 -108t77.5 -91q-30 -80 -188 -80 q-103 0 -157 55t-54 201z" />
<glyph unicode="8" horiz-adv-x="1021" d="M-16 401q0 149 95 276t273 177q-88 51 -131 123.5t-43 155.5q0 74 34 146t92.5 128.5t145.5 91.5t185 35q185 0 286 -85t101 -212q0 -107 -75 -211.5t-212 -171.5q125 -38 186.5 -123.5t61.5 -195.5q0 -94 -43 -190.5t-116 -175.5t-181 -129t-227 -50q-102 0 -185.5 34.5 t-136.5 92t-81.5 131t-28.5 153.5zM281 334q0 -88 37.5 -142.5t107.5 -54.5q101 0 168.5 103.5t67.5 240.5q0 87 -32.5 167t-97.5 136q-81 -54 -139.5 -134t-85 -160.5t-26.5 -155.5zM446 1167q0 -70 27.5 -134.5t81.5 -108.5q97 64 152 168.5t55 199.5q0 64 -26 104t-74 40 q-97 0 -156.5 -80.5t-59.5 -188.5z" />
<glyph unicode="9" horiz-adv-x="1001" d="M59 184q0 69 38.5 110.5t138.5 41.5q-29 -29 -29 -70q0 -44 31.5 -79t76.5 -35q20 0 38.5 2.5t59 19t74.5 46.5t77 93t75 149.5t59.5 224.5t40.5 310q4 78 4 107q0 93 -12 153.5t-37.5 91t-55.5 41.5t-75 11q-65 0 -125.5 -66.5t-97.5 -170t-37 -208.5q0 -36 5 -70 t17 -67.5t36 -53.5t57 -20q61 0 103.5 27.5t68.5 95.5q43 -52 43 -102q0 -77 -80.5 -132.5t-194.5 -55.5q-73 0 -130.5 32.5t-91 85.5t-50 114.5t-16.5 125.5q0 167 70 305t191.5 216.5t268.5 78.5q92 0 162.5 -26t114 -68.5t70.5 -106t37.5 -131t10.5 -149.5 q0 -308 -82.5 -548.5t-241 -378.5t-370.5 -138q-111 0 -176.5 59t-65.5 135z" />
<glyph unicode=":" horiz-adv-x="546" d="M84 276q0 68 47.5 116t114.5 48q68 0 116 -48t48 -116q0 -67 -48 -114t-116 -47t-115 47t-47 114zM186 768q0 68 47.5 116t114.5 48q68 0 116 -48t48 -116q0 -67 -48 -114.5t-116 -47.5t-115 47t-47 115z" />
<glyph unicode=";" horiz-adv-x="565" d="M94 186q0 68 47.5 116t114.5 48q66 0 102.5 -43t36.5 -112q0 -97 -72.5 -216.5t-193.5 -203.5q-18 13 -18 35q0 25 16.5 50t36.5 42.5t36.5 43t16.5 50.5q0 23 -27 41q-96 63 -96 149zM193 678q0 68 47 116t114 48q68 0 116 -48t48 -116q0 -67 -48 -114.5t-116 -47.5 q-67 0 -114 47t-47 115z" />
<glyph unicode="&#x3c;" horiz-adv-x="735" d="M41 487l18 84l629 308l-20 -113l-494 -246l397 -196l-24 -117z" />
<glyph unicode="=" horiz-adv-x="1054" d="M66 207l49 229h753l-47 -229h-755zM156 647l49 230h753l-47 -230h-755z" />
<glyph unicode="&#x3e;" horiz-adv-x="704" d="M31 207l28 117l492 196l-397 246l18 113l504 -308l-23 -110z" />
<glyph unicode="?" horiz-adv-x="903" d="M98 164q0 67 48 114.5t116 47.5t115 -47t47 -115t-47.5 -116t-114.5 -48q-68 0 -116 48t-48 116zM113 1104q0 55 24.5 110.5t73.5 106t135.5 82t196.5 31.5q102 0 169 -18.5t100.5 -55t45.5 -77t12 -97.5q0 -81 -21.5 -147.5t-58.5 -113.5t-82 -88t-94 -79t-93.5 -77 t-83 -92t-58.5 -114h-135q0 58 20.5 113t53.5 99.5t72.5 88.5t79 88.5t72.5 91t53.5 105t20.5 121.5q0 71 -32 106t-80 35q-62 0 -113 -48.5t-51 -121.5q0 -42 19.5 -83t58.5 -52q-26 -42 -66 -64t-84 -22q-64 0 -109.5 45t-45.5 127z" />
<glyph unicode="@" horiz-adv-x="1150" d="M-16 336q0 219 94.5 404.5t255 293t348.5 107.5q44 0 82.5 -6t85 -26.5t79 -53.5t55 -94t22.5 -142q0 -130 -50.5 -256t-132 -205t-166.5 -79q-64 0 -90 47q-58 -80 -121 -80q-131 0 -131 141q0 56 19 137t51.5 163.5t86.5 140t114 57.5q49 0 78 -37l8 33l112 -13 l-92 -393q-8 -32 -8 -47q0 -39 27 -39q39 0 77 92t59 198t21 169q0 162 -180 162q-87 0 -165 -39t-134 -104.5t-97.5 -151t-62 -179.5t-20.5 -188q0 -129 52.5 -185.5t197.5 -56.5q111 0 182.5 33t124.5 103q47 -20 47 -92q0 -99 -113 -163.5t-301 -64.5q-100 0 -173.5 21 t-129.5 67.5t-84 128t-28 197.5zM449 434q0 -63 36 -63q24 0 68 28q0 22 6 43l88 340q-14 17 -37 17q-42 0 -75 -44.5t-50.5 -107.5t-26.5 -119.5t-9 -93.5z" />
<glyph unicode="A" horiz-adv-x="1368" d="M18 686q0 105 119 178.5t299 73.5q42 0 107 -6q80 127 165.5 233.5t177 191t187 132t182.5 47.5q91 0 162 -29l-321 -1507h-295l157 743q-137 62 -274 74q-116 -252 -191 -514.5t-75 -421.5q0 -72 28 -114q-31 0 -50.5 0.5t-51.5 5t-53 12.5t-45.5 24t-39 38.5 t-24.5 57.5t-10 79q0 137 83.5 367t217.5 466q-204 -13 -240 -106q8 0 17.5 -21.5t9.5 -42.5q0 -36 -33 -58t-82 -22q-55 0 -91 30.5t-36 88.5zM727 905q148 -29 250 -71l119 557q-171 -92 -369 -486z" />
<glyph unicode="B" horiz-adv-x="1300" d="M12 993q0 104 62.5 204t164 174t238.5 119.5t279 45.5q109 0 194.5 -27t137 -73.5t78 -103.5t26.5 -122q0 -93 -54 -181t-151 -144q123 -25 182.5 -115t59.5 -215q0 -64 -13.5 -137.5t-47 -155t-82.5 -146.5t-128.5 -108t-177.5 -43q-37 0 -69.5 6.5t-64 22t-50 47.5 t-18.5 76q0 51 26 119q71 -74 137 -74q53 0 94.5 35t64 91.5t33.5 117.5t11 124q0 261 -194 261q-30 0 -95 -7l-168 -784h-294l278 1303l303 40l-96 -454h12q79 0 148 51t108 127.5t39 153.5q0 96 -66.5 158.5t-203.5 62.5q-73 0 -145 -19t-138.5 -59.5t-117.5 -98 t-81 -140.5t-30 -181q0 -46 6.5 -76t14 -44.5t7.5 -18.5q-219 0 -219 188z" />
<glyph unicode="C" horiz-adv-x="1017" d="M39 471q0 83 11 176t37 197.5t64 202t96.5 187t129.5 156.5t168.5 106.5t208.5 39.5q75 0 135.5 -15t107.5 -47t73 -85.5t26 -126.5q0 -87 -35 -138t-109 -51q-70 0 -116 53q37 19 65.5 75t28.5 114q0 55 -30 90t-95 35q-108 0 -208.5 -152t-159 -374t-58.5 -431 q0 -59 6.5 -105.5t23.5 -87.5t44.5 -68t70.5 -42.5t101 -15.5q119 0 223.5 54.5t175.5 150.5l47 -21q-39 -98 -110 -174.5t-154 -119.5t-164.5 -65t-155.5 -22q-232 0 -340 116.5t-108 387.5z" />
<glyph unicode="D" horiz-adv-x="1357" d="M12 995q0 104 61 203t163 173t244 119.5t294 45.5q144 0 252 -47.5t171 -131t93.5 -186.5t30.5 -225q0 -174 -46.5 -350.5t-123 -313.5t-182 -223t-215.5 -86q-124 0 -250 109l-17 -82h-294l278 1303l303 40l-246 -1148q55 -41 117 -41q71 0 134.5 54t109.5 144.5 t80.5 206.5t51.5 243.5t17 252.5q0 201 -79 294t-220 93q-234 0 -385 -135t-151 -363q0 -46 6.5 -76t14 -44.5t7.5 -18.5q-219 0 -219 190z" />
<glyph unicode="E" horiz-adv-x="940" d="M14 324q0 110 44.5 219.5t133 196.5t201.5 114q-125 89 -125 246q0 106 56.5 206.5t161.5 167t231 66.5q127 0 210 -67.5t83 -188.5q0 -91 -44.5 -152t-107.5 -61q-55 0 -96 55q37 12 63.5 68t26.5 111q0 58 -33 86t-80 28q-88 0 -148.5 -88.5t-60.5 -200.5 q0 -96 51.5 -171t155.5 -103q-79 -18 -149 -70.5t-116.5 -122t-73.5 -147.5t-27 -149q0 -93 47.5 -150t146.5 -57q102 0 214.5 57t164.5 152l47 -21q-78 -177 -245 -281t-355 -104q-95 0 -169 29t-118.5 79.5t-67 114.5t-22.5 138z" />
<glyph unicode="F" horiz-adv-x="940" d="M18 1004q0 84 23.5 160t77 144.5t133 118.5t199 79.5t266.5 29.5q35 0 152.5 -12.5t187.5 -12.5q105 0 184 25q-5 -14 -13.5 -45t-14.5 -50t-20 -46.5t-31 -45t-47 -34.5t-68 -25q-104 0 -287 39l-86 -407h299l-33 -152h-299l-166 -770h-295l295 1368q-63 -2 -109 -23 t-82.5 -67.5t-55.5 -130t-19 -203.5q0 -46 6.5 -76t14.5 -44.5t8 -18.5q-110 0 -165 46t-55 153z" />
<glyph unicode="G" horiz-adv-x="1183" d="M39 748q0 118 31 232t93 214.5t147.5 176.5t203 120.5t250.5 44.5q74 0 140 -15.5t121 -46.5t87.5 -85.5t32.5 -126.5q0 -87 -35 -138t-109 -51q-95 0 -141 53q35 10 62.5 67t27.5 101q0 14 -2 28.5t-10.5 37t-22.5 39t-41.5 29t-64.5 12.5q-109 0 -216 -108.5 t-173 -274.5t-66 -326q0 -148 59 -243t179 -95q117 0 174 76l88 389l264 -2l-168 -770q-27 -125 -64 -213t-97 -158t-150 -104.5t-213 -34.5q-137 0 -211 83.5t-74 199.5q0 112 67.5 196t182.5 84q31 0 53 -1.5t52.5 -9t49 -21.5t32.5 -40.5t14 -64.5q0 -36 -12 -82 q-37 31 -64 42t-59 11q-67 0 -105.5 -46.5t-38.5 -108.5q0 -58 34 -99t95 -41q37 0 64.5 10t54 36.5t48 77.5t38.5 128l82 367q-54 -28 -113.5 -46.5t-90.5 -23t-46 -4.5q-121 0 -209 41.5t-137 116t-71.5 165t-22.5 202.5z" />
<glyph unicode="H" horiz-adv-x="1361" d="M25 1004q0 132 107.5 256.5t274.5 200t336 75.5q28 0 82 -4l-131 -610h301l131 610h295l-325 -1532h-295l164 770h-301l-164 -770h-295l297 1393q-137 -58 -212 -173t-75 -276q0 -46 6.5 -76t14.5 -44.5t8 -18.5q-110 0 -164.5 46t-54.5 153z" />
<glyph unicode="I" horiz-adv-x="768" d="M12 1004q0 132 108 256.5t275 200t336 75.5q28 0 82 -4l-326 -1532h-294l296 1391q-136 -57 -211 -171t-75 -276q0 -46 6.5 -76t14 -44.5t7.5 -18.5q-110 0 -164.5 46t-54.5 153z" />
<glyph unicode="J" horiz-adv-x="1097" d="M35 -135q0 111 67 192.5t183 81.5q31 0 53 -1.5t52 -9t49 -21.5t32.5 -40.5t13.5 -64.5q0 -36 -12 -82q-37 31 -64 42t-59 11q-67 0 -105 -45t-38 -106q0 -72 43 -108t96 -36q50 0 82 18.5t61 74.5t52 159l321 1463q-136 -57 -212.5 -172.5t-76.5 -276.5q0 -46 6.5 -76 t14.5 -44.5t8 -18.5q-110 0 -164.5 46t-54.5 153q0 132 108 256.5t275 200t336 75.5h82l-307 -1454q-26 -123 -65.5 -212t-102 -157.5t-155.5 -102.5t-216 -34q-143 0 -223 79.5t-80 209.5z" />
<glyph unicode="K" horiz-adv-x="1230" d="M12 1004q0 132 108 256.5t275 200t336 75.5q28 0 82 -4l-133 -627q60 81 174.5 234.5t202.5 270.5t88 116h215l-569 -656q14 0 37 1t34 1q140 0 197 -58t57 -161q0 -89 -50 -273.5t-50 -244.5q0 -46 22 -84t58 -51q-120 -35 -203 -35q-160 0 -160 137q0 65 54.5 261.5 t54.5 277.5q0 139 -123 139q-18 0 -68 -8l-164 -772h-294l296 1393q-137 -58 -211.5 -173t-74.5 -276q0 -46 6.5 -76t14 -44.5t7.5 -18.5q-110 0 -164.5 46t-54.5 153z" />
<glyph unicode="L" horiz-adv-x="776" d="M12 983q0 99 64.5 197.5t166 171.5t232 118.5t256.5 45.5q15 0 82 -5l-315 -1470q57 -13 127 -45.5t134 -68.5t132.5 -70.5t145 -57t149.5 -22.5q94 0 172 33q-15 -148 -72.5 -235t-140.5 -87q-80 0 -170.5 48t-175.5 116t-172.5 136.5t-191.5 116.5t-204 48 q-31 0 -47 -2l305 1419q-136 -57 -211 -171t-75 -275q0 -46 6.5 -76t14 -45t7.5 -19q-110 0 -164.5 46t-54.5 153z" />
<glyph unicode="M" horiz-adv-x="1611" d="M137 0l520 1407q-155 -52 -240 -170.5t-85 -290.5q0 -48 6.5 -78.5t14 -44.5t7.5 -18q-219 0 -219 186q0 128 97.5 255.5t250 208.5t304.5 81q76 0 155 -29l-47 -1079l451 1079h295l-215 -1507h-295l131 920l-385 -920h-281l41 924l-342 -924h-164z" />
<glyph unicode="N" horiz-adv-x="1368" d="M12 1004q0 70 26 144.5t77.5 143.5t120 123.5t161.5 87.5t195 33q131 0 190 -29l162 -1085l223 1110h295l-325 -1532h-248l-174 1071l-228 -1071h-294l294 1391q-135 -56 -209.5 -171t-74.5 -276q0 -46 6.5 -76t14 -44.5t7.5 -18.5q-110 0 -164.5 46t-54.5 153z" />
<glyph unicode="O" horiz-adv-x="1361" d="M33 977q0 141 115 270.5t307 209t403 79.5q131 0 226.5 -38.5t151 -110t81.5 -164.5t26 -211q0 -87 -13.5 -181t-42.5 -194.5t-71.5 -193.5t-105 -176.5t-137.5 -145t-174.5 -97.5t-210.5 -36q-171 0 -269 98.5t-98 312.5q0 85 16 186.5t45.5 210t78 209t107.5 180 t139 127.5t169 48q55 0 107 -17q-89 -54 -174 -223.5t-135 -370.5t-50 -358q0 -110 29.5 -173.5t89.5 -63.5q100 0 201 145t164 362.5t63 421.5q0 95 -11 157.5t-39.5 110.5t-80 69.5t-131.5 21.5q-118 0 -224.5 -37t-188 -103.5t-129.5 -167t-48 -219.5q0 -48 11 -79 l10 -31q-207 0 -207 172z" />
<glyph unicode="P" horiz-adv-x="1173" d="M12 1004q0 132 108 256.5t275 200t336 75.5q122 0 216.5 -33t151.5 -90t86 -128t29 -152q0 -99 -41.5 -196t-115 -176t-187.5 -128t-247 -49h-11l-125 -584h-294l278 1303l303 40l-145 -684q75 6 143 55t114 121t73.5 159t27.5 169q0 123 -63 201t-191 78 q-249 0 -389.5 -132.5t-140.5 -365.5q0 -46 6.5 -76t14 -44.5t7.5 -18.5q-110 0 -164.5 46t-54.5 153z" />
<glyph unicode="Q" horiz-adv-x="1361" d="M33 977q0 141 115 270.5t307 209t403 79.5q131 0 226.5 -38.5t151 -110t81.5 -164.5t26 -211q0 -153 -39.5 -317.5t-131 -328.5t-220.5 -260q37 -52 65.5 -83t79 -56.5t111.5 -25.5q13 0 45 4q-37 -100 -88 -138t-123 -38q-52 0 -93 15t-66.5 36t-47.5 57.5t-32.5 65 t-24.5 73.5q-89 -28 -190 -28q-171 0 -269 98.5t-98 312.5q0 85 16 186.5t45.5 210t78 209t107.5 180t139 127.5t169 48q55 0 107 -17q-89 -54 -174 -223.5t-135 -370.5t-50 -358q0 -61 4 -88q78 19 127 19q91 0 164 -56q106 134 179 366.5t73 450.5q0 95 -11 157.5 t-39.5 110.5t-80 69.5t-131.5 21.5q-118 0 -224.5 -37t-188 -103.5t-129.5 -167t-48 -219.5q0 -48 11 -79l10 -31q-207 0 -207 172zM545 238q29 -84 98 -84q44 0 78 22q-43 70 -117 70q-28 0 -59 -8z" />
<glyph unicode="R" horiz-adv-x="1230" d="M12 1004q0 132 108 256.5t275 200t336 75.5q117 0 208.5 -27.5t146 -74t82.5 -104t28 -122.5q0 -96 -59 -192.5t-162 -157.5q141 -40 141 -205q0 -89 -50 -273.5t-50 -244.5q0 -46 22 -84t58 -51q-120 -35 -203 -35q-160 0 -160 137q0 65 54.5 261.5t54.5 277.5 q0 139 -123 139q-14 0 -68 -8l-164 -772h-294l278 1303l303 40l-100 -473h16q81 0 149.5 57t105 138.5t36.5 161.5q0 94 -56 154.5t-169 60.5q-251 0 -402 -133.5t-151 -364.5q0 -46 6.5 -76t14 -44.5t7.5 -18.5q-110 0 -164.5 46t-54.5 153z" />
<glyph unicode="S" horiz-adv-x="1167" d="M55 309q0 80 26.5 145.5t70.5 106t96.5 62.5t107.5 22q30 0 58.5 -6.5t56.5 -21t46 -42t20 -65.5q-44 0 -85 -10.5t-76.5 -32.5t-57 -60.5t-21.5 -89.5q0 -82 52 -139t145 -57q105 0 171 73t66 199q0 96 -43.5 184t-105 155.5t-123 132.5t-105 143t-43.5 161 q0 158 136.5 262.5t336.5 104.5q37 0 72 -3.5t84.5 -18.5t85.5 -40t62 -72.5t26 -111.5q0 -90 -46 -148.5t-122 -58.5q-57 0 -94 43q41 24 66.5 74.5t25.5 102.5q0 60 -36 98.5t-115 38.5q-87 0 -138 -48.5t-51 -138.5q0 -61 25.5 -114.5t66 -96t89.5 -84.5t98.5 -90 t90 -102t66 -130.5t25.5 -166.5q0 -125 -48 -224.5t-129 -161t-183 -94t-216 -32.5q-90 0 -166.5 20.5t-137.5 61.5t-95.5 110t-34.5 160z" />
<glyph unicode="T" horiz-adv-x="985" d="M12 1001q0 106 39 198.5t119.5 169t219 121t321.5 44.5q130 0 279.5 -23.5t244.5 -23.5q135 0 238 43q-6 -260 -256 -260q-118 0 -318 45l-283 -1315h-294l290 1356h-24q-69 0 -124 -11t-105 -40t-83.5 -74.5t-53 -118.5t-19.5 -170q0 -46 6.5 -76t14 -44.5t7.5 -18.5 q-110 0 -164.5 45.5t-54.5 152.5z" />
<glyph unicode="U" horiz-adv-x="1466" d="M0 993q0 85 42 167t116.5 149t171 118.5t212 80t232.5 28.5q44 0 98 -10q-32 -120 -74.5 -275t-64 -236t-49 -184t-40.5 -158.5t-26 -118.5t-17.5 -104.5t-4.5 -78.5q0 -185 141 -185q50 0 80.5 6t66.5 30t62.5 69.5t57.5 125t62 197t67 285.5l137 633h289l-136 -639 q-30 -145 -56.5 -247.5t-61 -204t-72 -168t-88.5 -125.5t-113 -92t-141 -51.5t-178 -18.5q-213 0 -304.5 81.5t-91.5 243.5q0 59 7 123.5t29.5 167.5t33.5 151t50 202t48 192l68 270q-170 -45 -266.5 -167t-96.5 -304q0 -48 6.5 -78.5t14.5 -44.5t8 -18q-219 0 -219 188z " />
<glyph unicode="V" horiz-adv-x="1259" d="M12 1004q0 132 108 256.5t275 200t336 75.5q28 0 82 -4l18 -1260l431 1254h143l-569 -1526h-312v1399q-321 -101 -321 -455q0 -46 6.5 -76t14 -44.5t7.5 -18.5q-110 0 -164.5 46t-54.5 153z" />
<glyph unicode="W" horiz-adv-x="1970" d="M12 1004q0 132 108 256.5t275 200t336 75.5q28 0 82 -4l18 -1260l431 1254h268v-1254l440 1254h144l-570 -1526h-303v1042l-405 -1042h-301v1399q-165 -52 -248.5 -168t-83.5 -287q0 -46 6.5 -76t14 -44.5t7.5 -18.5q-110 0 -164.5 46t-54.5 153z" />
<glyph unicode="X" horiz-adv-x="1269" d="M12 1004q0 132 108 256.5t275 200t336 75.5q28 0 82 -4l88 -426l238 420h143l-344 -596l192 -930h-325l-109 512l-297 -512h-125l385 680l-151 719q-144 -53 -224.5 -170.5t-80.5 -284.5q0 -46 6.5 -76t14 -44.5t7.5 -18.5q-110 0 -164.5 46t-54.5 153z" />
<glyph unicode="Y" horiz-adv-x="1269" d="M12 1004q0 132 108 256.5t275 200t336 75.5q28 0 82 -4l178 -733l303 727h136l-398 -895l-135 -631h-328l136 631l-197 768q-144 -53 -224.5 -170.5t-80.5 -284.5q0 -46 6.5 -76t14 -44.5t7.5 -18.5q-110 0 -164.5 46t-54.5 153z" />
<glyph unicode="Z" horiz-adv-x="1110" d="M23 0l716 1425q-18 0 -82 2.5t-102 2.5q-188 0 -188 -46q13 0 23.5 -16t10.5 -49q0 -61 -37 -89t-83 -28q-54 0 -79.5 36t-25.5 85q0 83 68 148t184 65h702l-706 -1403q25 0 93 -2t104 -2q180 0 213 45q-13 0 -25 15.5t-12 48.5q0 59 37.5 88.5t85.5 29.5 q53 0 78.5 -34.5t25.5 -83.5q0 -86 -73.5 -162t-188.5 -76h-739z" />
<glyph unicode="[" horiz-adv-x="819" d="M-49 -512l434 2048h395l-26 -127h-248l-381 -1794h248l-27 -127h-395z" />
<glyph unicode="\" horiz-adv-x="741" d="M86 1536h147l435 -2048h-148z" />
<glyph unicode="]" horiz-adv-x="819" d="M-49 -512l26 127h248l381 1794h-248l27 127h395l-434 -2048h-395z" />
<glyph unicode="^" horiz-adv-x="862" d="M102 1149l435 387h43l122 -387h-65l-123 164l-321 -164h-91z" />
<glyph unicode="_" horiz-adv-x="909" d="M74 0l37 162h716l-34 -162h-719z" />
<glyph unicode="`" horiz-adv-x="411" d="M49 1536h215l60 -387h-154z" />
<glyph unicode="a" horiz-adv-x="1077" d="M-27 317q0 71 14.5 149.5t42.5 159t73.5 153.5t101.5 130t132.5 91t162.5 34q84 0 125 -28.5t41 -75.5v-15l22 109h295l-147 -696q-9 -40 -9 -66q0 -88 84 -88q56 0 98 54t68 139h86q-133 -379 -411 -379q-87 0 -139.5 48.5t-61.5 139.5q-126 -188 -305 -188 q-43 0 -82 10.5t-74 35t-61 62t-41 94t-15 127.5zM276 346q0 -56 10 -91.5t28.5 -48.5t31.5 -16.5t33 -3.5q49 0 101 49t69 132l98 462q0 26 -20 52t-64 26q-62 0 -118 -60t-91.5 -148.5t-56.5 -183t-21 -169.5z" />
<glyph unicode="b" horiz-adv-x="909" d="M-14 250q0 57 14 117l219 1026l303 41l-98 -461q94 57 168 57q242 0 242 -350q0 -54 -8 -114t-27.5 -128t-48.5 -131t-74.5 -122t-102 -102t-134 -69t-167.5 -26q-139 0 -212.5 68.5t-73.5 193.5zM279 281q0 -95 108 -95q63 0 120 81t88.5 196.5t31.5 224.5 q0 81 -28.5 139t-80.5 58q-29 0 -67.5 -9.5t-53.5 -27.5l-112 -520q-6 -24 -6 -47z" />
<glyph unicode="c" horiz-adv-x="786" d="M-27 313q0 54 8.5 115.5t28.5 133t49 138.5t74 130t99.5 109.5t130 74.5t161.5 28q125 0 176.5 -53t51.5 -135q0 -72 -31 -110.5t-78 -38.5q-35 0 -72 24q25 70 25 121q0 84 -57 84q-61 0 -124 -103.5t-101 -244t-38 -254.5q0 -100 35 -136t113 -36q77 0 144.5 29.5 t113 69.5t104.5 108h70q-236 -379 -563 -379q-151 0 -235.5 79t-84.5 246z" />
<glyph unicode="d" horiz-adv-x="1075" d="M-27 317q0 71 14.5 149.5t42.5 159t73.5 153.5t101.5 130t132.5 91t162.5 34q84 0 125 -28.5t41 -75.5v-8l100 471l303 41l-235 -1106q-9 -40 -9 -66q0 -42 20 -59t64 -17q57 0 99 49.5t67 131.5h86q-33 -96 -77.5 -166t-85.5 -107.5t-89.5 -60t-83.5 -28t-75 -5.5 q-84 0 -136.5 45.5t-64.5 130.5q-122 -188 -303 -188q-43 0 -82 10.5t-74 35t-61 62t-41 94t-15 127.5zM276 346q0 -56 10 -91.5t28.5 -48.5t31.5 -16.5t33 -3.5q48 0 98.5 45.5t69.5 124.5v11l100 469q-4 26 -24 48.5t-60 22.5q-62 0 -118 -60t-91.5 -148.5t-56.5 -183 t-21 -169.5z" />
<glyph unicode="e" horiz-adv-x="786" d="M-27 313q0 53 8.5 114.5t28 133t48.5 138.5t74 130t100.5 110t131 75t162.5 28q226 0 226 -196q0 -115 -66.5 -212.5t-174 -155t-230.5 -64.5q-5 -72 -5 -82q0 -100 35 -136t113 -36q77 0 144.5 29.5t113 69.5t104.5 108h70q-236 -379 -563 -379q-151 0 -235.5 79 t-84.5 246zM297 512q119 8 208 109.5t89 228.5q0 84 -51 84q-50 0 -100.5 -64t-87.5 -158.5t-58 -199.5z" />
<glyph unicode="f" horiz-adv-x="546" d="M-426 -291q0 55 19 99t47.5 73t78.5 55.5t94 42.5t113 37l248 1170q18 84 50 148t68.5 101.5t82.5 60.5t86.5 30.5t85.5 7.5q97 0 169 -62t72 -159q0 -47 -6 -84h-96q4 40 4 55q0 34 -22.5 52t-55.5 18q-43 0 -83 -38t-60 -130l-35 -162h150l-15 -82h-151l-236 -1106 q-72 -348 -366 -348q-97 0 -169.5 62t-72.5 159zM-313 -262q0 -23 25 -45.5t57 -22.5q80 0 116 160l27 119q-108 -36 -166.5 -85t-58.5 -126z" />
<glyph unicode="g" horiz-adv-x="1038" d="M-27 317q0 71 14.5 149.5t42.5 159t73.5 153.5t101.5 130t132.5 91t162.5 34q84 0 125 -28.5t41 -75.5v-12l22 106h295l-203 -950q98 35 157.5 99.5t100.5 193.5h86q-23 -78 -56.5 -140t-68.5 -101.5t-78.5 -69t-79.5 -45t-79 -27.5l-31 -148q-72 -348 -369 -348 q-99 0 -164 51.5t-65 147.5q0 203 334 305l25 108q-105 -112 -246 -112q-43 0 -82 10.5t-74 35t-61 62t-41 94t-15 127.5zM246 -285q0 -24 19 -45.5t50 -21.5q34 0 67 47.5t52 134.5l12 59q-200 -75 -200 -174zM276 346q0 -56 10 -91.5t28.5 -48.5t31.5 -16.5t33 -3.5 q45 0 94.5 43.5t69.5 116.5l104 485q-2 26 -21.5 51t-62.5 25q-62 0 -118 -60t-91.5 -148.5t-56.5 -183t-21 -169.5z" />
<glyph unicode="h" d="M-78 0l297 1393l303 41l-110 -516q100 114 239 114q104 0 166 -56.5t62 -174.5q0 -89 -49.5 -283.5t-49.5 -245.5q0 -86 82 -86q61 0 96.5 43t75.5 138h86q-33 -97 -73.5 -168t-78.5 -110.5t-81.5 -63t-76.5 -30.5t-71 -7q-124 0 -182.5 66.5t-58.5 164.5q0 71 46 264 t46 258q0 105 -76 105q-53 0 -98.5 -63t-57.5 -117l-141 -666h-295z" />
<glyph unicode="i" horiz-adv-x="546" d="M-16 233q0 56 16 134l139 657h295l-147 -696q-8 -36 -8 -66q0 -42 19.5 -59t63.5 -17q59 0 110 51.5t75 129.5h86q-33 -95 -79 -167t-90.5 -111t-95.5 -63t-88.5 -31t-76.5 -7q-98 0 -158.5 61t-60.5 184zM180 1296q0 68 47.5 116t114.5 48q68 0 116 -48t48 -116 q0 -67 -48 -114t-116 -47t-115 47t-47 114z" />
<glyph unicode="j" horiz-adv-x="491" d="M-414 -313q0 204 336 305l219 1032h295l-203 -950q98 35 158 100t101 193h86q-29 -96 -71.5 -167.5t-94 -113.5t-97 -64.5t-100.5 -37.5l-31 -148q-72 -348 -368 -348q-99 0 -164.5 52t-65.5 147zM-301 -285q0 -24 19.5 -45.5t50.5 -21.5q34 0 66.5 47.5t51.5 134.5 l13 59q-201 -75 -201 -174zM164 1298q0 68 47.5 116t114.5 48t115 -48t48 -116q0 -67 -47.5 -114t-115.5 -47t-115 47t-47 114z" />
<glyph unicode="k" horiz-adv-x="1060" d="M-78 0l297 1393l303 41l-153 -721l395 311h203l-410 -285q52 9 68 9q109 0 167 -68t58 -172q0 -42 -8 -78l-23 -102q-10 -50 -10 -66q0 -76 80 -76q61 0 96.5 43t75.5 138h86q-33 -98 -75.5 -171t-80.5 -111.5t-82 -61.5t-74.5 -29t-64.5 -6q-126 0 -192 60t-66 173 q0 49 12 107l17 80q8 36 8 75q0 99 -74 99q-59 0 -151 -76l-107 -506h-295z" />
<glyph unicode="l" horiz-adv-x="546" d="M-16 233q0 56 16 134l219 1026l303 41l-235 -1106q-8 -36 -8 -66q0 -42 19.5 -59t63.5 -17q59 0 110 51.5t75 129.5h86q-33 -95 -79 -167t-90.5 -111t-95.5 -63t-88.5 -31t-76.5 -7q-98 0 -158.5 61t-60.5 184z" />
<glyph unicode="m" horiz-adv-x="1540" d="M-78 0l217 1024h295l-22 -106q102 116 250 116q178 0 210 -176q112 174 285 174q104 0 165.5 -56.5t61.5 -174.5q0 -89 -49 -283.5t-49 -245.5q0 -86 82 -86q61 0 96.5 43t75.5 138h86q-33 -97 -73.5 -168t-78.5 -110.5t-81.5 -63t-76.5 -30.5t-71 -7q-124 0 -182.5 66.5 t-58.5 164.5q0 71 46 264t46 258q0 105 -74 105q-52 0 -93.5 -53t-66.5 -136l-139 -657h-295l150 707q6 24 6 51q0 38 -15.5 64t-46.5 26q-56 0 -98 -53.5t-68 -137.5l-139 -657h-295z" />
<glyph unicode="n" d="M-78 0l217 1024h295l-22 -106q100 114 239 114q104 0 166 -56.5t62 -174.5q0 -89 -49.5 -283.5t-49.5 -245.5q0 -86 82 -86q61 0 96.5 43t75.5 138h86q-33 -97 -73.5 -168t-78.5 -110.5t-81.5 -63t-76.5 -30.5t-71 -7q-124 0 -182.5 66.5t-58.5 164.5q0 71 46 264t46 258 q0 105 -74 105q-52 0 -93.5 -53t-66.5 -136l-139 -657h-295z" />
<glyph unicode="h" horiz-adv-x="1034" d="M-78 0l297 1393l303 41l-110 -516q100 114 239 114q104 0 166 -56.5t62 -174.5q0 -89 -49.5 -283.5t-49.5 -245.5q0 -86 82 -86q61 0 96.5 43t75.5 138h86q-33 -97 -73.5 -168t-78.5 -110.5t-81.5 -63t-76.5 -30.5t-71 -7q-124 0 -182.5 66.5t-58.5 164.5q0 71 46 264 t46 258q0 105 -76 105q-53 0 -98.5 -63t-57.5 -117l-141 -666h-295z" />
<glyph unicode="o" horiz-adv-x="899" d="M-29 315q0 53 8.5 114.5t29 132.5t50 138.5t75.5 130t102 109t132.5 74.5t163.5 28q263 0 263 -327q8 -4 22 -4q66 0 155 36.5t161 86.5l18 -56q-58 -62 -153.5 -106.5t-209.5 -63.5q-24 -280 -160.5 -448t-328.5 -168q-152 0 -240 78t-88 245zM276 342 q0 -99 22.5 -132.5t82.5 -33.5q75 0 143.5 122.5t93.5 303.5q-55 13 -55 86q0 83 64 111q-3 65 -20.5 92t-57.5 27q-68 0 -133.5 -103t-102.5 -236.5t-37 -236.5z" />
<glyph unicode="p" horiz-adv-x="958" d="M-186 -512l342 1612h295l-33 -154q102 88 239 88q114 0 182 -75.5t68 -247.5q0 -74 -10 -150t-32 -159.5t-61.5 -156t-93 -131t-132.5 -92.5t-175 -34q-131 0 -174 73l-106 -499zM262 213q16 -47 78 -47q61 0 112 39t82.5 99t53 136t30.5 145.5t9 131.5q0 170 -103 170 q-35 0 -74 -26.5t-67 -74.5z" />
<glyph unicode="q" horiz-adv-x="995" d="M-27 317q0 71 14.5 149.5t42.5 159t73.5 153.5t101.5 130t132.5 91t162.5 34q84 0 125 -29t41 -79l20 98h295l-311 -1462l-310 -74l129 612q-105 -112 -243 -112q-43 0 -82 10.5t-74 35t-61 62t-41 94t-15 127.5zM276 346q0 -56 10 -91.5t28.5 -48.5t31.5 -16.5t33 -3.5 q43 0 90 39t70 107l108 506q-4 25 -24.5 47t-59.5 22q-62 0 -118 -60t-91.5 -148.5t-56.5 -183t-21 -169.5z" />
<glyph unicode="r" horiz-adv-x="770" d="M-78 0l217 1024h295l-26 -127q49 42 76.5 62.5t76 42.5t94.5 22q66 0 104 -45.5t37 -108.5q0 -59 -38.5 -104t-108.5 -45q-32 0 -50.5 14t-24 33.5t-9 39.5t-11 34t-24.5 14q-42 0 -73 -18t-76 -60l-164 -778h-295z" />
<glyph unicode="s" horiz-adv-x="782" d="M-66 250q0 66 32 117t77 73q138 244 252 607l303 40q11 -224 22.5 -387.5t17 -233.5t5.5 -124q0 -45 -8 -78q87 52 147 103h86q-127 -147 -313 -256q-60 -63 -147.5 -93t-174.5 -30q-75 0 -134.5 23t-94 61.5t-52.5 83.5t-18 94zM43 293q0 -73 29.5 -108t95.5 -35 q76 0 127 45.5t51 144.5q0 51 -14.5 186t-24.5 299q-51 -165 -166 -387q47 -21 47 -71q0 -39 -26 -70t-64 -31q-42 0 -55 27z" />
<glyph unicode="t" horiz-adv-x="546" d="M-16 233q0 56 16 134l123 575h-68l17 82h67l62 283l303 41l-70 -324h123l-16 -82h-123l-131 -614q-8 -36 -8 -66q0 -42 19.5 -59t63.5 -17q59 0 110 51.5t75 129.5h86q-33 -95 -79 -167t-90.5 -111t-95.5 -63t-88.5 -31t-76.5 -7q-98 0 -158.5 61t-60.5 184z" />
<glyph unicode="u" d="M-16 233q0 56 16 134l139 657h295l-147 -696q-6 -30 -6 -58q0 -84 61 -84q109 0 164 181l139 657h295l-147 -696q-9 -40 -9 -66q0 -42 20 -59t64 -17q57 0 99 49.5t67 131.5h86q-133 -379 -411 -379q-88 0 -141 49.5t-62 144.5q-118 -194 -303 -194q-98 0 -158.5 61 t-60.5 184z" />
<glyph unicode="v" horiz-adv-x="847" d="M-18 229q0 50 10 99l147 696h295l-147 -696q-11 -53 -11 -74q0 -68 70 -68q58 0 114 49.5t98 127t75 169.5t50 181t17 157q-4 -9 -26 -14.5t-39 -5.5q-34 0 -54 33t-20 71q0 50 32.5 80.5t94.5 30.5q68 0 98.5 -50.5t30.5 -127.5q0 -85 -14.5 -180.5t-43.5 -198 t-77.5 -194.5t-111 -165.5t-149.5 -117t-188 -43.5q-119 0 -185 61t-66 180z" />
<glyph unicode="w" horiz-adv-x="1353" d="M-16 233q0 56 16 134l139 657h295l-147 -696q-6 -24 -6 -52q0 -90 61 -90q109 0 164 181l139 657h295l-147 -696q-11 -53 -11 -74q0 -68 70 -68q58 0 114 49.5t98 127t75 169.5t50 181t17 157q-4 -9 -26 -14.5t-39 -5.5q-34 0 -54 33t-20 71q0 50 32.5 80.5t94.5 30.5 q68 0 98.5 -50.5t30.5 -127.5q0 -85 -14.5 -180.5t-43.5 -198t-77.5 -194.5t-111 -165.5t-149.5 -117t-188 -43.5t-163.5 43.5t-81.5 128.5q-117 -172 -291 -172q-98 0 -158.5 61t-60.5 184z" />
<glyph unicode="x" horiz-adv-x="1069" d="M0 367q20 98 48 186.5t70.5 178.5t94 155t121.5 106t149 41q58 0 101.5 -22.5t67 -61t36 -76.5t17.5 -83l18 -156q173 194 178 295q-24 -4 -35 -4q-96 0 -96 114q0 50 39.5 75.5t99.5 25.5q53 0 84 -57t31 -130q0 -89 -60.5 -177.5t-224.5 -268.5l19 -143 q12 -98 42 -138.5t85 -40.5q59 0 109.5 51.5t74.5 129.5h86q-32 -91 -75 -160.5t-85.5 -110t-91 -66t-87.5 -34t-79 -8.5q-192 0 -250 356l-282 -344h-148l414 467l-33 229q-14 99 -31.5 134.5t-46.5 35.5q-66 0 -144.5 -131t-129.5 -368h-86z" />
<glyph unicode="y" horiz-adv-x="995" d="M-16 233q0 56 16 134l139 657h295l-147 -696q-6 -24 -6 -52q0 -90 61 -90q54 0 94.5 45.5t65.5 122.5l143 670h295l-203 -950q98 35 157.5 99.5t100.5 193.5h86q-23 -78 -56.5 -140t-68.5 -101.5t-78.5 -69t-79.5 -45t-79 -27.5l-31 -148q-72 -348 -369 -348 q-99 0 -164 51.5t-65 147.5q0 203 334 305l25 110q-102 -114 -246 -114q-98 0 -158.5 61t-60.5 184zM203 -285q0 -24 19 -45.5t50 -21.5q34 0 67 47.5t52 134.5l12 59q-200 -75 -200 -174z" />
<glyph unicode="z" horiz-adv-x="876" d="M0 0l522 913h-114q-56 0 -84.5 -6t-28.5 -26q0 -3 5.5 -5t11 -10.5t5.5 -29.5q0 -53 -33 -81t-77 -28q-38 0 -66 24t-28 66q0 71 68 139t169 68h527l-502 -866q7 0 65 -6.5t90 -6.5q90 0 97 41q-39 3 -39 43q0 32 30.5 60t83.5 28q44 0 67.5 -27.5t23.5 -70.5 q0 -79 -70 -149t-180 -70h-543z" />
<glyph unicode="{" horiz-adv-x="720" d="M61 -287q0 65 30.5 150t69 157t81 167t59.5 171q6 24 6 45q0 64 -84 64q-25 0 -65 -6l24 117q44 -7 64 -7q38 0 64.5 15.5t40.5 36.5t21.5 55t9 59.5t1.5 61.5q0 58 -7 166t-7 159q0 50 10 103t35 109t61 100t93.5 72t127.5 28h88l-18 -102q-72 0 -113.5 -10t-72.5 -44 q-52 -58 -72.5 -125t-22.5 -157l13 -350q-6 -164 -82 -228q24 -27 24 -74q0 -60 -38 -157t-83.5 -184t-83.5 -188.5t-38 -170.5q0 -164 174 -164l-19 -92h-18q-105 0 -151 14t-83 72q-39 58 -39 137z" />
<glyph unicode="|" horiz-adv-x="1089" d="M449 -512v2050h190v-2050h-190z" />
<glyph unicode="}" horiz-adv-x="720" d="M61 -510l19 102q72 0 113.5 10t72.5 44q52 58 72 124.5t22 157.5l-12 351q5 163 82 227q-24 27 -24 74q0 60 38 157t83.5 184t83.5 188.5t38 170.5q0 164 -174 164l19 92h18q105 0 150.5 -14t82.5 -72q39 -58 39 -137q0 -65 -30.5 -150t-69 -157t-80.5 -167t-59 -171 q-6 -24 -6 -45q0 -64 84 -64q25 0 65 6l-24 -116q-38 6 -64 6q-38 0 -64.5 -15.5t-40.5 -36.5t-21.5 -55t-9 -59.5t-1.5 -61.5q0 -58 7 -166t7 -159q0 -50 -10 -103t-35 -109t-61 -100t-93.5 -72t-127.5 -28h-89z" />
<glyph unicode="~" horiz-adv-x="882" d="M100 1192q49 98 137 149.5t205 51.5q79 0 180.5 -34t157.5 -34q85 0 129 47l13 -2q-18 -75 -117.5 -140t-212.5 -65q-70 0 -180 38t-164 38q-79 0 -135 -53z" />
<glyph unicode="&#xa1;" horiz-adv-x="448" d="M-125 -508l266 961h174l-145 -961h-295zM121 762q0 68 47.5 116t114.5 48t115 -48t48 -116q0 -67 -47.5 -114.5t-115.5 -47.5q-67 0 -114.5 47t-47.5 115z" />
<glyph unicode="&#xa2;" horiz-adv-x="825" d="M63 647q0 141 48 262.5t146.5 206.5t231.5 103l46 251h118l-55 -249q81 -5 132.5 -38.5t51.5 -101.5q0 -33 -10 -67h-117q11 42 11 57q0 70 -76 70h-10l-156 -703q10 -2 31 -2q40 0 76 10.5t72.5 34t59 41.5t62.5 53q-45 -267 -332 -278l-78 -352h-55l64 354 q-112 16 -186.5 107t-74.5 241zM279 653q0 -55 18.5 -105t56.5 -79l113 625q-82 -64 -135 -190t-53 -251z" />
<glyph unicode="&#xa3;" horiz-adv-x="952" d="M51 686q67 136 215 182l148 605l307 63l-164 -678q8 -2 32.5 -10.5t35.5 -11.5t31.5 -8t38 -7t36.5 -2q85 0 129 47l12 -2q-18 -75 -117 -140t-212 -65h-33l-115 -473q32 4 101.5 6.5t111.5 7.5t115.5 36t150.5 88q-15 -148 -72 -236t-140 -88h-605l176 733q-5 0 -16.5 1 t-17.5 1q-80 0 -136 -53z" />
<glyph unicode="&#xa4;" horiz-adv-x="1024" d="M139 1008l78 73l115 -114q83 61 186 61q101 0 182 -59l115 114l74 -73l-113 -113q62 -84 62 -188q0 -103 -62 -187l113 -112l-74 -74l-113 113q-83 -60 -184 -60q-104 0 -188 62l-115 -115l-74 74l115 114q-59 81 -59 183q0 103 59 184zM313 709q0 -85 60 -145t145 -60 t145 60t60 145t-60 144.5t-145 59.5t-145 -59.5t-60 -144.5z" />
<glyph unicode="&#xa5;" horiz-adv-x="970" d="M39 291l29 102h196l29 133h-203l29 103h196l-229 907h336l180 -739l307 739h135l-401 -907h268l-28 -103h-262l-29 -133h268l-29 -102h-262l-61 -291h-328l62 291h-203z" />
<glyph unicode="&#xa6;" horiz-adv-x="1089" d="M449 455h190v-967h-190v967zM449 616v922h190v-922h-190z" />
<glyph unicode="&#xa7;" horiz-adv-x="1110" d="M16 158q0 111 56.5 181.5t140.5 70.5q38 0 72 -18.5t49.5 -35.5t40.5 -49q-91 -7 -128.5 -42.5t-37.5 -112.5q0 -81 39.5 -120.5t128.5 -39.5q78 0 121 48.5t43 149.5q0 68 -20.5 125.5t-53 99t-71.5 78.5t-78.5 71t-72 69.5t-53 82t-20.5 99.5q0 95 59 170t154 111 q-10 45 -10 86q0 88 38.5 157.5t101.5 111.5t138.5 63.5t155.5 21.5q29 0 57.5 -2.5t68.5 -14.5t69 -31.5t50 -57.5t21 -89q0 -72 -36.5 -118.5t-98.5 -46.5q-46 0 -76 32q33 20 53.5 60.5t20.5 81.5q0 46 -29 78t-86 32q-82 0 -137 -65.5t-55 -153.5q0 -51 22.5 -96 t58 -79.5t79 -68t86.5 -71t78.5 -79t58 -99.5t22.5 -127q0 -79 -27 -150.5t-82 -124t-128 -67.5q0 -182 -118 -286t-327 -104q-43 0 -82 4.5t-88.5 21.5t-84.5 44.5t-59 78.5t-24 120zM389 924q0 -47 34.5 -94t87 -92t107 -94.5t102.5 -119.5t66 -149q39 48 39 129 q0 67 -29 123.5t-76.5 100.5t-98.5 82t-106 87t-87 98q-39 -20 -39 -71z" />
<glyph unicode="&#xa8;" horiz-adv-x="802" d="M115 1298q0 51 36.5 88t88.5 37q51 0 88 -37t37 -88q0 -52 -37 -88t-88 -36q-53 0 -89 36t-36 88zM483 1298q0 51 36.5 88t88.5 37q51 0 88 -37t37 -88q0 -52 -37 -88t-88 -36q-53 0 -89 36t-36 88z" />
<glyph unicode="&#xa9;" horiz-adv-x="1202" d="M104 678q0 144 67.5 265t181.5 190t247 69t247 -68.5t181.5 -189t67.5 -264.5t-67.5 -265t-181.5 -190t-247 -69t-247 69t-181.5 189.5t-67.5 263.5zM199 678q0 -183 119 -309.5t286 -126.5q166 0 285 126.5t119 309.5t-119 309.5t-285 126.5q-167 0 -286 -126.5 t-119 -309.5zM311 688q0 129 88.5 216t214.5 87q95 -4 164.5 -58t89.5 -136l-96 -37q-7 26 -14 41.5t-23.5 38t-46 34t-70.5 11.5q-82 0 -138 -48.5t-56 -138.5q0 -92 56 -155.5t138 -63.5q48 0 89.5 24.5t64.5 67.5l90 -59q-43 -65 -110 -102t-142 -37q-124 0 -211.5 93.5 t-87.5 221.5z" />
<glyph unicode="&#xaa;" horiz-adv-x="706" d="M88 1096q0 60 9 116.5t32 112t57.5 96.5t89 66.5t123.5 25.5q40 0 80 -28l6 31h170l-86 -377q-6 -36 -6 -37q0 -41 43 -41q21 0 31 4q-15 -45 -38.5 -69t-41 -28.5t-43.5 -4.5q-99 0 -119 81q-72 -88 -162 -88q-77 0 -111 41t-34 99zM248 1126q0 -77 69 -77q35 0 74 53 l76 330q-23 20 -59 20q-42 0 -80 -50.5t-59 -125.5t-21 -150z" />
<glyph unicode="&#xab;" horiz-adv-x="1206" d="M41 487l18 84l629 308l-20 -113l-494 -246l397 -196l-24 -117zM471 487l18 84l629 308l-20 -113l-494 -246l397 -196l-24 -117z" />
<glyph unicode="&#xac;" horiz-adv-x="909" d="M39 455l37 161h741l-104 -512h-232l72 351h-514z" />
<glyph unicode="&#xad;" horiz-adv-x="593" d="M39 455l37 161h409l-34 -161h-412z" />
<glyph unicode="&#xae;" horiz-adv-x="1132" d="M70 684q0 108 39.5 205.5t106.5 167t158 110.5t191 41q133 0 247 -68.5t181.5 -189t67.5 -264.5t-67.5 -265t-181.5 -190t-247 -69q-100 0 -191 41t-158 110.5t-106.5 166.5t-39.5 204zM164 684q0 -183 119 -309.5t286 -126.5q166 0 285 126.5t119 309.5t-119 309.5 t-285 126.5q-167 0 -286 -126.5t-119 -309.5zM360 393l2 596h193q110 0 178 -45.5t68 -126.5q0 -57 -33.5 -100t-87.5 -58l133 -256l-96 -14l-127 256h-135v-252h-95zM455 723h106q36 0 65.5 6t55 27.5t25.5 56.5q0 49 -44.5 70.5t-105.5 21.5h-102v-182z" />
<glyph unicode="&#xb0;" horiz-adv-x="643" d="M76 999q0 187 91 313t241 126q87 0 127 -58.5t40 -173.5q0 -68 -20.5 -142.5t-57 -142t-96 -111.5t-129.5 -44q-113 0 -154.5 57t-41.5 176zM223 975q0 -133 56 -133q53 0 93 56t60.5 145t20.5 194q0 129 -52 129q-50 0 -106.5 -83.5t-67.5 -219.5q-4 -50 -4 -88z" />
<glyph unicode="&#xb1;" horiz-adv-x="1091" d="M63 139l37 162h752l-35 -162h-754zM170 633l49 229h262l56 250h231l-55 -250h260l-47 -229h-262l-56 -252h-231l55 252h-262z" />
<glyph unicode="&#xb2;" horiz-adv-x="614" d="M6 739q0 66 40.5 130t97.5 118t114.5 110.5t98 131t40.5 155.5q0 38 -22 64.5t-49 26.5q-56 0 -76.5 -22t-20.5 -67q0 -24 11 -47t34 -28q-45 -39 -92 -39q-37 0 -60.5 26t-23.5 74q0 65 61 113.5t185 48.5q225 0 225 -176q0 -70 -34 -132.5t-88 -111t-110 -90 t-111 -87.5t-81 -85h9q38 0 114 -10.5t117 -10.5q16 0 29.5 1.5t26 6t20 7.5t20 12.5t17.5 13.5t20 18t21 19q0 -37 -0.5 -57t-3.5 -47t-8.5 -40.5t-15.5 -29.5t-25 -23.5t-37 -12.5t-52 -5q-65 0 -149 20.5t-144 20.5q-13 0 -30.5 -6t-37 -15.5t-26.5 -11.5q-4 24 -4 37z " />
<glyph unicode="&#xb3;" horiz-adv-x="647" d="M27 879q0 79 36.5 123.5t104.5 44.5q82 0 96 -56q-34 -3 -56.5 -15.5t-32 -33t-12.5 -39t-3 -43.5q0 -52 26.5 -71t77.5 -19q63 0 104.5 58.5t41.5 134.5q0 68 -38.5 124.5t-115.5 81.5q96 23 149.5 88.5t53.5 131.5q0 38 -20 62t-56 24q-107 0 -107 -89q0 -24 11.5 -47 t34.5 -28q-45 -39 -93 -39q-37 0 -60.5 26t-23.5 74q0 64 66 113t190 49q98 0 153.5 -47t55.5 -115q0 -59 -40.5 -113.5t-120.5 -91.5q147 -44 147 -180q0 -105 -89.5 -196t-215.5 -91q-44 0 -83 6t-83.5 23t-71 55.5t-26.5 94.5z" />
<glyph unicode="&#xb4;" horiz-adv-x="647" d="M246 1149l186 387h215l-248 -387h-153z" />
<glyph unicode="&#xb5;" d="M-150 -340l289 1364h295l-147 -696q-6 -24 -6 -52q0 -39 14.5 -64.5t46.5 -25.5q109 0 164 181l139 657h295l-147 -696q-9 -40 -9 -66q0 -42 20 -59t64 -17q57 0 99 49.5t67 131.5h86q-33 -96 -77.5 -166t-85.5 -107.5t-89.5 -60t-83.5 -28t-75 -5.5q-86 0 -139 47.5 t-62 136.5q-113 -180 -293 -184l-55 -266z" />
<glyph unicode="&#xb6;" horiz-adv-x="1110" d="M147 1006q0 77 20.5 152.5t63 143.5t102 119.5t144 82t182.5 30.5q80 0 146 -18.5t119.5 -57t83.5 -105.5t30 -157q0 -62 -16 -147l-260 -1215h-193l166 778q-33 -11 -88 -22l-158 -756h-192l158 756q-148 29 -228 146t-80 270zM670 694h12q41 0 72 8l98 465 q12 59 12 101q0 85 -47 129z" />
<glyph unicode="&#xb7;" horiz-adv-x="888" d="M246 547q0 82 57 140t139 58t140.5 -58t58.5 -140t-58.5 -139.5t-140.5 -57.5t-139 57.5t-57 139.5z" />
<glyph unicode="&#xb8;" horiz-adv-x="464" d="M0 -389q35 65 82 65q45 0 85.5 -27.5t65.5 -27.5q26 0 44 26.5t18 59.5q0 31 -20 52.5t-60 21.5q-48 0 -106 -25l108 303l72 -47l-60 -147q66 16 109 16q63 0 95 -27t32 -75q0 -104 -74.5 -164.5t-171.5 -60.5q-70 0 -117.5 14t-101.5 43z" />
<glyph unicode="&#xb9;" horiz-adv-x="444" d="M45 707l158 690h-113l14 51q148 0 302 86l-189 -827h-172z" />
<glyph unicode="&#xba;" horiz-adv-x="673" d="M86 1137q0 98 25.5 174t69.5 122t99 69.5t117 23.5q45 0 79 -14t34 -35q0 -37 -53 -54q-16 39 -54 39q-41 0 -73.5 -36t-50 -89t-26.5 -103t-9 -87q0 -47 22 -65.5t62 -18.5q50 0 80 65.5t41 155.5q-31 8 -31 45q0 30 25.5 57t54.5 27q22 0 30.5 -8t8.5 -31q14 8 23.5 17 t22.5 25t21 24l12 -23q-27 -87 -79 -117q-4 -82 -30.5 -150t-65 -109.5t-82.5 -64t-87 -22.5q-96 0 -141 43t-45 140z" />
<glyph unicode="&#xbb;" horiz-adv-x="1200" d="M31 207l28 117l492 196l-397 246l18 113l504 -308l-23 -110zM485 207l29 117l492 196l-398 246l19 113l503 -308l-22 -110z" />
<glyph unicode="&#xbc;" horiz-adv-x="1411" d="M143 461l158 690h-113l15 51q147 0 301 86l-189 -827h-172zM285 -338l540 1874h148l-541 -1874h-147zM766 307q14 41 60 129t79 172t33 156q0 36 -8 67q56 0 94.5 -27t38.5 -77q0 -49 -20 -99t-44 -84t-58.5 -81t-51.5 -76h184l96 422l177 22l-103 -444h78l-25 -80h-71 l-70 -305h-170l70 305h-289z" />
<glyph unicode="&#xbd;" horiz-adv-x="1382" d="M143 461l158 690h-113l15 51q147 0 301 86l-189 -827h-172zM274 -338l541 1874h148l-541 -1874h-148zM750 43q0 49 21.5 96t56 86.5t76.5 79.5t83.5 82t76 86t56 99.5t21.5 115.5q0 38 -22 64t-50 26q-56 0 -76 -21.5t-20 -66.5q0 -24 11.5 -47.5t33.5 -28.5 q-45 -39 -92 -39q-37 0 -60.5 26.5t-23.5 74.5q0 66 60.5 114t184.5 48q226 0 226 -176q0 -70 -34 -132.5t-88 -111t-110 -90t-111 -87.5t-81 -85h8q37 0 114 -10.5t117 -10.5q16 0 29.5 1.5t26 6t20 7.5t20 12.5t17.5 13.5t20 18t21 19q0 -52 -1.5 -77.5t-8.5 -57.5 t-21.5 -46t-41.5 -24t-68 -10q-65 0 -149 20.5t-144 20.5q-13 0 -30.5 -6t-37 -15.5t-26.5 -11.5q-4 24 -4 37z" />
<glyph unicode="&#xbe;" horiz-adv-x="1677" d="M125 633q0 79 36.5 123.5t104.5 44.5q82 0 96 -56q-34 -3 -56.5 -15.5t-32 -33t-12.5 -39t-3 -43.5q0 -52 26.5 -71t77.5 -19q63 0 104.5 58.5t41.5 134.5q0 68 -38.5 125t-115.5 82q96 23 149.5 88.5t53.5 130.5q0 38 -20 62t-56 24q-106 0 -106 -88q0 -24 11.5 -47.5 t33.5 -28.5q-45 -39 -92 -39q-37 0 -60.5 26t-23.5 74q0 64 66 113t190 49q98 0 153.5 -47t55.5 -115q0 -58 -41 -112.5t-121 -91.5q75 -22 111 -70t36 -111q0 -105 -89.5 -195.5t-215.5 -90.5q-264 0 -264 178zM522 -338l541 1874h147l-540 -1874h-148zM1010 307 q14 41 60 129t79 172t33 156q0 36 -8 67q56 0 94.5 -27t38.5 -77q0 -49 -20 -99t-44 -84t-58.5 -81t-51.5 -76h184l96 422l176 22l-102 -444h78l-25 -80h-72l-69 -305h-170l69 305h-288z" />
<glyph unicode="&#xbf;" horiz-adv-x="899" d="M25 -262q0 78 20 142.5t55 112t77.5 88.5t91.5 80.5t93.5 79.5t87 95t68.5 117h135q0 -58 -20.5 -113t-53.5 -99.5t-72.5 -88.5t-79 -88.5t-72.5 -91t-53.5 -105t-20.5 -121.5q0 -71 32 -106t80 -35q62 0 113 48.5t51 121.5q0 42 -19.5 83t-58.5 52q26 42 66 64t84 22 q64 0 109.5 -45t45.5 -127q0 -55 -24.5 -110.5t-73.5 -106t-135.5 -82t-196.5 -31.5q-329 0 -329 244zM473 762q0 69 47.5 117.5t114.5 48.5q68 0 116 -48.5t48 -117.5q0 -67 -48 -114.5t-116 -47.5q-67 0 -114.5 47t-47.5 115z" />
<glyph unicode="&#xc0;" horiz-adv-x="1368" d="M18 686q0 105 119 178.5t299 73.5q42 0 107 -6q80 127 165.5 233.5t177 191t187 132t182.5 47.5q91 0 162 -29l-321 -1507h-295l157 743q-137 62 -274 74q-116 -252 -191 -514.5t-75 -421.5q0 -72 28 -114q-31 0 -50.5 0.5t-51.5 5t-53 12.5t-45.5 24t-39 38.5 t-24.5 57.5t-10 79q0 137 83.5 367t217.5 466q-204 -13 -240 -106q8 0 17.5 -21.5t9.5 -42.5q0 -36 -33 -58t-82 -22q-55 0 -91 30.5t-36 88.5zM727 905q148 -29 250 -71l119 557q-171 -92 -369 -486zM895 2048h215l59 -387h-153z" />
<glyph unicode="&#xc1;" horiz-adv-x="1368" d="M18 686q0 105 119 178.5t299 73.5q42 0 107 -6q80 127 165.5 233.5t177 191t187 132t182.5 47.5q91 0 162 -29l-321 -1507h-295l157 743q-137 62 -274 74q-116 -252 -191 -514.5t-75 -421.5q0 -72 28 -114q-31 0 -50.5 0.5t-51.5 5t-53 12.5t-45.5 24t-39 38.5 t-24.5 57.5t-10 79q0 137 83.5 367t217.5 466q-204 -13 -240 -106q8 0 17.5 -21.5t9.5 -42.5q0 -36 -33 -58t-82 -22q-55 0 -91 30.5t-36 88.5zM727 905q148 -29 250 -71l119 557q-171 -92 -369 -486zM995 1661l187 387h215l-248 -387h-154z" />
<glyph unicode="&#xc2;" horiz-adv-x="1368" d="M18 686q0 105 119 178.5t299 73.5q42 0 107 -6q80 127 165.5 233.5t177 191t187 132t182.5 47.5q91 0 162 -29l-321 -1507h-295l157 743q-137 62 -274 74q-116 -252 -191 -514.5t-75 -421.5q0 -72 28 -114q-31 0 -50.5 0.5t-51.5 5t-53 12.5t-45.5 24t-39 38.5 t-24.5 57.5t-10 79q0 137 83.5 367t217.5 466q-204 -13 -240 -106q8 0 17.5 -21.5t9.5 -42.5q0 -36 -33 -58t-82 -22q-55 0 -91 30.5t-36 88.5zM727 905q148 -29 250 -71l119 557q-171 -92 -369 -486zM834 1661l434 387h43l123 -387h-66l-123 164l-321 -164h-90z" />
<glyph unicode="&#xc3;" horiz-adv-x="1368" d="M18 686q0 105 119 178.5t299 73.5q42 0 107 -6q80 127 165.5 233.5t177 191t187 132t182.5 47.5q91 0 162 -29l-321 -1507h-295l157 743q-137 62 -274 74q-116 -252 -191 -514.5t-75 -421.5q0 -72 28 -114q-31 0 -50.5 0.5t-51.5 5t-53 12.5t-45.5 24t-39 38.5 t-24.5 57.5t-10 79q0 137 83.5 367t217.5 466q-204 -13 -240 -106q8 0 17.5 -21.5t9.5 -42.5q0 -36 -33 -58t-82 -22q-55 0 -91 30.5t-36 88.5zM727 905q148 -29 250 -71l119 557q-171 -92 -369 -486zM838 1704q49 98 137 149.5t205 51.5q79 0 180.5 -34t157.5 -34 q85 0 129 47l12 -2q-18 -75 -117.5 -140t-212.5 -65q-70 0 -180 38t-164 38q-79 0 -135 -53z" />
<glyph unicode="&#xc4;" horiz-adv-x="1368" d="M18 686q0 105 119 178.5t299 73.5q42 0 107 -6q80 127 165.5 233.5t177 191t187 132t182.5 47.5q91 0 162 -29l-321 -1507h-295l157 743q-137 62 -274 74q-116 -252 -191 -514.5t-75 -421.5q0 -72 28 -114q-31 0 -50.5 0.5t-51.5 5t-53 12.5t-45.5 24t-39 38.5 t-24.5 57.5t-10 79q0 137 83.5 367t217.5 466q-204 -13 -240 -106q8 0 17.5 -21.5t9.5 -42.5q0 -36 -33 -58t-82 -22q-55 0 -91 30.5t-36 88.5zM727 905q148 -29 250 -71l119 557q-171 -92 -369 -486zM881 1810q0 51 36.5 88t88.5 37q51 0 87.5 -37t36.5 -88 q0 -52 -36.5 -88t-87.5 -36q-53 0 -89 36t-36 88zM1249 1810q0 51 36.5 88t88.5 37q51 0 88 -37t37 -88q0 -52 -37 -88t-88 -36q-53 0 -89 36t-36 88z" />
<glyph unicode="&#xc5;" horiz-adv-x="1368" d="M18 686q0 105 119 178.5t299 73.5q42 0 107 -6q80 127 165.5 233.5t177 191t187 132t182.5 47.5q91 0 162 -29l-321 -1507h-295l157 743q-137 62 -274 74q-116 -252 -191 -514.5t-75 -421.5q0 -72 28 -114q-31 0 -50.5 0.5t-51.5 5t-53 12.5t-45.5 24t-39 38.5 t-24.5 57.5t-10 79q0 137 83.5 367t217.5 466q-204 -13 -240 -106q8 0 17.5 -21.5t9.5 -42.5q0 -36 -33 -58t-82 -22q-55 0 -91 30.5t-36 88.5zM727 905q148 -29 250 -71l119 557q-171 -92 -369 -486zM993 1786q0 29 10.5 60.5t30 60t54.5 47t79 18.5q72 0 110 -44t38 -113 q0 -74 -44.5 -123.5t-133.5 -49.5q-64 0 -104 42t-40 102zM1075 1790q0 -76 70 -76q46 0 70 25t24 69q0 20 -1.5 32.5t-7.5 29.5t-21 26t-38 9q-49 0 -72.5 -35t-23.5 -80z" />
<glyph unicode="&#xc6;" horiz-adv-x="1564" d="M18 696q0 61 55.5 116t148 87.5t196.5 32.5q54 0 121 -6q81 129 166 236.5t177 193.5t187.5 134t183.5 48q53 0 173.5 -20.5t195.5 -20.5q119 0 240 39q-3 -9 -10.5 -34.5t-12 -38.5t-15 -36.5t-20 -36.5t-26 -30.5t-35 -26.5t-44.5 -15.5t-57 -6.5q-21 0 -40.5 1.5 t-41.5 6.5t-34.5 7.5t-37.5 11.5t-31 11t-36 14t-32 13l-111 -518h317l-41 -151h-309l-104 -490h458l-43 -217h-755l157 743q-151 66 -276 74q-116 -249 -190 -511.5t-74 -422.5q0 -36 4 -59t9 -30.5t9.5 -13.5t5.5 -11q-118 7 -163 24q-98 36 -109 165q-2 19 -2 40 q0 131 83.5 359t217.5 460q-100 -7 -160 -30.5t-80 -75.5q8 0 17.5 -21.5t9.5 -42.5q0 -35 -31.5 -57.5t-93.5 -22.5q-49 0 -83 32.5t-34 96.5zM723 903q146 -27 254 -69l119 557q-176 -96 -373 -488z" />
<glyph unicode="&#xc7;" horiz-adv-x="1017" d="M39 471q0 83 11 176t37 197.5t64 202t96.5 187t129.5 156.5t168.5 106.5t208.5 39.5q75 0 135.5 -15t107.5 -47t73 -85.5t26 -126.5q0 -87 -35 -138t-109 -51q-70 0 -116 53q37 19 65.5 75t28.5 114q0 55 -30 90t-95 35q-108 0 -208.5 -152t-159 -374t-58.5 -431 q0 -59 6.5 -105.5t23.5 -87.5t44.5 -68t70.5 -42.5t101 -15.5q119 0 223.5 54.5t175.5 150.5l47 -21q-35 -88 -96.5 -159t-134 -115t-146 -69.5t-145.5 -33.5l-43 -106q66 16 108 16q63 0 95 -27t32 -75q0 -104 -74 -164.5t-171 -60.5q-71 0 -118.5 14.5t-101.5 42.5 q35 65 82 65q45 0 86 -27.5t66 -27.5q26 0 43.5 26.5t17.5 59.5q0 31 -19.5 52.5t-59.5 21.5q-50 0 -107 -25l76 211q-218 6 -320 123t-102 381z" />
<glyph unicode="&#xc8;" horiz-adv-x="940" d="M14 324q0 110 44.5 219.5t133 196.5t201.5 114q-125 89 -125 246q0 106 56.5 206.5t161.5 167t231 66.5q127 0 210 -67.5t83 -188.5q0 -91 -44.5 -152t-107.5 -61q-55 0 -96 55q37 12 63.5 68t26.5 111q0 58 -33 86t-80 28q-88 0 -148.5 -88.5t-60.5 -200.5 q0 -96 51.5 -171t155.5 -103q-79 -18 -149 -70.5t-116.5 -122t-73.5 -147.5t-27 -149q0 -93 47.5 -150t146.5 -57q102 0 214.5 57t164.5 152l47 -21q-78 -177 -245 -281t-355 -104q-95 0 -169 29t-118.5 79.5t-67 114.5t-22.5 138zM516 2048h215l60 -387h-154z" />
<glyph unicode="&#xc9;" horiz-adv-x="940" d="M14 324q0 110 44.5 219.5t133 196.5t201.5 114q-125 89 -125 246q0 106 56.5 206.5t161.5 167t231 66.5q127 0 210 -67.5t83 -188.5q0 -91 -44.5 -152t-107.5 -61q-55 0 -96 55q37 12 63.5 68t26.5 111q0 58 -33 86t-80 28q-88 0 -148.5 -88.5t-60.5 -200.5 q0 -96 51.5 -171t155.5 -103q-79 -18 -149 -70.5t-116.5 -122t-73.5 -147.5t-27 -149q0 -93 47.5 -150t146.5 -57q102 0 214.5 57t164.5 152l47 -21q-78 -177 -245 -281t-355 -104q-95 0 -169 29t-118.5 79.5t-67 114.5t-22.5 138zM676 1661l186 387h215l-248 -387h-153z " />
<glyph unicode="&#xca;" horiz-adv-x="940" d="M14 324q0 110 44.5 219.5t133 196.5t201.5 114q-125 89 -125 246q0 106 56.5 206.5t161.5 167t231 66.5q127 0 210 -67.5t83 -188.5q0 -91 -44.5 -152t-107.5 -61q-55 0 -96 55q37 12 63.5 68t26.5 111q0 58 -33 86t-80 28q-88 0 -148.5 -88.5t-60.5 -200.5 q0 -96 51.5 -171t155.5 -103q-79 -18 -149 -70.5t-116.5 -122t-73.5 -147.5t-27 -149q0 -93 47.5 -150t146.5 -57q102 0 214.5 57t164.5 152l47 -21q-78 -177 -245 -281t-355 -104q-95 0 -169 29t-118.5 79.5t-67 114.5t-22.5 138zM414 1661l434 387h43l123 -387h-66 l-123 164l-321 -164h-90z" />
<glyph unicode="&#xcb;" horiz-adv-x="940" d="M14 324q0 110 44.5 219.5t133 196.5t201.5 114q-125 89 -125 246q0 106 56.5 206.5t161.5 167t231 66.5q127 0 210 -67.5t83 -188.5q0 -91 -44.5 -152t-107.5 -61q-55 0 -96 55q37 12 63.5 68t26.5 111q0 58 -33 86t-80 28q-88 0 -148.5 -88.5t-60.5 -200.5 q0 -96 51.5 -171t155.5 -103q-79 -18 -149 -70.5t-116.5 -122t-73.5 -147.5t-27 -149q0 -93 47.5 -150t146.5 -57q102 0 214.5 57t164.5 152l47 -21q-78 -177 -245 -281t-355 -104q-95 0 -169 29t-118.5 79.5t-67 114.5t-22.5 138zM487 1810q0 51 36.5 88t88.5 37 q51 0 88 -37t37 -88q0 -52 -37 -88t-88 -36q-53 0 -89 36t-36 88zM856 1810q0 51 36.5 88t88.5 37q51 0 88 -37t37 -88q0 -52 -37 -88t-88 -36q-53 0 -89 36t-36 88z" />
<glyph unicode="&#xcc;" horiz-adv-x="768" d="M12 1004q0 132 108 256.5t275 200t336 75.5q28 0 82 -4l-326 -1532h-294l296 1391q-136 -57 -211 -171t-75 -276q0 -46 6.5 -76t14 -44.5t7.5 -18.5q-110 0 -164.5 46t-54.5 153zM350 2048h215l60 -387h-154z" />
<glyph unicode="&#xcd;" horiz-adv-x="768" d="M12 1004q0 132 108 256.5t275 200t336 75.5q28 0 82 -4l-326 -1532h-294l296 1391q-136 -57 -211 -171t-75 -276q0 -46 6.5 -76t14 -44.5t7.5 -18.5q-110 0 -164.5 46t-54.5 153zM551 1661l186 387h215l-247 -387h-154z" />
<glyph unicode="&#xce;" horiz-adv-x="768" d="M12 1004q0 132 108 256.5t275 200t336 75.5q28 0 82 -4l-326 -1532h-294l296 1391q-136 -57 -211 -171t-75 -276q0 -46 6.5 -76t14 -44.5t7.5 -18.5q-110 0 -164.5 46t-54.5 153zM309 1661l434 387h43l123 -387h-65l-123 164l-322 -164h-90z" />
<glyph unicode="&#xcf;" horiz-adv-x="768" d="M12 1004q0 132 108 256.5t275 200t336 75.5q28 0 82 -4l-326 -1532h-294l296 1391q-136 -57 -211 -171t-75 -276q0 -46 6.5 -76t14 -44.5t7.5 -18.5q-110 0 -164.5 46t-54.5 153zM342 1810q0 51 36.5 88t88.5 37q51 0 88 -37t37 -88q0 -52 -37 -88t-88 -36q-53 0 -89 36 t-36 88zM711 1810q0 51 36.5 88t88.5 37q51 0 88 -37t37 -88q0 -52 -37 -88t-88 -36q-53 0 -89 36t-36 88z" />
<glyph unicode="&#xd0;" horiz-adv-x="1357" d="M12 1004q0 132 108 256.5t275 200t336 75.5q138 0 243 -30.5t169.5 -80.5t105.5 -123t56.5 -150t15.5 -169q0 -260 -78 -493.5t-209.5 -375t-279.5 -141.5q-124 0 -250 109l-17 -82h-294l151 707h-80l41 151h72l94 445l303 40l-104 -485h161l-40 -151h-154l-109 -512 q55 -41 117 -41q88 0 164 83t125 213t76.5 285t27.5 305q0 82 -6.5 141t-24.5 110.5t-49.5 83t-81.5 49.5t-120 18q-251 0 -402 -133.5t-151 -364.5q0 -46 6.5 -76t14 -44.5t7.5 -18.5q-110 0 -164.5 46t-54.5 153z" />
<glyph unicode="&#xd1;" horiz-adv-x="1404" d="M12 1004q0 70 26 144.5t77.5 143.5t120 123.5t161.5 87.5t195 33q131 0 190 -29l162 -1085l223 1110h295l-325 -1532h-248l-174 1071l-228 -1071h-294l294 1391q-135 -56 -209.5 -171t-74.5 -276q0 -46 6.5 -76t14 -44.5t7.5 -18.5q-110 0 -164.5 46t-54.5 153zM631 1704 q49 98 137 149.5t205 51.5q79 0 180.5 -34t157.5 -34q85 0 129 47l12 -2q-18 -75 -117.5 -140t-212.5 -65q-70 0 -180 38t-164 38q-79 0 -135 -53z" />
<glyph unicode="&#xd2;" horiz-adv-x="1347" d="M33 977q0 141 115 270.5t307 209t403 79.5q131 0 226.5 -38.5t151 -110t81.5 -164.5t26 -211q0 -87 -13.5 -181t-42.5 -194.5t-71.5 -193.5t-105 -176.5t-137.5 -145t-174.5 -97.5t-210.5 -36q-171 0 -269 98.5t-98 312.5q0 85 16 186.5t45.5 210t78 209t107.5 180 t139 127.5t169 48q55 0 107 -17q-89 -54 -174 -223.5t-135 -370.5t-50 -358q0 -110 29.5 -173.5t89.5 -63.5q100 0 201 145t164 362.5t63 421.5q0 95 -11 157.5t-39.5 110.5t-80 69.5t-131.5 21.5q-118 0 -224.5 -37t-188 -103.5t-129.5 -167t-48 -219.5q0 -48 11 -79 l10 -31q-207 0 -207 172zM598 2048h215l59 -387h-153z" />
<glyph unicode="&#xd3;" horiz-adv-x="1347" d="M33 977q0 141 115 270.5t307 209t403 79.5q131 0 226.5 -38.5t151 -110t81.5 -164.5t26 -211q0 -87 -13.5 -181t-42.5 -194.5t-71.5 -193.5t-105 -176.5t-137.5 -145t-174.5 -97.5t-210.5 -36q-171 0 -269 98.5t-98 312.5q0 85 16 186.5t45.5 210t78 209t107.5 180 t139 127.5t169 48q55 0 107 -17q-89 -54 -174 -223.5t-135 -370.5t-50 -358q0 -110 29.5 -173.5t89.5 -63.5q100 0 201 145t164 362.5t63 421.5q0 95 -11 157.5t-39.5 110.5t-80 69.5t-131.5 21.5q-118 0 -224.5 -37t-188 -103.5t-129.5 -167t-48 -219.5q0 -48 11 -79 l10 -31q-207 0 -207 172zM813 1661l186 387h215l-247 -387h-154z" />
<glyph unicode="&#xd4;" horiz-adv-x="1347" d="M33 977q0 141 115 270.5t307 209t403 79.5q131 0 226.5 -38.5t151 -110t81.5 -164.5t26 -211q0 -87 -13.5 -181t-42.5 -194.5t-71.5 -193.5t-105 -176.5t-137.5 -145t-174.5 -97.5t-210.5 -36q-171 0 -269 98.5t-98 312.5q0 85 16 186.5t45.5 210t78 209t107.5 180 t139 127.5t169 48q55 0 107 -17q-89 -54 -174 -223.5t-135 -370.5t-50 -358q0 -110 29.5 -173.5t89.5 -63.5q100 0 201 145t164 362.5t63 421.5q0 95 -11 157.5t-39.5 110.5t-80 69.5t-131.5 21.5q-118 0 -224.5 -37t-188 -103.5t-129.5 -167t-48 -219.5q0 -48 11 -79 l10 -31q-207 0 -207 172zM557 1661l434 387h43l123 -387h-65l-123 164l-322 -164h-90z" />
<glyph unicode="&#xd5;" horiz-adv-x="1347" d="M33 977q0 141 115 270.5t307 209t403 79.5q131 0 226.5 -38.5t151 -110t81.5 -164.5t26 -211q0 -87 -13.5 -181t-42.5 -194.5t-71.5 -193.5t-105 -176.5t-137.5 -145t-174.5 -97.5t-210.5 -36q-171 0 -269 98.5t-98 312.5q0 85 16 186.5t45.5 210t78 209t107.5 180 t139 127.5t169 48q55 0 107 -17q-89 -54 -174 -223.5t-135 -370.5t-50 -358q0 -110 29.5 -173.5t89.5 -63.5q100 0 201 145t164 362.5t63 421.5q0 95 -11 157.5t-39.5 110.5t-80 69.5t-131.5 21.5q-118 0 -224.5 -37t-188 -103.5t-129.5 -167t-48 -219.5q0 -48 11 -79 l10 -31q-207 0 -207 172zM561 1704q49 98 137 149.5t205 51.5q79 0 180.5 -34t157.5 -34q85 0 129 47l12 -2q-18 -75 -117 -140t-212 -65q-70 0 -180 38t-164 38q-80 0 -136 -53z" />
<glyph unicode="&#xd6;" horiz-adv-x="1347" d="M33 977q0 141 115 270.5t307 209t403 79.5q131 0 226.5 -38.5t151 -110t81.5 -164.5t26 -211q0 -87 -13.5 -181t-42.5 -194.5t-71.5 -193.5t-105 -176.5t-137.5 -145t-174.5 -97.5t-210.5 -36q-171 0 -269 98.5t-98 312.5q0 85 16 186.5t45.5 210t78 209t107.5 180 t139 127.5t169 48q55 0 107 -17q-89 -54 -174 -223.5t-135 -370.5t-50 -358q0 -110 29.5 -173.5t89.5 -63.5q100 0 201 145t164 362.5t63 421.5q0 95 -11 157.5t-39.5 110.5t-80 69.5t-131.5 21.5q-118 0 -224.5 -37t-188 -103.5t-129.5 -167t-48 -219.5q0 -48 11 -79 l10 -31q-207 0 -207 172zM590 1810q0 51 36.5 88t88.5 37q51 0 88 -37t37 -88q0 -52 -37 -88t-88 -36q-53 0 -89 36t-36 88zM958 1810q0 51 36.5 88t88.5 37q51 0 88 -37t37 -88q0 -52 -37 -88t-88 -36q-53 0 -89 36t-36 88z" />
<glyph unicode="&#xd7;" horiz-adv-x="1054" d="M201 338l194 194l-194 195l133 131l192 -194l197 196l131 -133l-195 -195l195 -194l-131 -133l-197 194l-192 -192z" />
<glyph unicode="&#xd8;" horiz-adv-x="1347" d="M31 913q0 99 66.5 195.5t175 168.5t255.5 116.5t299 44.5q34 0 50 -2l22 100h107l-25 -115q313 -72 313 -475q0 -106 -21.5 -221.5t-70 -236.5t-118 -220.5t-174.5 -173.5t-230 -96l-31 -143h-106l28 133q-169 0 -263.5 92.5t-94.5 294.5q0 79 15.5 174t44.5 196 t75.5 195.5t103.5 169t134 119.5t162 45q49 0 92 -14l18 83q-40 7 -78 7q-153 0 -281.5 -59t-208 -173t-79.5 -262q0 -32 5 -54.5t10 -33t5 -14.5q-98 0 -149 37t-51 122zM506 367q0 -207 98 -224l234 1106q-83 -56 -161.5 -213t-124.5 -341t-46 -328zM719 180 q81 59 153.5 194.5t116 308t43.5 331.5q0 108 -17 177t-61 107z" />
<glyph unicode="&#xd9;" horiz-adv-x="1472" d="M0 993q0 85 42 167t116.5 149t171 118.5t212 80t232.5 28.5q44 0 98 -10q-32 -120 -74.5 -275t-64 -236t-49 -184t-40.5 -158.5t-26 -118.5t-17.5 -104.5t-4.5 -78.5q0 -185 141 -185q50 0 80.5 6t66.5 30t62.5 69.5t57.5 125t62 197t67 285.5l137 633h289l-136 -639 q-30 -145 -56.5 -247.5t-61 -204t-72 -168t-88.5 -125.5t-113 -92t-141 -51.5t-178 -18.5q-213 0 -304.5 81.5t-91.5 243.5q0 59 7 123.5t29.5 167.5t33.5 151t50 202t48 192l68 270q-170 -45 -266.5 -167t-96.5 -304q0 -48 6.5 -78.5t14.5 -44.5t8 -18q-219 0 -219 188z M840 2048h215l59 -387h-153z" />
<glyph unicode="&#xda;" horiz-adv-x="1472" d="M0 993q0 85 42 167t116.5 149t171 118.5t212 80t232.5 28.5q44 0 98 -10q-32 -120 -74.5 -275t-64 -236t-49 -184t-40.5 -158.5t-26 -118.5t-17.5 -104.5t-4.5 -78.5q0 -185 141 -185q50 0 80.5 6t66.5 30t62.5 69.5t57.5 125t62 197t67 285.5l137 633h289l-136 -639 q-30 -145 -56.5 -247.5t-61 -204t-72 -168t-88.5 -125.5t-113 -92t-141 -51.5t-178 -18.5q-213 0 -304.5 81.5t-91.5 243.5q0 59 7 123.5t29.5 167.5t33.5 151t50 202t48 192l68 270q-170 -45 -266.5 -167t-96.5 -304q0 -48 6.5 -78.5t14.5 -44.5t8 -18q-219 0 -219 188z M924 1661l186 387h215l-248 -387h-153z" />
<glyph unicode="&#xdb;" horiz-adv-x="1472" d="M0 993q0 85 42 167t116.5 149t171 118.5t212 80t232.5 28.5q44 0 98 -10q-32 -120 -74.5 -275t-64 -236t-49 -184t-40.5 -158.5t-26 -118.5t-17.5 -104.5t-4.5 -78.5q0 -185 141 -185q50 0 80.5 6t66.5 30t62.5 69.5t57.5 125t62 197t67 285.5l137 633h289l-136 -639 q-30 -145 -56.5 -247.5t-61 -204t-72 -168t-88.5 -125.5t-113 -92t-141 -51.5t-178 -18.5q-213 0 -304.5 81.5t-91.5 243.5q0 59 7 123.5t29.5 167.5t33.5 151t50 202t48 192l68 270q-170 -45 -266.5 -167t-96.5 -304q0 -48 6.5 -78.5t14.5 -44.5t8 -18q-219 0 -219 188z M743 1661l435 387h43l122 -387h-65l-123 164l-321 -164h-91z" />
<glyph unicode="&#xdc;" horiz-adv-x="1472" d="M0 993q0 85 42 167t116.5 149t171 118.5t212 80t232.5 28.5q44 0 98 -10q-32 -120 -74.5 -275t-64 -236t-49 -184t-40.5 -158.5t-26 -118.5t-17.5 -104.5t-4.5 -78.5q0 -185 141 -185q50 0 80.5 6t66.5 30t62.5 69.5t57.5 125t62 197t67 285.5l137 633h289l-136 -639 q-30 -145 -56.5 -247.5t-61 -204t-72 -168t-88.5 -125.5t-113 -92t-141 -51.5t-178 -18.5q-213 0 -304.5 81.5t-91.5 243.5q0 59 7 123.5t29.5 167.5t33.5 151t50 202t48 192l68 270q-170 -45 -266.5 -167t-96.5 -304q0 -48 6.5 -78.5t14.5 -44.5t8 -18q-219 0 -219 188z M764 1810q0 51 36.5 88t88.5 37q51 0 88 -37t37 -88q0 -52 -37 -88t-88 -36q-53 0 -89 36t-36 88zM1133 1810q0 51 36 88t88 37q51 0 88 -37t37 -88q0 -52 -37 -88t-88 -36q-53 0 -88.5 36t-35.5 88z" />
<glyph unicode="&#xdd;" horiz-adv-x="1269" d="M12 1004q0 132 108 256.5t275 200t336 75.5q28 0 82 -4l178 -733l303 727h136l-398 -895l-135 -631h-328l136 631l-197 768q-144 -53 -224.5 -170.5t-80.5 -284.5q0 -46 6.5 -76t14 -44.5t7.5 -18.5q-110 0 -164.5 46t-54.5 153zM928 1661l186 387h215l-248 -387h-153z " />
<glyph unicode="&#xde;" horiz-adv-x="1193" d="M12 778q0 146 129.5 281t319.5 203l51 233l303 41l-49 -225q113 -5 200.5 -40t140.5 -91.5t80 -125.5t27 -147q0 -99 -41.5 -196t-115 -176t-187.5 -128t-247 -49h-60l-76 -358h-294l245 1151q-115 -60 -175 -170t-60 -262q0 -46 6.5 -76t14 -44.5t7.5 -18.5 q-110 0 -164.5 45.5t-54.5 152.5zM580 434h28q104 0 193 79.5t137.5 195t48.5 229.5q0 77 -23.5 137t-78.5 99.5t-137 42.5z" />
<glyph unicode="&#xdf;" horiz-adv-x="921" d="M-174 -512l340 1597q18 84 50 148.5t68.5 101.5t82.5 60t86.5 31t85.5 8q135 0 207.5 -75.5t72.5 -184.5q0 -92 -49.5 -175.5t-138.5 -124.5q103 -35 150.5 -112.5t47.5 -177.5q0 -120 -26.5 -220.5t-68 -166t-94 -111.5t-103.5 -66t-97 -20q-21 0 -67 4l26 121 q60 0 106 51t70.5 131.5t36 161.5t11.5 158q0 70 -34 113.5t-114 64.5l37 119q73 30 121.5 87t48.5 140q0 58 -18.5 80t-59.5 22q-43 0 -83 -38t-60 -130l-326 -1523z" />
<glyph unicode="&#xe0;" horiz-adv-x="1077" d="M-27 317q0 71 14.5 149.5t42.5 159t73.5 153.5t101.5 130t132.5 91t162.5 34q84 0 125 -28.5t41 -75.5v-15l22 109h295l-147 -696q-9 -40 -9 -66q0 -88 84 -88q56 0 98 54t68 139h86q-133 -379 -411 -379q-87 0 -139.5 48.5t-61.5 139.5q-126 -188 -305 -188 q-43 0 -82 10.5t-74 35t-61 62t-41 94t-15 127.5zM276 346q0 -56 10 -91.5t28.5 -48.5t31.5 -16.5t33 -3.5q49 0 101 49t69 132l98 462q0 26 -20 52t-64 26q-62 0 -118 -60t-91.5 -148.5t-56.5 -183t-21 -169.5zM442 1536h215l60 -387h-154z" />
<glyph unicode="&#xe1;" horiz-adv-x="1077" d="M-27 317q0 71 14.5 149.5t42.5 159t73.5 153.5t101.5 130t132.5 91t162.5 34q84 0 125 -28.5t41 -75.5v-15l22 109h295l-147 -696q-9 -40 -9 -66q0 -88 84 -88q56 0 98 54t68 139h86q-133 -379 -411 -379q-87 0 -139.5 48.5t-61.5 139.5q-126 -188 -305 -188 q-43 0 -82 10.5t-74 35t-61 62t-41 94t-15 127.5zM276 346q0 -56 10 -91.5t28.5 -48.5t31.5 -16.5t33 -3.5q49 0 101 49t69 132l98 462q0 26 -20 52t-64 26q-62 0 -118 -60t-91.5 -148.5t-56.5 -183t-21 -169.5zM502 1149l186 387h215l-248 -387h-153z" />
<glyph unicode="&#xe2;" horiz-adv-x="1077" d="M-27 317q0 71 14.5 149.5t42.5 159t73.5 153.5t101.5 130t132.5 91t162.5 34q84 0 125 -28.5t41 -75.5v-15l22 109h295l-147 -696q-9 -40 -9 -66q0 -88 84 -88q56 0 98 54t68 139h86q-133 -379 -411 -379q-87 0 -139.5 48.5t-61.5 139.5q-126 -188 -305 -188 q-43 0 -82 10.5t-74 35t-61 62t-41 94t-15 127.5zM276 346q0 -56 10 -91.5t28.5 -48.5t31.5 -16.5t33 -3.5q49 0 101 49t69 132l98 462q0 26 -20 52t-64 26q-62 0 -118 -60t-91.5 -148.5t-56.5 -183t-21 -169.5zM299 1149l434 387h43l123 -387h-65l-123 164l-322 -164h-90z " />
<glyph unicode="&#xe3;" horiz-adv-x="1077" d="M-27 317q0 71 14.5 149.5t42.5 159t73.5 153.5t101.5 130t132.5 91t162.5 34q84 0 125 -28.5t41 -75.5v-15l22 109h295l-147 -696q-9 -40 -9 -66q0 -88 84 -88q56 0 98 54t68 139h86q-133 -379 -411 -379q-87 0 -139.5 48.5t-61.5 139.5q-126 -188 -305 -188 q-43 0 -82 10.5t-74 35t-61 62t-41 94t-15 127.5zM209 1192q49 98 137 149.5t205 51.5q79 0 180.5 -34t157.5 -34q85 0 129 47l12 -2q-18 -75 -117.5 -140t-212.5 -65q-70 0 -180 38t-164 38q-79 0 -135 -53zM276 346q0 -56 10 -91.5t28.5 -48.5t31.5 -16.5t33 -3.5 q49 0 101 49t69 132l98 462q0 26 -20 52t-64 26q-62 0 -118 -60t-91.5 -148.5t-56.5 -183t-21 -169.5z" />
<glyph unicode="&#xe4;" horiz-adv-x="1077" d="M-27 317q0 71 14.5 149.5t42.5 159t73.5 153.5t101.5 130t132.5 91t162.5 34q84 0 125 -28.5t41 -75.5v-15l22 109h295l-147 -696q-9 -40 -9 -66q0 -88 84 -88q56 0 98 54t68 139h86q-133 -379 -411 -379q-87 0 -139.5 48.5t-61.5 139.5q-126 -188 -305 -188 q-43 0 -82 10.5t-74 35t-61 62t-41 94t-15 127.5zM276 346q0 -56 10 -91.5t28.5 -48.5t31.5 -16.5t33 -3.5q49 0 101 49t69 132l98 462q0 26 -20 52t-64 26q-62 0 -118 -60t-91.5 -148.5t-56.5 -183t-21 -169.5zM369 1298q0 51 36.5 88t88.5 37q51 0 87.5 -37t36.5 -88 q0 -52 -36.5 -88t-87.5 -36q-53 0 -89 36t-36 88zM737 1298q0 51 36.5 88t88.5 37q51 0 88 -37t37 -88q0 -52 -37 -88t-88 -36q-53 0 -89 36t-36 88z" />
<glyph unicode="&#xe5;" horiz-adv-x="1077" d="M-27 317q0 71 14.5 149.5t42.5 159t73.5 153.5t101.5 130t132.5 91t162.5 34q84 0 125 -28.5t41 -75.5v-15l22 109h295l-147 -696q-9 -40 -9 -66q0 -88 84 -88q56 0 98 54t68 139h86q-133 -379 -411 -379q-87 0 -139.5 48.5t-61.5 139.5q-126 -188 -305 -188 q-43 0 -82 10.5t-74 35t-61 62t-41 94t-15 127.5zM276 346q0 -56 10 -91.5t28.5 -48.5t31.5 -16.5t33 -3.5q49 0 101 49t69 132l98 462q0 26 -20 52t-64 26q-62 0 -118 -60t-91.5 -148.5t-56.5 -183t-21 -169.5zM479 1274q0 29 10.5 60.5t30 60t54.5 47t79 18.5 q72 0 110 -44t38 -113q0 -74 -44.5 -123.5t-133.5 -49.5q-64 0 -104 42t-40 102zM561 1278q0 -76 70 -76q46 0 70 25t24 69q0 20 -1.5 32.5t-7.5 29.5t-21 26t-38 9q-49 0 -72.5 -35t-23.5 -80z" />
<glyph unicode="&#xe6;" horiz-adv-x="1331" d="M-16 254q0 93 34 160t97 105.5t142.5 56.5t180.5 18q57 0 107 -8q43 91 43 180q0 65 -31.5 105t-93.5 40q-84 0 -140 -24.5t-108 -71.5l-57 59q55 56 104 90.5t98 48.5t82.5 17.5t87.5 3.5q166 0 267 -82q121 90 276 90q66 0 111.5 -15.5t69 -45t33 -63.5t9.5 -78 q0 -110 -66.5 -206.5t-174.5 -154.5t-230 -65q-4 -46 -4 -66q0 -108 31 -148t92 -40q71 0 125.5 13t102 45.5t77 61.5t82.5 87h70q-48 -77 -99 -137.5t-120.5 -117.5t-157.5 -88.5t-188 -31.5q-246 0 -301 192q-49 -93 -114 -144.5t-177 -51.5q-49 0 -91.5 11.5t-82.5 39.5 t-63 83t-23 132zM272 289q0 -33 10.5 -55.5t28 -31.5t30.5 -12.5t26 -3.5q55 0 94.5 61.5t68.5 219.5q-12 2 -34 2q-100 0 -162 -49.5t-62 -130.5zM840 512q119 7 209 108.5t90 223.5q0 90 -49 90q-50 0 -101.5 -65.5t-88.5 -159.5t-60 -197z" />
<glyph unicode="&#xe7;" horiz-adv-x="786" d="M-27 313q0 54 8.5 115.5t28.5 133t49 138.5t74 130t99.5 109.5t130 74.5t161.5 28q125 0 176.5 -53t51.5 -135q0 -72 -31 -110.5t-78 -38.5q-35 0 -72 24q25 70 25 121q0 84 -57 84q-61 0 -124 -103.5t-101 -244t-38 -254.5q0 -100 35 -136t113 -36q77 0 144.5 29.5 t113 69.5t104.5 108h70q-181 -289 -410 -357l-57 -145q66 16 109 16q63 0 95 -27t32 -75q0 -104 -74.5 -164.5t-171.5 -60.5q-70 0 -117.5 14t-101.5 43q35 65 82 65q45 0 85.5 -27.5t65.5 -27.5q26 0 44 26.5t18 59.5q0 31 -20 52.5t-60 21.5q-49 0 -107 -25l84 236 q-20 -4 -59 -4q-151 0 -235.5 79t-84.5 246z" />
<glyph unicode="&#xe8;" horiz-adv-x="786" d="M-27 313q0 53 8.5 114.5t28 133t48.5 138.5t74 130t100.5 110t131 75t162.5 28q226 0 226 -196q0 -115 -66.5 -212.5t-174 -155t-230.5 -64.5q-5 -72 -5 -82q0 -100 35 -136t113 -36q77 0 144.5 29.5t113 69.5t104.5 108h70q-236 -379 -563 -379q-151 0 -235.5 79 t-84.5 246zM297 512q119 8 208 109.5t89 228.5q0 84 -51 84q-50 0 -100.5 -64t-87.5 -158.5t-58 -199.5zM354 1536h215l60 -387h-154z" />
<glyph unicode="&#xe9;" horiz-adv-x="786" d="M-27 313q0 53 8.5 114.5t28 133t48.5 138.5t74 130t100.5 110t131 75t162.5 28q226 0 226 -196q0 -115 -66.5 -212.5t-174 -155t-230.5 -64.5q-5 -72 -5 -82q0 -100 35 -136t113 -36q77 0 144.5 29.5t113 69.5t104.5 108h70q-236 -379 -563 -379q-151 0 -235.5 79 t-84.5 246zM297 512q119 8 208 109.5t89 228.5q0 84 -51 84q-50 0 -100.5 -64t-87.5 -158.5t-58 -199.5zM397 1149l187 387h215l-248 -387h-154z" />
<glyph unicode="&#xea;" horiz-adv-x="786" d="M-27 313q0 53 8.5 114.5t28 133t48.5 138.5t74 130t100.5 110t131 75t162.5 28q226 0 226 -196q0 -115 -66.5 -212.5t-174 -155t-230.5 -64.5q-5 -72 -5 -82q0 -100 35 -136t113 -36q77 0 144.5 29.5t113 69.5t104.5 108h70q-236 -379 -563 -379q-151 0 -235.5 79 t-84.5 246zM215 1149l434 387h43l123 -387h-65l-123 164l-322 -164h-90zM297 512q119 8 208 109.5t89 228.5q0 84 -51 84q-50 0 -100.5 -64t-87.5 -158.5t-58 -199.5z" />
<glyph unicode="&#xeb;" horiz-adv-x="786" d="M-27 313q0 53 8.5 114.5t28 133t48.5 138.5t74 130t100.5 110t131 75t162.5 28q226 0 226 -196q0 -115 -66.5 -212.5t-174 -155t-230.5 -64.5q-5 -72 -5 -82q0 -100 35 -136t113 -36q77 0 144.5 29.5t113 69.5t104.5 108h70q-236 -379 -563 -379q-151 0 -235.5 79 t-84.5 246zM244 1298q0 51 36.5 88t88.5 37q51 0 88 -37t37 -88q0 -52 -37 -88t-88 -36q-53 0 -89 36t-36 88zM297 512q119 8 208 109.5t89 228.5q0 84 -51 84q-50 0 -100.5 -64t-87.5 -158.5t-58 -199.5zM612 1298q0 51 36.5 88t88.5 37q51 0 88 -37t37 -88q0 -52 -37 -88 t-88 -36q-53 0 -89 36t-36 88z" />
<glyph unicode="&#xec;" horiz-adv-x="546" d="M-16 233q0 56 16 134l139 657h295l-147 -696q-8 -36 -8 -66q0 -42 19.5 -59t63.5 -17q59 0 110 51.5t75 129.5h86q-33 -95 -79 -167t-90.5 -111t-95.5 -63t-88.5 -31t-76.5 -7q-98 0 -158.5 61t-60.5 184zM135 1536h215l60 -387h-154z" />
<glyph unicode="&#xed;" horiz-adv-x="546" d="M-16 233q0 56 16 134l139 657h295l-147 -696q-8 -36 -8 -66q0 -42 19.5 -59t63.5 -17q59 0 110 51.5t75 129.5h86q-33 -95 -79 -167t-90.5 -111t-95.5 -63t-88.5 -31t-76.5 -7q-98 0 -158.5 61t-60.5 184zM248 1149l186 387h215l-248 -387h-153z" />
<glyph unicode="&#xee;" horiz-adv-x="546" d="M-16 233q0 56 16 134l139 657h295l-147 -696q-8 -36 -8 -66q0 -42 19.5 -59t63.5 -17q59 0 110 51.5t75 129.5h86q-33 -95 -79 -167t-90.5 -111t-95.5 -63t-88.5 -31t-76.5 -7q-98 0 -158.5 61t-60.5 184zM12 1149l434 387h43l123 -387h-65l-123 164l-322 -164h-90z" />
<glyph unicode="&#xef;" horiz-adv-x="546" d="M-16 233q0 56 16 134l139 657h295l-147 -696q-8 -36 -8 -66q0 -42 19.5 -59t63.5 -17q59 0 110 51.5t75 129.5h86q-33 -95 -79 -167t-90.5 -111t-95.5 -63t-88.5 -31t-76.5 -7q-98 0 -158.5 61t-60.5 184zM35 1298q0 51 36.5 88t88.5 37q51 0 88 -37t37 -88 q0 -52 -37 -88t-88 -36q-53 0 -89 36t-36 88zM403 1298q0 51 36.5 88t88.5 37q51 0 88 -37t37 -88q0 -52 -37 -88t-88 -36q-53 0 -89 36t-36 88z" />
<glyph unicode="&#xf0;" horiz-adv-x="1101" d="M-2 317q0 71 14.5 149.5t42.5 159t73 153.5t101 130t132.5 91t162.5 34q84 0 125 -28.5t41 -75.5v-12l17 75q19 91 22 156h-158l17 82h141q-12 104 -86 203h92q79 -44 133 -90t86 -113h129l-16 -82h-86q12 -50 12 -109q0 -77 -22 -190l-111 -522q-8 -36 -8 -66 q0 -42 20 -59t64 -17q57 0 99 49.5t67 131.5h86q-33 -96 -77.5 -166t-85.5 -107.5t-90 -60t-84 -28t-75 -5.5q-84 0 -136.5 45.5t-64.5 132.5q-123 -190 -305 -190q-55 0 -101.5 17.5t-86 55t-62 103t-22.5 153.5zM301 346q0 -45 7.5 -77t17 -47.5t26 -24t26.5 -10t25 -1.5 q49 0 101 49t69 132l99 462q0 26 -19.5 52t-64.5 26q-62 0 -118 -60t-91.5 -148.5t-56.5 -183t-21 -169.5z" />
<glyph unicode="&#xf1;" d="M-78 0l217 1024h295l-22 -106q100 114 239 114q104 0 166 -56.5t62 -174.5q0 -89 -49.5 -283.5t-49.5 -245.5q0 -86 82 -86q61 0 96.5 43t75.5 138h86q-33 -97 -73.5 -168t-78.5 -110.5t-81.5 -63t-76.5 -30.5t-71 -7q-124 0 -182.5 66.5t-58.5 164.5q0 71 46 264t46 258 q0 105 -74 105q-52 0 -93.5 -53t-66.5 -136l-139 -657h-295zM180 1192q49 98 137 149.5t205 51.5q79 0 180.5 -34t157.5 -34q85 0 129 47l12 -2q-18 -75 -117 -140t-212 -65q-70 0 -180 38t-164 38q-79 0 -135 -53z" />
<glyph unicode="&#xf2;" horiz-adv-x="886" d="M-41 315q0 53 8.5 114.5t29 132.5t50 138.5t75.5 130t102 109t132.5 74.5t163.5 28q262 0 262 -327q8 -4 23 -4q66 0 154.5 36.5t160.5 86.5l19 -56q-58 -62 -153.5 -106.5t-209.5 -63.5q-24 -280 -160.5 -448t-328.5 -168q-152 0 -240 78t-88 245zM264 342 q0 -99 22.5 -132.5t82.5 -33.5q75 0 143.5 122.5t93.5 303.5q-55 13 -55 86q0 84 63 111q-3 65 -20.5 92t-56.5 27q-68 0 -133.5 -103t-102.5 -236.5t-37 -236.5zM367 1536h215l59 -387h-154z" />
<glyph unicode="&#xf3;" horiz-adv-x="886" d="M-41 315q0 53 8.5 114.5t29 132.5t50 138.5t75.5 130t102 109t132.5 74.5t163.5 28q262 0 262 -327q8 -4 23 -4q66 0 154.5 36.5t160.5 86.5l19 -56q-58 -62 -153.5 -106.5t-209.5 -63.5q-24 -280 -160.5 -448t-328.5 -168q-152 0 -240 78t-88 245zM264 342 q0 -99 22.5 -132.5t82.5 -33.5q75 0 143.5 122.5t93.5 303.5q-55 13 -55 86q0 84 63 111q-3 65 -20.5 92t-56.5 27q-68 0 -133.5 -103t-102.5 -236.5t-37 -236.5zM449 1149l186 387h215l-248 -387h-153z" />
<glyph unicode="&#xf4;" horiz-adv-x="886" d="M-41 315q0 53 8.5 114.5t29 132.5t50 138.5t75.5 130t102 109t132.5 74.5t163.5 28q262 0 262 -327q8 -4 23 -4q66 0 154.5 36.5t160.5 86.5l19 -56q-58 -62 -153.5 -106.5t-209.5 -63.5q-24 -280 -160.5 -448t-328.5 -168q-152 0 -240 78t-88 245zM195 1149l434 387h43 l123 -387h-66l-123 164l-321 -164h-90zM264 342q0 -99 22.5 -132.5t82.5 -33.5q75 0 143.5 122.5t93.5 303.5q-55 13 -55 86q0 84 63 111q-3 65 -20.5 92t-56.5 27q-68 0 -133.5 -103t-102.5 -236.5t-37 -236.5z" />
<glyph unicode="&#xf5;" horiz-adv-x="886" d="M-41 315q0 53 8.5 114.5t29 132.5t50 138.5t75.5 130t102 109t132.5 74.5t163.5 28q262 0 262 -327q8 -4 23 -4q66 0 154.5 36.5t160.5 86.5l19 -56q-58 -62 -153.5 -106.5t-209.5 -63.5q-24 -280 -160.5 -448t-328.5 -168q-152 0 -240 78t-88 245zM82 1192 q49 98 137 149.5t205 51.5q79 0 180.5 -34t157.5 -34q85 0 129 47l12 -2q-18 -75 -117.5 -140t-212.5 -65q-70 0 -180 38t-164 38q-79 0 -135 -53zM264 342q0 -99 22.5 -132.5t82.5 -33.5q75 0 143.5 122.5t93.5 303.5q-55 13 -55 86q0 84 63 111q-3 65 -20.5 92t-56.5 27 q-68 0 -133.5 -103t-102.5 -236.5t-37 -236.5z" />
<glyph unicode="&#xf6;" horiz-adv-x="886" d="M-41 315q0 53 8.5 114.5t29 132.5t50 138.5t75.5 130t102 109t132.5 74.5t163.5 28q262 0 262 -327q8 -4 23 -4q66 0 154.5 36.5t160.5 86.5l19 -56q-58 -62 -153.5 -106.5t-209.5 -63.5q-24 -280 -160.5 -448t-328.5 -168q-152 0 -240 78t-88 245zM215 1298 q0 51 36.5 88t88.5 37q51 0 88 -37t37 -88q0 -52 -37 -88t-88 -36q-53 0 -89 36t-36 88zM264 342q0 -99 22.5 -132.5t82.5 -33.5q75 0 143.5 122.5t93.5 303.5q-55 13 -55 86q0 84 63 111q-3 65 -20.5 92t-56.5 27q-68 0 -133.5 -103t-102.5 -236.5t-37 -236.5zM584 1298 q0 51 36.5 88t88.5 37q51 0 88 -37t37 -88q0 -52 -37 -88t-88 -36q-53 0 -89 36t-36 88z" />
<glyph unicode="&#xf7;" horiz-adv-x="966" d="M104 422l37 162h717l-35 -162h-719zM301 164q0 68 47.5 116t114.5 48t115.5 -48t48.5 -116q0 -67 -48 -114.5t-116 -47.5q-67 0 -114.5 47t-47.5 115zM424 850q0 68 47.5 116t114.5 48q68 0 116 -48t48 -116q0 -67 -48 -114.5t-116 -47.5t-115 47t-47 115z" />
<glyph unicode="&#xf8;" horiz-adv-x="876" d="M-29 315q0 52 8 112t27 130t47.5 136t72 128.5t97 109.5t127.5 76.5t158 32.5l41 199h106l-43 -209q170 -46 176 -299q70 3 156.5 41.5t147.5 81.5h65q-46 -66 -151 -131.5t-222 -95.5q-17 -251 -123.5 -417t-267.5 -206l-45 -215h-106l43 203q-145 3 -229.5 81 t-84.5 242zM276 342q0 -99 22.5 -132.5t82.5 -33.5q75 0 142.5 124.5t90.5 307.5q-57 15 -57 94q0 41 17.5 69.5t46.5 39.5q-4 58 -22.5 82.5t-55.5 24.5q-68 0 -132 -103t-99.5 -236t-35.5 -237z" />
<glyph unicode="&#xf9;" d="M-16 233q0 56 16 134l139 657h295l-147 -696q-6 -30 -6 -58q0 -84 61 -84q109 0 164 181l139 657h295l-147 -696q-9 -40 -9 -66q0 -42 20 -59t64 -17q57 0 99 49.5t67 131.5h86q-133 -379 -411 -379q-88 0 -141 49.5t-62 144.5q-118 -194 -303 -194q-98 0 -158.5 61 t-60.5 184zM379 1536h215l59 -387h-153z" />
<glyph unicode="&#xfa;" d="M-16 233q0 56 16 134l139 657h295l-147 -696q-6 -30 -6 -58q0 -84 61 -84q109 0 164 181l139 657h295l-147 -696q-9 -40 -9 -66q0 -42 20 -59t64 -17q57 0 99 49.5t67 131.5h86q-133 -379 -411 -379q-88 0 -141 49.5t-62 144.5q-118 -194 -303 -194q-98 0 -158.5 61 t-60.5 184zM489 1149l187 387h215l-248 -387h-154z" />
<glyph unicode="&#xfb;" d="M-16 233q0 56 16 134l139 657h295l-147 -696q-6 -30 -6 -58q0 -84 61 -84q109 0 164 181l139 657h295l-147 -696q-9 -40 -9 -66q0 -42 20 -59t64 -17q57 0 99 49.5t67 131.5h86q-133 -379 -411 -379q-88 0 -141 49.5t-62 144.5q-118 -194 -303 -194q-98 0 -158.5 61 t-60.5 184zM258 1149l434 387h43l123 -387h-65l-123 164l-322 -164h-90z" />
<glyph unicode="&#xfc;" d="M-16 233q0 56 16 134l139 657h295l-147 -696q-6 -30 -6 -58q0 -84 61 -84q109 0 164 181l139 657h295l-147 -696q-9 -40 -9 -66q0 -42 20 -59t64 -17q57 0 99 49.5t67 131.5h86q-133 -379 -411 -379q-88 0 -141 49.5t-62 144.5q-118 -194 -303 -194q-98 0 -158.5 61 t-60.5 184zM279 1298q0 51 36 88t88 37q51 0 88 -37t37 -88q0 -52 -37 -88t-88 -36q-53 0 -88.5 36t-35.5 88zM647 1298q0 51 36.5 88t88.5 37q51 0 88 -37t37 -88q0 -52 -37 -88t-88 -36q-53 0 -89 36t-36 88z" />
<glyph unicode="&#xfd;" d="M-16 233q0 56 16 134l139 657h295l-147 -696q-6 -24 -6 -52q0 -90 61 -90q54 0 94.5 45.5t65.5 122.5l143 670h295l-203 -950q98 35 157.5 99.5t100.5 193.5h86q-23 -78 -56.5 -140t-68.5 -101.5t-78.5 -69t-79.5 -45t-79 -27.5l-31 -148q-72 -348 -369 -348 q-99 0 -164 51.5t-65 147.5q0 203 334 305l25 110q-102 -114 -246 -114q-98 0 -158.5 61t-60.5 184zM203 -285q0 -24 19 -45.5t50 -21.5q34 0 67 47.5t52 134.5l12 59q-200 -75 -200 -174zM487 1149l187 387h215l-248 -387h-154z" />
<glyph unicode="&#xfe;" horiz-adv-x="968" d="M-188 -512l319 1505q25 116 25 191q0 132 -88 250h92q47 -26 79 -47.5t68.5 -56.5t58.5 -73t37 -94t15 -123q0 -51 -8 -100q105 94 247 94q114 0 182 -75.5t68 -247.5q0 -74 -10 -150t-32 -159.5t-61.5 -156t-93 -131t-132.5 -92.5t-175 -34q-138 0 -176 75l-106 -501z M260 217q16 -51 80 -51q61 0 112 39t82.5 99t53 136t30.5 145.5t9 131.5q0 170 -103 170q-36 0 -76.5 -28.5t-66.5 -78.5z" />
<glyph unicode="&#xff;" d="M-16 233q0 56 16 134l139 657h295l-147 -696q-6 -24 -6 -52q0 -90 61 -90q54 0 94.5 45.5t65.5 122.5l143 670h295l-203 -950q98 35 157.5 99.5t100.5 193.5h86q-23 -78 -56.5 -140t-68.5 -101.5t-78.5 -69t-79.5 -45t-79 -27.5l-31 -148q-72 -348 -369 -348 q-99 0 -164 51.5t-65 147.5q0 203 334 305l25 110q-102 -114 -246 -114q-98 0 -158.5 61t-60.5 184zM203 -285q0 -24 19 -45.5t50 -21.5q34 0 67 47.5t52 134.5l12 59q-200 -75 -200 -174zM252 1298q0 51 36.5 88t88.5 37q51 0 88 -37t37 -88q0 -52 -37 -88t-88 -36 q-53 0 -89 36t-36 88zM621 1298q0 51 36 88t88 37q51 0 88 -37t37 -88q0 -52 -37 -88t-88 -36q-53 0 -88.5 36t-35.5 88z" />
<glyph unicode="&#x152;" horiz-adv-x="1732" d="M33 977q0 141 115 270.5t307 209t403 79.5q130 0 225 -39q109 39 265 39q35 0 152.5 -12.5t187.5 -12.5q105 0 184 25q-5 -14 -13.5 -45t-14.5 -50t-20.5 -46.5t-31.5 -45t-47 -34.5t-68 -25q-90 0 -232.5 34.5t-193.5 39.5q92 -131 92 -352q0 -66 -10 -154h273l-41 -151 h-260q-70 -301 -234 -490h498l-43 -217h-793q-86 -12 -145 -12q-171 0 -269 98.5t-98 312.5q0 85 16 186.5t45.5 210t78 209t107.5 180t139 127.5t169 48q55 0 107 -17q-89 -54 -174 -223.5t-135 -370.5t-50 -358q0 -110 29.5 -173.5t89.5 -63.5q100 0 201 145t164 362.5 t63 421.5q0 95 -11 157.5t-39.5 110.5t-80 69.5t-131.5 21.5q-118 0 -224.5 -37t-188 -103.5t-129.5 -167t-48 -219.5q0 -48 11 -79l10 -31q-207 0 -207 172z" />
<glyph unicode="&#x153;" horiz-adv-x="1357" d="M-14 324q0 183 44 324t119.5 226t170.5 127.5t204 42.5q182 0 230 -174q128 172 327 172q127 0 194.5 -53.5t67.5 -159.5q0 -89 -44 -166t-114.5 -127.5t-148.5 -82t-155 -41.5q-7 -58 -7 -88q0 -93 49 -135t119 -42q79 0 185.5 80.5t158.5 190.5h93 q-37 -66 -79.5 -124.5t-98.5 -113.5t-116 -94t-133.5 -62.5t-150.5 -23.5q-101 0 -171.5 48.5t-104.5 129.5q-66 -93 -151.5 -141.5t-174.5 -48.5q-166 0 -239.5 77.5t-73.5 258.5zM258 342q0 -87 35.5 -121.5t101.5 -34.5q45 0 83 33.5t64.5 90.5t44 125.5t27.5 146.5 q-42 0 -64 26.5t-22 65.5q0 46 25 87t65 56q-9 107 -86 107q-68 0 -123.5 -67t-86.5 -164t-47.5 -190t-16.5 -161zM897 510q90 1 165.5 48t116.5 117.5t42 143.5q0 27 -4.5 50t-22 44t-45.5 21q-54 0 -106.5 -68t-87.5 -159.5t-58 -196.5z" />
<glyph unicode="&#x178;" horiz-adv-x="1269" d="M12 1004q0 132 108 256.5t275 200t336 75.5q28 0 82 -4l178 -733l303 727h136l-398 -895l-135 -631h-328l136 631l-197 768q-144 -53 -224.5 -170.5t-80.5 -284.5q0 -46 6.5 -76t14 -44.5t7.5 -18.5q-110 0 -164.5 46t-54.5 153zM776 1810q0 51 36.5 88t88.5 37 q51 0 88 -37t37 -88q0 -52 -37 -88t-88 -36q-53 0 -89 36t-36 88zM1145 1810q0 51 36.5 88t88.5 37q51 0 88 -37t37 -88q0 -52 -37 -88t-88 -36q-53 0 -89 36t-36 88z" />
<glyph unicode="&#x2c6;" horiz-adv-x="600" d="M0 1149l434 387h43l123 -387h-65l-123 164l-322 -164h-90z" />
<glyph unicode="&#x2dc;" horiz-adv-x="825" d="M78 1192q49 98 137 149.5t205 51.5q79 0 180.5 -34t157.5 -34q85 0 129 47l12 -2q-18 -75 -117.5 -140t-212.5 -65q-70 0 -180 38t-164 38q-79 0 -135 -53z" />
<glyph unicode="&#x2000;" horiz-adv-x="1024" />
<glyph unicode="&#x2001;" horiz-adv-x="2048" />
<glyph unicode="&#x2002;" horiz-adv-x="1024" />
<glyph unicode="&#x2003;" horiz-adv-x="2048" />
<glyph unicode="&#x2004;" horiz-adv-x="682" />
<glyph unicode="&#x2005;" horiz-adv-x="512" />
<glyph unicode="&#x2006;" horiz-adv-x="341" />
<glyph unicode="&#x2007;" horiz-adv-x="341" />
<glyph unicode="&#x2008;" horiz-adv-x="256" />
<glyph unicode="&#x2009;" horiz-adv-x="409" />
<glyph unicode="&#x200a;" horiz-adv-x="113" />
<glyph unicode="&#x2010;" horiz-adv-x="593" d="M39 455l37 161h409l-34 -161h-412z" />
<glyph unicode="&#x2011;" horiz-adv-x="593" d="M39 455l37 161h409l-34 -161h-412z" />
<glyph unicode="&#x2012;" horiz-adv-x="593" d="M39 455l37 161h409l-34 -161h-412z" />
<glyph unicode="&#x2013;" horiz-adv-x="720" d="M39 455l37 161h532l-35 -161h-534z" />
<glyph unicode="&#x2014;" horiz-adv-x="909" d="M39 455l37 161h717l-35 -161h-719z" />
<glyph unicode="&#x2018;" horiz-adv-x="624" d="M172 1397q0 60 34.5 97.5t96.5 37.5q63 0 106.5 -42t43.5 -101q0 -74 -91 -129q-24 -15 -24 -35l100 -144q0 -18 -18 -28q-115 73 -181.5 168t-66.5 176z" />
<glyph unicode="&#x2019;" horiz-adv-x="624" d="M172 1389q0 59 43.5 101t106.5 42q62 0 96.5 -37.5t34.5 -97.5q0 -81 -66.5 -176t-181.5 -168q-19 11 -19 28l101 144q0 19 -25 35q-90 55 -90 129z" />
<glyph unicode="&#x201a;" horiz-adv-x="579" d="M156 156q0 59 43 101t106 42q62 0 96.5 -37.5t34.5 -97.5q0 -81 -66.5 -176t-181.5 -168q-18 10 -18 28l100 144q0 20 -24 35q-90 55 -90 129z" />
<glyph unicode="&#x201c;" horiz-adv-x="1042" d="M156 1397q0 60 34.5 97.5t96.5 37.5q63 0 106 -42t43 -101q0 -74 -90 -129q-24 -15 -24 -35l100 -144q0 -17 -19 -28q-114 73 -180.5 167.5t-66.5 176.5zM606 1397q0 60 34.5 97.5t96.5 37.5q63 0 106.5 -42t43.5 -101q0 -74 -90 -129q-25 -16 -25 -35l100 -144 q0 -18 -18 -28q-115 73 -181.5 168t-66.5 176z" />
<glyph unicode="&#x201d;" horiz-adv-x="1042" d="M156 1389q0 59 43 101t106 42q62 0 96.5 -37.5t34.5 -97.5q0 -81 -66.5 -176t-181.5 -168q-18 10 -18 28l100 144q0 20 -24 35q-90 55 -90 129zM606 1389q0 59 43.5 101t106.5 42q62 0 96.5 -37.5t34.5 -97.5q0 -81 -66.5 -176t-181.5 -168q-18 10 -18 28l100 144 q0 19 -25 35q-90 55 -90 129z" />
<glyph unicode="&#x201e;" horiz-adv-x="1042" d="M156 156q0 59 43 101t106 42q62 0 96.5 -37.5t34.5 -97.5q0 -81 -66.5 -176t-181.5 -168q-18 10 -18 28l100 144q0 20 -24 35q-90 55 -90 129zM606 156q0 59 43.5 101t106.5 42q62 0 96.5 -37.5t34.5 -97.5q0 -81 -66.5 -176t-181.5 -168q-18 10 -18 28l100 144 q0 19 -25 35q-90 55 -90 129z" />
<glyph unicode="&#x2022;" horiz-adv-x="888" d="M246 547q0 82 57 140t139 58t140.5 -58t58.5 -140t-58.5 -139.5t-140.5 -57.5t-139 57.5t-57 139.5z" />
<glyph unicode="&#x2026;" horiz-adv-x="1437" d="M63 154q0 68 47.5 115.5t114.5 47.5q68 0 116 -48t48 -115t-48 -114.5t-116 -47.5q-67 0 -114.5 47t-47.5 115zM545 154q0 68 47.5 115.5t114.5 47.5t115 -47.5t48 -115.5q0 -67 -47.5 -114.5t-115.5 -47.5q-67 0 -114.5 47t-47.5 115zM1047 154q0 68 47 115.5t114 47.5 q68 0 116 -48t48 -115t-48 -114.5t-116 -47.5q-67 0 -114 47t-47 115z" />
<glyph unicode="&#x202f;" horiz-adv-x="409" />
<glyph unicode="&#x2039;" horiz-adv-x="735" d="M41 487l18 84l629 349l-20 -113l-494 -287l397 -237l-24 -117z" />
<glyph unicode="&#x203a;" horiz-adv-x="704" d="M31 166l28 117l492 237l-397 287l18 113l504 -349l-23 -110z" />
<glyph unicode="&#x205f;" horiz-adv-x="512" />
<glyph unicode="&#x20ac;" horiz-adv-x="1173" d="M-6 582l29 102h151q4 43 16 133h-145l29 103h137q24 103 59.5 190.5t90.5 167.5t124.5 136t165 89t207.5 33q59 0 110.5 -9t97 -30t78 -52.5t51.5 -78t19 -104.5q0 -87 -34.5 -138t-108.5 -51q-71 0 -117 53q35 10 62.5 67t27.5 101q0 14 -2 28.5t-10.5 37t-22.5 39 t-41.5 29t-64.5 12.5q-83 0 -158 -75t-126 -189t-84 -256h413l-28 -103h-406q-12 -66 -18 -133h401l-29 -102h-379v-27q0 -84 7 -143t24.5 -107t48.5 -76t78 -42.5t113 -14.5q119 0 186.5 17.5t128.5 64.5l4 -59q-88 -116 -198.5 -161.5t-264.5 -45.5q-67 0 -127 13.5 t-120.5 50t-103.5 93t-70 150.5t-27 215v72h-174z" />
<glyph unicode="&#x2122;" horiz-adv-x="776" d="M-47 1188q0 68 51.5 114t157.5 46q8 0 63.5 -5.5t89.5 -5.5q51 0 76 11q-13 -80 -51 -80q-19 0 -63.5 8t-57.5 10l-86 -399h-88l88 407q-58 -2 -90.5 -30t-32.5 -95q0 -17 8 -41q-65 0 -65 60zM305 887l139 430l84 12v-346l136 356h96l-78 -452h-88l55 319l-129 -319h-84 v268l-82 -268h-49z" />
<glyph unicode="&#xe000;" horiz-adv-x="1136" d="M0 0v1137h1137v-1137h-1137z" />
<glyph unicode="u" horiz-adv-x="1034" d="M-16 233q0 56 16 134l139 657h295l-147 -696q-6 -30 -6 -58q0 -84 61 -84q109 0 164 181l139 657h295l-147 -696q-9 -40 -9 -66q0 -42 20 -59t64 -17q57 0 99 49.5t67 131.5h86q-133 -379 -411 -379q-88 0 -141 49.5t-62 144.5q-118 -194 -303 -194q-98 0 -158.5 61 t-60.5 184z" />
<glyph unicode="&#x2000;" horiz-adv-x="768" />
<glyph unicode="&#x2001;" horiz-adv-x="1536" />
<glyph unicode="&#x2002;" horiz-adv-x="768" />
<glyph unicode="&#x2003;" horiz-adv-x="1536" />
<glyph unicode="&#x2004;" horiz-adv-x="512" />
<glyph unicode="&#x2005;" horiz-adv-x="384" />
<glyph unicode="&#x2006;" horiz-adv-x="256" />
<glyph unicode="&#x2007;" horiz-adv-x="256" />
<glyph unicode="&#x2008;" horiz-adv-x="192" />
<glyph unicode="&#x2009;" horiz-adv-x="307" />
<glyph unicode="&#x200a;" horiz-adv-x="85" />
<glyph unicode="&#x202f;" horiz-adv-x="307" />
<glyph unicode="&#x205f;" horiz-adv-x="384" />
<glyph unicode="&#x25fc;" horiz-adv-x="1140" d="M0 0v1140h1140v-1140h-1140z" />
</font>
</defs></svg>

Before

Width:  |  Height:  |  Size: 85 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
couchpotato/static/fonts/Lobster-webfont.ttf

Binary file not shown.

BIN
couchpotato/static/fonts/Lobster-webfont.woff

Binary file not shown.

BIN
couchpotato/static/fonts/Lobster-webfont.woff2

Binary file not shown.

BIN
couchpotato/static/fonts/OpenSans-Light-webfont.eot

Binary file not shown.

1831
couchpotato/static/fonts/OpenSans-Light-webfont.svg

File diff suppressed because it is too large

After

Width:  |  Height:  |  Size: 114 KiB

BIN
couchpotato/static/fonts/OpenSans-Light-webfont.ttf

Binary file not shown.

BIN
couchpotato/static/fonts/OpenSans-Light-webfont.woff

Binary file not shown.

190
couchpotato/static/fonts/config.json

@ -0,0 +1,190 @@
{
"name": "icons",
"css_prefix_text": "icon-",
"css_use_suffix": false,
"hinting": true,
"units_per_em": 1000,
"ascent": 850,
"glyphs": [
{
"uid": "48cc210e59ff4bc56b6c8fba6eb384b8",
"css": "emo-coffee",
"code": 59401,
"src": "fontelico"
},
{
"uid": "078fec38562c3f83a1201a908040c141",
"css": "emo-sunglasses",
"code": 59402,
"src": "fontelico"
},
{
"uid": "04688d76a33ce7a7950e40fae79c08ac",
"css": "emo-cry",
"code": 59400,
"src": "fontelico"
},
{
"uid": "9dd9e835aebe1060ba7190ad2b2ed951",
"css": "search",
"code": 59394,
"src": "fontawesome"
},
{
"uid": "474656633f79ea2f1dad59ff63f6bf07",
"css": "star",
"code": 59418,
"src": "fontawesome"
},
{
"uid": "d17030afaecc1e1c22349b99f3c4992a",
"css": "star-empty",
"code": 59419,
"src": "fontawesome"
},
{
"uid": "84cf1fcc3fec556e7eaeb19679ca2dc9",
"css": "star-half",
"code": 59420,
"src": "fontawesome"
},
{
"uid": "872d9516df93eb6b776cc4d94bd97dac",
"css": "movie",
"code": 59416,
"src": "fontawesome"
},
{
"uid": "b1887b423d2fd15c345e090320c91ca0",
"css": "thumbs",
"code": 59397,
"src": "fontawesome"
},
{
"uid": "f805bb95d40c7ef2bc51b3d50d4f2e5c",
"css": "list",
"code": 59398,
"src": "fontawesome"
},
{
"uid": "12f4ece88e46abd864e40b35e05b11cd",
"css": "ok",
"code": 59408,
"src": "fontawesome"
},
{
"uid": "5211af474d3a9848f67f945e2ccaf143",
"css": "cancel",
"code": 59406,
"src": "fontawesome"
},
{
"uid": "44e04715aecbca7f266a17d5a7863c68",
"css": "plus",
"code": 59411,
"src": "fontawesome"
},
{
"uid": "3d4ea8a78dc34efe891f3a0f3d961274",
"css": "info",
"code": 59403,
"src": "fontawesome"
},
{
"uid": "d7271d490b71df4311e32cdacae8b331",
"css": "home",
"code": 59415,
"src": "fontawesome"
},
{
"uid": "c5fd349cbd3d23e4ade333789c29c729",
"css": "eye",
"code": 59412,
"src": "fontawesome"
},
{
"uid": "9a76bc135eac17d2c8b8ad4a5774fc87",
"css": "download",
"code": 59404,
"src": "fontawesome"
},
{
"uid": "f48ae54adfb27d8ada53d0fd9e34ee10",
"css": "delete",
"code": 59405,
"src": "fontawesome"
},
{
"uid": "e99461abfef3923546da8d745372c995",
"css": "settings",
"code": 59393,
"src": "fontawesome"
},
{
"uid": "bc71f4c6e53394d5ba46b063040014f1",
"css": "redo",
"code": 59407,
"src": "fontawesome"
},
{
"uid": "a73c5deb486c8d66249811642e5d719a",
"css": "refresh",
"code": 59414,
"src": "fontawesome"
},
{
"uid": "4109c474ff99cad28fd5a2c38af2ec6f",
"css": "filter",
"code": 59396,
"src": "fontawesome"
},
{
"uid": "026007bd17bfc67f3fe013199676f620",
"css": "donate",
"code": 59421,
"src": "fontawesome"
},
{
"uid": "94103e1b3f1e8cf514178ec5912b4469",
"css": "dropdown",
"code": 59409,
"src": "fontawesome"
},
{
"uid": "2cfb3f2b46b34a1790aec0aa846297b6",
"css": "menu",
"code": 59417,
"src": "entypo"
},
{
"uid": "c311c48d79488965b0fab7f9cd12b6b5",
"css": "left-arrow",
"code": 59392,
"src": "entypo"
},
{
"uid": "cb13afd4722a849d48056540bb74c47e",
"css": "play",
"code": 59410,
"src": "entypo"
},
{
"uid": "d10920db2e79c997c5e783279291970c",
"css": "dots",
"code": 59395,
"src": "entypo"
},
{
"uid": "51fb22f9ff9d7f60c95ef31e4c59502d",
"css": "notifications",
"code": 59399,
"src": "mfglabs"
},
{
"uid": "3ab229dd9bccaaaf6c71096da4b72c04",
"css": "error",
"code": 59413,
"src": "elusive"
}
]
}

BIN
couchpotato/static/fonts/icons.eot

Binary file not shown.

41
couchpotato/static/fonts/icons.svg

@ -0,0 +1,41 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Copyright (C) 2015 by original authors @ fontello.com</metadata>
<defs>
<font id="icons" horiz-adv-x="1000" >
<font-face font-family="icons" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
<missing-glyph horiz-adv-x="1000" />
<glyph glyph-name="left-arrow" unicode="&#xe800;" d="m242 626q14 16 39 16t41-16q38-36 0-80l-186-196 186-194q38-44 0-80-16-16-40-16t-40 16l-226 236q-16 16-16 38 0 24 16 40 206 214 226 236z" horiz-adv-x="341" />
<glyph glyph-name="settings" unicode="&#xe801;" d="m571 350q0 59-41 101t-101 42-101-42-42-101 42-101 101-42 101 42 41 101z m286 61v-124q0-7-4-13t-11-7l-104-16q-10-30-21-51 19-27 59-77 6-6 6-13t-5-13q-15-21-55-61t-53-39q-7 0-14 5l-77 60q-25-13-51-21-9-76-16-104-4-16-20-16h-124q-8 0-14 5t-6 12l-16 103q-27 9-50 21l-79-60q-6-5-14-5-8 0-14 6-70 64-92 94-4 5-4 13 0 6 5 12 8 12 28 37t30 40q-15 28-23 55l-102 15q-7 1-11 7t-5 13v124q0 7 5 13t10 7l104 16q8 25 22 51-23 32-60 77-6 7-6 14 0 5 5 12 15 20 55 60t53 40q7 0 15-5l77-60q24 13 50 21 9 76 17 104 3 15 20 15h124q7 0 13-4t7-12l15-103q28-9 50-21l80 60q5 5 13 5 7 0 14-5 72-67 92-95 4-5 4-13 0-6-4-12-9-12-29-38t-30-39q14-28 23-55l102-15q7-1 12-7t4-13z" horiz-adv-x="857.1" />
<glyph glyph-name="search" unicode="&#xe802;" d="m643 386q0 103-74 176t-176 74-177-74-73-176 73-177 177-73 176 73 74 177z m286-465q0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 84-84 125-31 153 31 152 84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51z" horiz-adv-x="928.6" />
<glyph glyph-name="dots" unicode="&#xe803;" d="m110 460q46 0 78-32t32-78q0-44-32-77t-78-33-78 33-32 77q0 46 32 78t78 32z m350 0q46 0 78-32t32-78q0-44-33-77t-77-33-77 33-33 77q0 46 32 78t78 32z m350 0q46 0 78-32t32-78q0-44-32-77t-78-33-78 33-32 77q0 46 32 78t78 32z" horiz-adv-x="920" />
<glyph glyph-name="filter" unicode="&#xe804;" d="m783 685q9-23-8-39l-275-275v-414q0-23-22-33-7-3-14-3-15 0-25 11l-143 143q-10 10-10 25v271l-275 275q-18 16-8 39 9 22 33 22h714q23 0 33-22z" horiz-adv-x="785.7" />
<glyph glyph-name="thumbs" unicode="&#xe805;" d="m286 154v-108q0-22-16-37t-38-16h-178q-23 0-38 16t-16 37v108q0 22 16 38t38 15h178q22 0 38-15t16-38z m0 285v-107q0-22-16-38t-38-15h-178q-23 0-38 15t-16 38v107q0 23 16 38t38 16h178q22 0 38-16t16-38z m357-285v-108q0-22-16-37t-38-16h-178q-23 0-38 16t-16 37v108q0 22 16 38t38 15h178q23 0 38-15t16-38z m-357 571v-107q0-22-16-38t-38-16h-178q-23 0-38 16t-16 38v107q0 22 16 38t38 16h178q22 0 38-16t16-38z m357-286v-107q0-22-16-38t-38-15h-178q-23 0-38 15t-16 38v107q0 23 16 38t38 16h178q23 0 38-16t16-38z m357-285v-108q0-22-16-37t-38-16h-178q-22 0-38 16t-16 37v108q0 22 16 38t38 15h178q23 0 38-15t16-38z m-357 571v-107q0-22-16-38t-38-16h-178q-23 0-38 16t-16 38v107q0 22 16 38t38 16h178q23 0 38-16t16-38z m357-286v-107q0-22-16-38t-38-15h-178q-22 0-38 15t-16 38v107q0 23 16 38t38 16h178q23 0 38-16t16-38z m0 286v-107q0-22-16-38t-38-16h-178q-22 0-38 16t-16 38v107q0 22 16 38t38 16h178q23 0 38-16t16-38z" horiz-adv-x="1000" />
<glyph glyph-name="list" unicode="&#xe806;" d="m286 154v-108q0-22-16-37t-38-16h-178q-23 0-38 16t-16 37v108q0 22 16 38t38 15h178q22 0 38-15t16-38z m0 285v-107q0-22-16-38t-38-15h-178q-23 0-38 15t-16 38v107q0 23 16 38t38 16h178q22 0 38-16t16-38z m714-285v-108q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v108q0 22 16 38t38 15h535q23 0 38-15t16-38z m-714 571v-107q0-22-16-38t-38-16h-178q-23 0-38 16t-16 38v107q0 22 16 38t38 16h178q22 0 38-16t16-38z m714-286v-107q0-22-16-38t-38-15h-535q-23 0-38 15t-16 38v107q0 23 16 38t38 16h535q23 0 38-16t16-38z m0 286v-107q0-22-16-38t-38-16h-535q-23 0-38 16t-16 38v107q0 22 16 38t38 16h535q23 0 38-16t16-38z" horiz-adv-x="1000" />
<glyph glyph-name="notifications" unicode="&#xe807;" d="m0 404q0 67 27 130t75 114 114 89 145 59 166 21 166-21 146-59 113-89 76-114 26-130q0-84-42-160t-112-131-168-88-205-33q-105 0-201 31l-121-85q-67-42-94-24t-12 100l25 125q-60 55-92 122t-32 143z" horiz-adv-x="1054.7" />
<glyph glyph-name="emo-cry" unicode="&#xe808;" d="m278 787c-7 0-15-2-23-5l-128-62-80-38c-2-1-4-2-6-3-1-5-1-11-1-16l0 0 0-1 0 0c0-69 40-162 122-163l0 0 0 0 0 0c34 1 65 19 87 50 26 35 37 82 34 128l18 8c27 13 38 45 25 71-9 19-28 31-48 31z m212 0c-20 0-39-11-48-30-13-27-1-59 25-71l18-9c-3-46 9-93 34-128 22-31 53-49 87-49l0 0 1 0 0 0c82 0 121 93 122 162l0 0 0 1 0 0c0 5-1 11-1 16-2 1-5 2-7 3l-80 38-128 62c-7 3-15 5-23 5z m279-302c-7 0-15-5-21-16-42-72-96-259 27-259 123 1 73 182 16 261-6 8-14 13-22 14z m-512-138c-57 0-112-9-166-26-10-4-20-7-30-11-11-5-21-9-30-13l0 0-1-1 0 0c-26-12-37-44-25-70 13-26 44-38 70-25l0-1c9 5 17 8 24 11 9 3 17 6 25 9 43 14 88 21 133 21 51 0 101-9 148-27 19-7 37-15 55-24 91-49 163-130 200-232 10-27 40-41 68-31 27 10 42 40 32 68-46 126-137 227-250 288-22 12-45 22-69 31-57 21-120 33-184 33z" horiz-adv-x="851" />
<glyph glyph-name="emo-coffee" unicode="&#xe809;" d="m1234 850c-17 0-34-8-44-23-54-80-24-144 4-204 13-29 26-56 5-72-23-17-28-51-10-74 17-23 51-28 74-10 89 67 60 131 27 201-15 33-32 70-12 99 16 25 10 57-14 74-9 6-20 9-30 9z m-1021-121c-81 0-157-39-203-105-18-25-12-59 14-77 24-17 59-11 76 14 45 63 132 76 193 32l0 0c3-2 7-6 11-9l1-1 1-1c3-3 7-7 10-10l1-2 0 0 0 0 1-1 1 0c20-23 55-25 78-4 22 20 24 55 4 77-46 55-116 87-188 87z m499 0c-80 0-156-39-202-105-18-25-12-59 13-77 25-17 59-11 77 14 44 63 131 76 192 32l0 0c4-2 8-6 12-9l0-1 1-1c4-3 7-7 11-10l1-2 0 0 0 0 1-1 0 0c20-23 55-25 78-4 23 20 25 55 4 77-46 55-116 87-188 87z m206-346c-24 0-44-19-44-43l1-4-1-275 0 0 0 0 0 0c0-58 24-111 62-149l0 0 0 0 0 0c38-38 91-62 148-62l0 0 226 0c1 0 3 0 5 0 13 1 27 2 39 5 15 4 29 8 42 14 55 26 97 74 114 133l31 0 0 0c37 0 70 15 94 39 23 23 38 56 38 92l0 0 0 0 0 119 0 0c0 36-15 69-39 93l0 0c-23 23-56 38-92 38l0 0 0 0-624 0z m604-100c11 0 21-5 28-12l1 0 0 0c7-8 12-18 12-29l0 0 0-110 0 0c0-11-5-21-12-29-8-7-18-12-29-12l0 0-62 0 0 0c-21 0-39-16-40-37-4-41-31-76-67-93-7-3-15-6-22-8-7-1-14-2-21-2l-3 0-209 0 0-1c-30 1-59 13-79 34l-1 0c-21 21-34 50-34 81l0 0 0 0 0 0 1 218 537 0 0 0z m-82-55l0-96 32 0c22 0 39 17 39 38l0 20c0 21-17 38-39 38l-32 0z m-1131-12c-30 0-55-25-55-55s25-55 55-55l297 0c30 0 54 25 54 55s-24 55-54 55l-297 0z" horiz-adv-x="1673" />
<glyph glyph-name="emo-sunglasses" unicode="&#xe80a;" d="m495 745c-154 0-309 0-463 0-18 0-32-15-32-33 3-153 129-306 278-309 84-2 164 36 218 95 55-59 135-97 219-95 149 3 272 156 275 309 0 18-14 33-32 33-155 0-309 0-463 0z m319-510c-18 0-35-9-45-25l0 0c0-1-1-2-1-3-7-12-15-23-24-34-10-12-19-23-29-32-54-51-126-80-203-80l0 0 0 0c-21 0-43 2-64 7-3 0-6 1-10 2-17 5-34 11-51 19-26 12-58 1-70-26-13-27-1-58 25-71 22-10 45-18 69-24 5-1 9-2 14-4 29-6 58-9 87-9l0 0 0 0c104 0 201 39 275 108 15 14 28 29 40 43 11 15 22 31 32 48 0 0 1 1 1 1 15 25 7 58-18 73-9 5-18 7-28 7z" horiz-adv-x="990" />
<glyph glyph-name="info" unicode="&#xe80b;" d="m357 100v-71q0-15-10-25t-26-11h-285q-15 0-25 11t-11 25v71q0 15 11 25t25 11h35v214h-35q-15 0-25 11t-11 25v71q0 15 11 25t25 11h214q15 0 25-11t11-25v-321h35q15 0 26-11t10-25z m-71 643v-107q0-15-11-25t-25-11h-143q-14 0-25 11t-11 25v107q0 14 11 25t25 11h143q15 0 25-11t11-25z" horiz-adv-x="357.1" />
<glyph glyph-name="download" unicode="&#xe80c;" d="m714 100q0 15-10 25t-25 11-26-11-10-25 10-25 26-11 25 11 10 25z m143 0q0 15-10 25t-26 11-25-11-10-25 10-25 25-11 26 11 10 25z m72 125v-179q0-22-16-37t-38-16h-821q-23 0-38 16t-16 37v179q0 22 16 38t38 16h259l75-76q33-32 76-32t76 32l76 76h259q22 0 38-16t16-38z m-182 318q10-23-8-40l-250-250q-10-10-25-10t-25 10l-250 250q-17 17-8 40 10 21 33 21h143v250q0 15 11 25t25 11h143q14 0 25-11t10-25v-250h143q24 0 33-21z" horiz-adv-x="928.6" />
<glyph glyph-name="delete" unicode="&#xe80d;" d="m286 439v-321q0-8-5-13t-13-5h-36q-8 0-13 5t-5 13v321q0 8 5 13t13 5h36q8 0 13-5t5-13z m143 0v-321q0-8-5-13t-13-5h-36q-8 0-13 5t-5 13v321q0 8 5 13t13 5h36q8 0 13-5t5-13z m142 0v-321q0-8-5-13t-12-5h-36q-8 0-13 5t-5 13v321q0 8 5 13t13 5h36q7 0 12-5t5-13z m72-404v529h-500v-529q0-12 4-22t8-15 6-5h464q2 0 6 5t8 15 4 22z m-375 601h250l-27 65q-4 5-9 6h-177q-6-1-10-6z m518-18v-36q0-8-5-13t-13-5h-54v-529q0-46-26-80t-63-34h-464q-37 0-63 33t-27 79v531h-53q-8 0-13 5t-5 13v36q0 8 5 13t13 5h172l39 93q9 21 31 35t44 15h178q22 0 44-15t30-35l39-93h173q8 0 13-5t5-13z" horiz-adv-x="785.7" />
<glyph glyph-name="cancel" unicode="&#xe80e;" d="m724 112q0-22-15-38l-76-76q-16-15-38-15t-38 15l-164 165-164-165q-16-15-38-15t-38 15l-76 76q-16 16-16 38t16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38z" horiz-adv-x="785.7" />
<glyph glyph-name="redo" unicode="&#xe80f;" d="m857 707v-250q0-14-10-25t-26-11h-250q-23 0-32 23-10 22 7 38l77 77q-82 77-194 77-58 0-111-23t-91-61-62-91-22-111 22-111 62-91 91-61 111-23q66 0 125 29t100 82q4 6 13 7 8 0 14-5l76-77q5-4 6-11t-5-13q-60-74-147-114t-182-41q-87 0-167 34t-136 92-92 137-34 166 34 166 92 137 136 92 167 34q82 0 158-31t137-88l72 72q16 18 39 8 22-9 22-33z" horiz-adv-x="857.1" />
<glyph glyph-name="ok" unicode="&#xe810;" d="m932 534q0-22-15-38l-404-404-76-76q-16-15-38-15t-38 15l-76 76-202 202q-15 16-15 38t15 38l76 76q16 16 38 16t38-16l164-165 366 367q16 16 38 16t38-16l76-76q15-16 15-38z" horiz-adv-x="1000" />
<glyph glyph-name="dropdown" unicode="&#xe811;" d="m571 243q0-15-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 10-11 25t11 25 25 11h500q14 0 25-11t10-25z" horiz-adv-x="571.4" />
<glyph glyph-name="play" unicode="&#xe812;" d="m486 376q14-10 14-26 0-14-14-24l-428-266q-24-16-41-6t-17 40l0 514q0 30 17 40t41-6z" horiz-adv-x="500" />
<glyph glyph-name="plus" unicode="&#xe813;" d="m786 439v-107q0-22-16-38t-38-15h-232v-233q0-22-16-37t-38-16h-107q-22 0-38 16t-15 37v233h-232q-23 0-38 15t-16 38v107q0 23 16 38t38 16h232v232q0 22 15 38t38 16h107q23 0 38-16t16-38v-232h232q22 0 38-16t16-38z" horiz-adv-x="785.7" />
<glyph glyph-name="eye" unicode="&#xe814;" d="m929 314q-85 132-213 197 34-58 34-125 0-104-73-177t-177-73-177 73-73 177q0 67 34 125-128-65-213-197 75-114 187-182t242-68 242 68 187 182z m-402 215q0 11-8 19t-19 7q-70 0-120-50t-50-119q0-12 8-19t19-8 19 8 8 19q0 48 34 82t82 34q11 0 19 8t8 19z m473-215q0-19-11-38-78-129-210-206t-279-77-279 77-210 206q-11 19-11 38t11 39q78 128 210 205t279 78 279-78 210-205q11-20 11-39z" horiz-adv-x="1000" />
<glyph glyph-name="error" unicode="&#xe815;" d="m0 350q0 207 147 354t353 146 354-146 146-354-146-354-354-146-353 146-147 354z m137 0q0-150 106-257t257-106 257 106 106 257-106 257-257 106-257-106-106-257z m97-98l0 196 532 0 0-196-532 0z" horiz-adv-x="1000" />
<glyph glyph-name="refresh" unicode="&#xe816;" d="m843 261q0-3 0-4-36-150-150-243t-267-93q-81 0-157 31t-136 88l-72-72q-11-11-25-11t-25 11-11 25v250q0 14 11 25t25 11h250q14 0 25-11t10-25-10-25l-77-77q40-37 90-57t105-20q74 0 139 37t104 99q6 10 29 66 5 13 17 13h107q8 0 13-6t5-12z m14 446v-250q0-14-10-25t-26-11h-250q-14 0-25 11t-10 25 10 25l77 77q-82 77-194 77-75 0-140-37t-104-99q-6-10-29-66-5-13-17-13h-111q-7 0-13 6t-5 12v4q36 150 151 243t268 93q81 0 158-31t137-88l72 72q11 11 25 11t26-11 10-25z" horiz-adv-x="857.1" />
<glyph glyph-name="home" unicode="&#xe817;" d="m786 296v-267q0-15-11-26t-25-10h-214v214h-143v-214h-214q-15 0-25 10t-11 26v267q0 1 0 2t0 2l321 264 321-264q1-1 1-4z m124 39l-34-41q-5-5-12-6h-2q-7 0-12 3l-386 322-386-322q-7-4-13-4-7 2-12 7l-35 41q-4 5-3 13t6 12l401 334q18 15 42 15t43-15l136-114v109q0 8 5 13t13 5h107q8 0 13-5t5-13v-227l122-102q5-5 6-12t-4-13z" horiz-adv-x="928.6" />
<glyph glyph-name="movie" unicode="&#xe818;" d="m214-43v72q0 14-10 25t-25 10h-72q-14 0-25-10t-11-25v-72q0-14 11-25t25-11h72q14 0 25 11t10 25z m0 214v72q0 14-10 25t-25 11h-72q-14 0-25-11t-11-25v-72q0-14 11-25t25-10h72q14 0 25 10t10 25z m0 215v71q0 15-10 25t-25 11h-72q-14 0-25-11t-11-25v-71q0-15 11-25t25-11h72q14 0 25 11t10 25z m572-429v286q0 14-11 25t-25 11h-429q-14 0-25-11t-10-25v-286q0-14 10-25t25-11h429q15 0 25 11t11 25z m-572 643v71q0 15-10 26t-25 10h-72q-14 0-25-10t-11-26v-71q0-15 11-25t25-11h72q14 0 25 11t10 25z m786-643v72q0 14-11 25t-25 10h-71q-15 0-25-10t-11-25v-72q0-14 11-25t25-11h71q15 0 25 11t11 25z m-214 429v285q0 15-11 26t-25 10h-429q-14 0-25-10t-10-26v-285q0-15 10-25t25-11h429q15 0 25 11t11 25z m214-215v72q0 14-11 25t-25 11h-71q-15 0-25-11t-11-25v-72q0-14 11-25t25-10h71q15 0 25 10t11 25z m0 215v71q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-71q0-15 11-25t25-11h71q15 0 25 11t11 25z m0 214v71q0 15-11 26t-25 10h-71q-15 0-25-10t-11-26v-71q0-15 11-25t25-11h71q15 0 25 11t11 25z m71 89v-750q0-37-26-63t-63-26h-893q-36 0-63 26t-26 63v750q0 37 26 63t63 27h893q37 0 63-27t26-63z" horiz-adv-x="1071.4" />
<glyph glyph-name="menu" unicode="&#xe819;" d="m650 400q22 0 36-15t14-35-15-35-35-15l-600 0q-20 0-35 15t-15 35 14 35 36 15l600 0z m-600 100q-20 0-35 15t-15 35 14 35 36 15l600 0q22 0 36-15t14-35-15-35-35-15l-600 0z m600-300q22 0 36-15t14-35-15-35-35-15l-600 0q-20 0-35 15t-15 35 14 35 36 15l600 0z" horiz-adv-x="700" />
<glyph glyph-name="star" unicode="&#xe81a;" d="m929 489q0-12-15-27l-203-197 48-279q1-4 1-12 0-11-6-19t-17-9q-10 0-22 7l-251 132-250-132q-13-7-23-7-11 0-17 9t-6 19q0 4 1 12l48 279-203 197q-14 15-14 27 0 21 31 26l280 40 126 254q11 23 27 23t28-23l125-254 280-40q32-5 32-26z" horiz-adv-x="928.6" />
<glyph glyph-name="star-empty" unicode="&#xe81b;" d="m634 290l171 165-235 35-106 213-105-213-236-35 171-165-41-235 211 111 211-111z m295 199q0-12-15-27l-203-197 48-279q1-4 1-12 0-28-23-28-10 0-22 7l-251 132-250-132q-13-7-23-7-11 0-17 9t-6 19q0 4 1 12l48 279-203 197q-14 15-14 27 0 21 31 26l280 40 126 254q11 23 27 23t28-23l125-254 280-40q32-5 32-26z" horiz-adv-x="928.6" />
<glyph glyph-name="star-half" unicode="&#xe81c;" d="m662 316l143 139-198 29-37 6-17 34-89 179v-537l33-17 178-94-34 198-7 37z m252 146l-202-197 47-279q3-19-3-29t-19-11q-9 0-22 7l-251 132-250-132q-13-7-23-7-12 0-19 11t-3 29l48 279-203 197q-18 18-13 33t30 20l280 40 126 254q11 23 27 23 16 0 28-23l125-254 280-40q25-4 30-20t-13-33z" horiz-adv-x="928.6" />
<glyph glyph-name="donate" unicode="&#xe81d;" d="m546 189q0-86-56-147t-144-77v-97q0-8-5-13t-13-5h-75q-7 0-13 5t-5 13v97q-37 5-71 18t-57 25-41 26-26 21-10 10q-9 12-1 23l58 76q3 5 12 6 9 1 14-5l1-1q63-55 135-70 21-4 42-4 45 0 79 24t35 68q0 16-9 30t-18 23-33 21-37 18-45 18q-21 9-34 14t-34 15-35 17-32 20-29 24-25 27-20 32-11 37-5 44q0 77 55 135t142 75v100q0 7 5 13t13 5h75q8 0 13-5t5-13v-98q32-4 62-13t48-19 36-21 21-16 9-8q9-10 3-21l-46-81q-4-9-12-9-8-2-16 4-1 1-8 6t-21 15-33 18-42 15-47 6q-53 0-87-24t-33-62q0-14 4-27t17-23 22-18 31-18 34-15 39-15q30-11 45-18t43-19 42-24 34-28 30-35 18-43 7-52z" horiz-adv-x="571.4" />
</font>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

BIN
couchpotato/static/fonts/icons.ttf

Binary file not shown.

BIN
couchpotato/static/fonts/icons.woff

Binary file not shown.

8
couchpotato/static/scripts/api.js

@ -14,16 +14,16 @@ var ApiClass = new Class({
'callbackKey': 'callback_func',
'method': 'get',
'url': self.createUrl(type, {'t': randomString()})
}, options)).send()
}, options)).send();
},
createUrl: function(action, params){
return this.options.url + (action || 'default') + '/' + (params ? '?'+Object.toQueryString(params) : '')
return this.options.url + (action || 'default') + '/' + (params ? '?'+Object.toQueryString(params) : '');
},
getOption: function(name){
return this.options[name]
return this.options[name];
}
});
window.Api = new ApiClass();
window.Api = new ApiClass();

8
couchpotato/static/scripts/block.js

@ -1,6 +1,6 @@
var BlockBase = new Class({
Implements: [Options, Events],
Implements: [Options],
options: {},
@ -19,7 +19,7 @@ var BlockBase = new Class({
},
getParent: function(){
return this.page
return this.page;
},
hide: function(){
@ -31,9 +31,7 @@ var BlockBase = new Class({
},
toElement: function(){
return this.el
return this.el;
}
});
var Block = BlockBase;

4
couchpotato/static/scripts/block/footer.js

@ -1,4 +1,4 @@
Block.Footer = new Class({
var BlockFooter = new Class({
Extends: BlockBase,
@ -8,4 +8,4 @@ Block.Footer = new Class({
self.el = new Element('div.footer');
}
});
});

52
couchpotato/static/scripts/block/header.js

@ -0,0 +1,52 @@
var BlockHeader = new Class({
Extends: BlockNavigation,
create: function(){
var self = this,
animation_options = {
type: dynamics.spring
},
couch, potato;
self.parent();
self.el.adopt(
self.logo = new Element('a.logo', {
'href': App.createUrl(''),
'events': {
'mouseenter': function(){
dynamics.animate(couch, {
opacity: 0,
translateX: -50
}, animation_options);
dynamics.animate(potato, {
opacity: 1,
translateX: 0
}, animation_options);
},
'mouseleave': function(){
dynamics.animate(couch, {
opacity: 1,
translateX: 0
}, animation_options);
dynamics.animate(potato, {
opacity: 0,
translateX: 50
}, animation_options);
}
}
}).adopt(
couch = new Element('span[text=Couch]'),
potato = new Element('span[text=Potato]')
),
self.nav
);
}
});

110
couchpotato/static/scripts/block/menu.js

@ -1,46 +1,120 @@
Block.Menu = new Class({
var BlockMenu = new Class({
Extends: BlockBase,
Implements: [Options, Events],
options: {
'class': 'menu'
},
lis: null,
create: function(){
var self = this;
self.lis = [];
self.shown = false;
self.el = new Element('div', {
'class': 'more_menu '+self.options['class']
}).adopt(
self.wrapper = new Element('div.wrapper').adopt(
self.more_option_ul = new Element('ul')
),
self.button = new Element('a.button' + (self.options.button_class ? '.' + self.options.button_class : ''), {
self.button = new Element('a' + (self.options.button_class ? '.' + self.options.button_class : ''), {
'text': self.options.button_text || '',
'events': {
'click': function(){
self.el.toggleClass('show');
self.fireEvent(self.el.hasClass('show') ? 'open' : 'close');
if(self.el.hasClass('show')){
self.el.addEvent('outerClick', self.removeOuterClick.bind(self));
this.addEvent('outerClick', function(e){
if(e.target.get('tag') != 'input')
self.removeOuterClick()
})
if(!self.shown){
dynamics.css(self.wrapper, {
opacity: 0,
scale: 0.1,
display: 'block'
});
dynamics.animate(self.wrapper, {
opacity: 1,
scale: 1
}, {
type: dynamics.spring,
frequency: 200,
friction: 270,
duration: 800
});
if(self.lis === null)
self.lis = self.more_option_ul.getElements('> li').slice(0, 10);
self.lis.each(function(li, nr){
dynamics.css(li, {
opacity: 0,
translateY: 20
});
// Animate to final properties
dynamics.animate(li, {
opacity: 1,
translateY: 0
}, {
type: dynamics.spring,
frequency: 300,
friction: 435,
duration: 1000,
delay: 100 + nr * 40
});
});
self.shown = true;
}
else {
self.hide();
}
else
self.removeOuterClick()
self.fireEvent(self.shown ? 'open' : 'close');
if(self.shown){
self.el.addEvent('outerClick', self.removeOuterClick.bind(self));
this.addEvent('outerClick', function(e) {
if (e.target.get('tag') != 'input')
self.removeOuterClick();
});
}
else {
self.removeOuterClick();
}
}
}
})
)
);
},
hide: function(){
var self = this;
dynamics.animate(self.wrapper, {
opacity: 0,
scale: 0.1
}, {
type: dynamics.easeInOut,
duration: 300,
friction: 100,
complete: function(){
dynamics.css(self.wrapper, {
display: 'none'
});
}
});
self.shown = false;
},
removeOuterClick: function(){
var self = this;
self.hide();
self.el.removeClass('show');
self.el.removeEvents('outerClick');
@ -48,8 +122,12 @@ Block.Menu = new Class({
},
addLink: function(tab, position){
var self = this;
return new Element('li').adopt(tab).inject(self.more_option_ul, position || 'bottom');
var self = this,
li = new Element('li').adopt(tab).inject(self.more_option_ul, position || 'bottom');
self.lis = null;
return li;
}
});
});

71
couchpotato/static/scripts/block/navigation.js

@ -1,51 +1,14 @@
Block.Navigation = new Class({
var BlockNavigation = new Class({
Extends: BlockBase,
create: function(){
var self = this;
self.el = new Element('div.navigation').adopt(
self.foldout = new Element('a.foldout.icon2.menu', {
'events': {
'click': self.toggleMenu.bind(self)
}
}).grab(new Element('span.overlay')),
self.logo = new Element('a.logo', {
'text': 'CouchPotato',
'href': App.createUrl('')
}),
self.nav = new Element('ul'),
self.backtotop = new Element('a.backtotop', {
'text': 'back to top',
'events': {
'click': function(){
window.scroll(0,0)
}
},
'tween': {
'duration': 100
}
})
self.el = new Element('div.navigation').grab(
self.nav = new Element('ul')
);
new ScrollSpy({
min: 400,
onLeave: function(){
self.backtotop.fade('out')
},
onEnter: function(){
self.backtotop.fade('in')
}
});
self.nav.addEvents({
'click:relay(a)': function(){
if($(document.body).getParent().hasClass('menu_shown'))
self.toggleMenu();
}
})
},
addTab: function(name, tab){
@ -53,31 +16,7 @@ Block.Navigation = new Class({
return new Element('li.tab_'+(name || 'unknown')).grab(
new Element('a', tab)
).inject(self.nav)
},
toggleMenu: function(){
var self = this,
body = $(document.body),
html = body.getParent();
// Copy over settings menu
if(!self.added){
new Element('li.separator').inject(self.nav);
body.getElements('.header .more_menu.menu li a, .header .more_menu.menu li span.separator').each(function(el, nr){
if(nr <= 2) return;
if(el.get('tag') == 'a')
self.nav.grab(new Element('li').grab(el.clone().cloneEvents(el)));
else
self.nav.grab(new Element('li.separator'));
});
self.added = true;
}
html.toggleClass('menu_shown');
).inject(self.nav);
},
@ -89,4 +28,4 @@ Block.Navigation = new Class({
}
});
});

2069
couchpotato/static/scripts/combined.base.min.js

File diff suppressed because it is too large

3844
couchpotato/static/scripts/combined.plugins.min.js

File diff suppressed because it is too large

9028
couchpotato/static/scripts/combined.vendor.min.js

File diff suppressed because it is too large

243
couchpotato/static/scripts/couchpotato.js

@ -23,8 +23,6 @@
self.c = $(document.body);
self.route = new Route(self.defaults);
self.createLayout();
self.createPages();
@ -34,34 +32,65 @@
self.openPage(window.location.pathname);
History.addEvent('change', self.openPage.bind(self));
self.c.addEvent('click:relay(.header a, .navigation a, .movie_details a, .list_list .movie)', self.ripple.bind(self));
self.c.addEvent('click:relay(a[href^=/]:not([target]))', self.pushState.bind(self));
self.c.addEvent('click:relay(a[href^=http])', self.openDerefered.bind(self));
// Check if device is touchenabled
self.touch_device = 'ontouchstart' in window || navigator.msMaxTouchPoints;
if(self.touch_device)
if(self.touch_device){
self.c.addClass('touch_enabled');
FastClick.attach(document.body);
}
window.addEvent('resize', self.resize.bind(self));
self.resize();
},
resize: function(){
var self = this;
self.mobile_screen = Math.max(document.documentElement.clientWidth, window.innerWidth || 0) <= 480;
self.c[self.mobile_screen ? 'addClass' : 'removeClass']('mobile');
},
ripple: function(e, el){
var self = this,
button = el.getCoordinates(),
x = e.page.x - button.left,
y = e.page.y - button.top,
ripple = new Element('div.ripple', {
'styles': {
'left': x,
'top': y
}
});
ripple.inject(el);
setTimeout(function(){ ripple.addClass('animate'); }, 0);
setTimeout(function(){ ripple.dispose(); }, 2100);
},
getOption: function(name){
try {
return this.options[name];
}
catch(e){
return null
return null;
}
},
pushState: function(e){
pushState: function(e, el){
var self = this;
if((!e.meta && self.isMac()) || (!e.control && !self.isMac())){
if((!e.meta && App.isMac()) || (!e.control && !App.isMac())){
(e).preventDefault();
var url = e.target.get('href');
var url = el.get('href');
// Middle click
if(e.event && e.event.button == 1)
if(e.event && e.event.button === 1)
window.open(url);
else if(History.getPath() != url)
History.push(url);
@ -69,24 +98,33 @@
},
isMac: function(){
return Browser.platform == 'mac'
return Browser.platform == 'mac';
},
createLayout: function(){
var self = this;
self.block.header = new Block();
self.block.header = new BlockBase();
self.c.adopt(
$(self.block.header).addClass('header').adopt(
new Element('div').adopt(
self.block.navigation = new Block.Navigation(self, {}),
self.block.search = new Block.Search(self, {}),
self.block.more = new Block.Menu(self, {'button_class': 'icon2.cog'})
)
self.block.navigation = new BlockHeader(self, {}),
self.block.search = new BlockSearch(self, {}),
self.support = new Element('a.donate.icon-donate', {
'href': 'https://couchpota.to/support/',
'target': '_blank'
}).grab(
new Element('span', {
'text': 'Donate'
})
),
self.block.more = new BlockMenu(self, {'button_class': 'icon-settings'})
),
self.content = new Element('div.content'),
self.block.footer = new Block.Footer(self, {})
new Element('div.corner_background'),
self.content = new Element('div.content').adopt(
self.pages_container = new Element('div.pages'),
self.block.footer = new BlockFooter(self, {})
)
);
var setting_links = [
@ -100,7 +138,6 @@
'click': self.checkForUpdate.bind(self, null)
}
}),
new Element('span.separator'),
new Element('a', {
'text': 'Settings',
'href': App.createUrl('settings/general')
@ -109,7 +146,6 @@
'text': 'Logs',
'href': App.createUrl('log')
}),
new Element('span.separator'),
new Element('a', {
'text': 'Restart',
'events': {
@ -125,19 +161,19 @@
];
setting_links.each(function(a){
self.block.more.addLink(a)
self.block.more.addLink(a);
});
new ScrollSpy({
min: 10,
onLeave: function(){
$(self.block.header).removeClass('with_shadow')
$(self.block.header).removeClass('with_shadow');
},
onEnter: function(){
$(self.block.header).addClass('with_shadow')
$(self.block.header).addClass('with_shadow');
}
})
});
},
createPages: function(){
@ -145,7 +181,9 @@
var pages = [];
Object.each(Page, function(page_class, class_name){
var pg = new Page[class_name](self, {});
var pg = new Page[class_name](self, {
'level': 1
});
self.pages[class_name] = pg;
pages.include({
@ -158,28 +196,29 @@
pages.stableSort(self.sortPageByOrder).each(function(page){
page['class'].load();
self.fireEvent('load'+page.name);
$(page['class']).inject(self.content);
$(page['class']).inject(self.getPageContainer());
});
delete pages;
self.fireEvent('load');
},
sortPageByOrder: function(a, b){
return (a.order || 100) - (b.order || 100)
return (a.order || 100) - (b.order || 100);
},
openPage: function(url) {
var self = this;
var self = this,
route = new Route(self.defaults);
route.parse(rep(History.getPath()));
self.route.parse();
var page_name = self.route.getPage().capitalize();
var action = self.route.getAction();
var params = self.route.getParams();
var page_name = route.getPage().capitalize(),
action = route.getAction(),
params = route.getParams(),
current_url = route.getCurrentUrl(),
page;
var current_url = self.route.getCurrentUrl();
if(current_url == self.current_url)
return;
@ -187,12 +226,12 @@
self.current_page.hide();
try {
var page = self.pages[page_name] || self.pages.Home;
page = self.pages[page_name] || self.pages.Home;
page.open(action, params, current_url);
page.show();
}
catch(e){
console.error("Can't open page:" + url, e)
console.error("Can't open page:" + url, e);
}
self.current_page = page;
@ -201,11 +240,15 @@
},
getBlock: function(block_name){
return this.block[block_name]
return this.block[block_name];
},
getPage: function(name){
return this.pages[name]
return this.pages[name];
},
getPageContainer: function(){
return this.pages_container;
},
shutdown: function(){
@ -281,7 +324,7 @@
var onFailure = function(){
self.checkAvailable.delay(1000, self, [delay, onAvailable]);
self.fireEvent('unload');
}
};
var request = Api.request('app.available', {
'timeout': 2000,
@ -298,7 +341,7 @@
}
});
}).delay(delay || 0)
}).delay(delay || 0);
},
blockPage: function(message, title){
@ -306,35 +349,40 @@
self.unBlockPage();
self.mask = new Element('div.mask').adopt(
new Element('div').adopt(
self.mask = new Element('div.mask.with_message').adopt(
new Element('div.message').adopt(
new Element('h1', {'text': title || 'Unavailable'}),
new Element('div', {'text': message || 'Something must have crashed.. check the logs ;)'})
)
).fade('hide').inject(document.body).fade('in');
).inject(document.body);
createSpinner(self.mask, {
'top': -50
});
createSpinner(self.mask);
setTimeout(function(){
self.mask.addClass('show');
}, 10);
},
unBlockPage: function(){
var self = this;
if(self.mask)
self.mask.get('tween').start('opacity', 0).chain(function(){
this.element.destroy()
this.element.destroy();
});
},
createUrl: function(action, params){
return this.options.base_url + (action ? action+'/' : '') + (params ? '?'+Object.toQueryString(params) : '')
return this.options.base_url + (action ? action+'/' : '') + (params ? '?'+Object.toQueryString(params) : '');
},
openDerefered: function(e, el){
var self = this;
(e).stop();
var url = 'http://www.dereferer.org/?' + el.get('href');
var url = el.get('href');
if(self.getOption('dereferer')){
url = self.getOption('dereferer') + el.get('href');
}
if(el.get('target') == '_blank' || (e.meta && self.isMac()) || (e.control && !self.isMac()))
window.open(url);
@ -356,15 +404,17 @@
new Element('span.bookmarklet').adopt(
new Element('a.button.orange', {
'text': '+CouchPotato',
/* jshint ignore:start */
'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)})());",
/* jshint ignore:end */
'target': '',
'events': {
'click': function(e){
(e).stop();
alert('Drag it to your bookmark ;)')
alert('Drag it to your bookmark ;)');
}
}
}),
@ -399,22 +449,14 @@
}
// Create parallel callback
var callbacks = [];
self.global_events[name].each(function(handle){
callbacks.push(function(callback){
setTimeout(function(){
var results = handle.apply(handle, args || []);
callback(null, results || null);
});
});
// Fire events
async.parallel(callbacks, function(err, results){
if(err) p(err);
if(on_complete)
on_complete(results);
if(on_complete)
on_complete(results);
}, 0);
});
},
@ -440,77 +482,72 @@ window.App = new CouchPotato();
var Route = new Class({
defaults: {},
defaults: null,
page: '',
action: 'index',
params: {},
initialize: function(defaults){
var self = this;
self.defaults = defaults
self.defaults = defaults || {};
},
parse: function(){
parse: function(path){
var self = this;
var rep = function (pa) {
return pa.replace(Api.getOption('url'), '/').replace(App.getOption('base_url'), '/')
};
var path = rep(History.getPath());
if(path == '/' && location.hash){
path = rep(location.hash.replace('#', '/'))
path = rep(location.hash.replace('#', '/'));
}
self.current = path.replace(/^\/+|\/+$/g, '');
var url = self.current.split('/');
self.page = (url.length > 0) ? url.shift() : self.defaults.page;
self.action = (url.length > 0) ? url.shift() : self.defaults.action;
self.action = (url.length > 0) ? url.join('/') : self.defaults.action;
self.params = Object.merge({}, self.defaults.params);
if(url.length > 1){
var key;
url.each(function(el, nr){
if(nr%2 == 0)
if(nr%2 === 0)
key = el;
else if(key) {
self.params[key] = el;
key = null
key = null;
}
})
});
}
else if(url.length == 1){
self.params[url] = true;
}
return self
return self;
},
getPage: function(){
return this.page
return this.page;
},
getAction: function(){
return this.action
return this.action;
},
getParams: function(){
return this.params
return this.params;
},
getCurrentUrl: function(){
return this.current
return this.current;
},
get: function(param){
return this.params[param]
return this.params[param];
}
});
var p = function(){
if(typeof(console) !== 'undefined' && console != null)
console.log(arguments)
if(typeof(console) !== 'undefined' && console !== null)
console.log(arguments);
};
@ -553,14 +590,14 @@ var p = function(){
function randomString(length, extra) {
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz" + (extra ? '-._!@#$%^&*()+=' : '');
var stringLength = length || 8;
var randomString = '';
for (var i = 0; i < stringLength; i++) {
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz" + (extra ? '-._!@#$%^&*()+=' : ''),
string_length = length || 8,
random_string = '';
for (var i = 0; i < string_length; i++) {
var rnum = Math.floor(Math.random() * chars.length);
randomString += chars.charAt(rnum);
random_string += chars.charAt(rnum);
}
return randomString;
return random_string;
}
(function(){
@ -576,7 +613,7 @@ function randomString(length, extra) {
var valueOf = function(object, path) {
var ptr = object;
path.each(function(key) { ptr = ptr[key] });
path.each(function(key) { ptr = ptr[key]; });
return ptr;
};
@ -606,22 +643,12 @@ function randomString(length, extra) {
})();
var createSpinner = function(target, options){
var opts = Object.merge({
lines: 12,
length: 5,
width: 4,
radius: 9,
color: '#fff',
speed: 1.9,
trail: 53,
shadow: false,
hwaccel: true,
className: 'spinner',
zIndex: 2e9,
top: 'auto',
left: 'auto'
}, options);
return new Spinner(opts).spin(target);
var createSpinner = function(container){
var spinner = new Element('div.spinner');
container.grab(spinner);
return spinner;
};
var rep = function (pa) {
return pa.replace(Api.getOption('url'), '/').replace(App.getOption('base_url'), '/');
};

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save