From 01be3f30245a957cda5a36e12c13bf3fbb2504a9 Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 19 Aug 2015 23:38:17 +0200 Subject: [PATCH] Don't merge js and css files --- couchpotato/core/_base/clientscript.py | 113 ++--------------- couchpotato/core/_base/updater/main.py | 1 - couchpotato/core/plugins/base.py | 37 +----- couchpotato/templates/database.html | 2 +- couchpotato/templates/index.html | 9 +- couchpotato/templates/login.html | 4 +- libs/minify/__init__.py | 0 libs/minify/cssmin.py | 202 ------------------------------ libs/minify/jsmin.py | 218 --------------------------------- 9 files changed, 18 insertions(+), 568 deletions(-) delete mode 100644 libs/minify/__init__.py delete mode 100644 libs/minify/cssmin.py delete mode 100644 libs/minify/jsmin.py diff --git a/couchpotato/core/_base/clientscript.py b/couchpotato/core/_base/clientscript.py index 69f35f3..ab52003 100644 --- a/couchpotato/core/_base/clientscript.py +++ b/couchpotato/core/_base/clientscript.py @@ -1,13 +1,10 @@ import os -import re 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 tornado.web import StaticFileHandler log = CPLog(__name__) @@ -17,7 +14,7 @@ autoload = 'ClientScript' class ClientScript(Plugin): - core_static = { + paths = { 'style': [ 'style/combined.min.css', ], @@ -28,91 +25,24 @@ class ClientScript(Plugin): ], } - watches = {} - - original_paths = {'style': {}, 'script': {}} - paths = {'style': {}, 'script': {}} - comment = { - 'style': '/*** %s:%d ***/\n', - 'script': '// %s:%d\n' - } - - html = { - 'style': '', - '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) - addEvent('app.load', self.compile) + 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 compile(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.original_paths.get(file_type, {}) - for position in positions: - files = positions.get(position) - self._compile(file_type, files, position, position + '.' + ext) - - def _compile(self, file_type, paths, position, out): - - cache = Env.get('cache_dir') - out_name = out - minified_dir = os.path.join(cache, 'minified') + core_url = 'static/%s?%d' % (rel_path, tryInt(os.path.getmtime(file_path))) - data_combined = '' + updates_paths.append(core_url) - new_paths = [] - for x in paths: - file_path, url_path = x - - f = open(file_path, 'r').read() - - if not Env.get('dev'): - data = f - - data_combined += self.comment.get(file_type) % (ss(file_path), int(os.path.getmtime(file_path))) - data_combined += data + '\n\n' - else: - new_paths.append(x) - - # Combine all files together with some comments - if not Env.get('dev'): - - out_path = os.path.join(minified_dir, out_name) - self.createFile(out_path, data_combined.strip()) - - minified_url = 'minified/%s?%s' % (out_name, tryInt(os.path.getmtime(out))) - new_paths.append((out_path, {'url': minified_url})) - - self.paths[file_type][position] = new_paths + self.paths[static_type] = updates_paths def getStyles(self, *args, **kwargs): return self.get('style', *args, **kwargs) @@ -120,27 +50,8 @@ class ClientScript(Plugin): def getScripts(self, *args, **kwargs): return self.get('script', *args, **kwargs) - def get(self, type, location = 'head'): - if type in self.paths and location in self.paths[type]: - paths = self.paths[type][location] - return [x[1] for x in paths] + def get(self, type): + if type in self.paths: + return self.paths[type] return [] - - 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.original_paths[type].get(location): - self.original_paths[type][location] = [] - self.original_paths[type][location].append((file_path, api_path)) - - if not self.paths[type].get(location): - self.paths[type][location] = [] - self.paths[type][location].append((file_path, api_path)) diff --git a/couchpotato/core/_base/updater/main.py b/couchpotato/core/_base/updater/main.py index 3393930..d739911 100644 --- a/couchpotato/core/_base/updater/main.py +++ b/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 diff --git a/couchpotato/core/plugins/base.py b/couchpotato/core/plugins/base.py index e149381..b1db842 100644 --- a/couchpotato/core/plugins/base.py +++ b/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 = False _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 - 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) diff --git a/couchpotato/templates/database.html b/couchpotato/templates/database.html index e512538..3643f9c 100644 --- a/couchpotato/templates/database.html +++ b/couchpotato/templates/database.html @@ -4,7 +4,7 @@ - + {% end %} - {% for url in fireEvent('clientscript.get_scripts', location = 'head', single = True) %} - {% end %} - {% for url in fireEvent('clientscript.get_styles', location = 'head', single = True) %} - {% end %} - diff --git a/couchpotato/templates/login.html b/couchpotato/templates/login.html index 5d79dff..c9f4d1d 100644 --- a/couchpotato/templates/login.html +++ b/couchpotato/templates/login.html @@ -8,9 +8,9 @@ - {% for url in fireEvent('clientscript.get_styles', location = 'front', single = True) %} + {% for url in fireEvent('clientscript.get_styles', single = True) %} {% end %} - {% for url in fireEvent('clientscript.get_scripts', location = 'front', single = True) %}{% if 'combined.plugins' not in url %} + {% for url in fireEvent('clientscript.get_scripts', single = True) %}{% if 'combined.plugins' not in url %} {% end %}{% end %} diff --git a/libs/minify/__init__.py b/libs/minify/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/libs/minify/cssmin.py b/libs/minify/cssmin.py deleted file mode 100644 index 09beb19..0000000 --- a/libs/minify/cssmin.py +++ /dev/null @@ -1,202 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# `cssmin.py` - A Python port of the YUI CSS compressor. - - -from StringIO import StringIO # The pure-Python StringIO supports unicode. -import re - - -__version__ = '0.1.1' - - -def remove_comments(css): - """Remove all CSS comment blocks.""" - - iemac = False - preserve = False - comment_start = css.find("/*") - while comment_start >= 0: - # Preserve comments that look like `/*!...*/`. - # Slicing is used to make sure we don"t get an IndexError. - preserve = css[comment_start + 2:comment_start + 3] == "!" - - comment_end = css.find("*/", comment_start + 2) - if comment_end < 0: - if not preserve: - css = css[:comment_start] - break - elif comment_end >= (comment_start + 2): - if css[comment_end - 1] == "\\": - # This is an IE Mac-specific comment; leave this one and the - # following one alone. - comment_start = comment_end + 2 - iemac = True - elif iemac: - comment_start = comment_end + 2 - iemac = False - elif not preserve: - css = css[:comment_start] + css[comment_end + 2:] - else: - comment_start = comment_end + 2 - comment_start = css.find("/*", comment_start) - - return css - - -def remove_unnecessary_whitespace(css): - """Remove unnecessary whitespace characters.""" - - def pseudoclasscolon(css): - - """ - Prevents 'p :link' from becoming 'p:link'. - - Translates 'p :link' into 'p ___PSEUDOCLASSCOLON___link'; this is - translated back again later. - """ - - regex = re.compile(r"(^|\})(([^\{\:])+\:)+([^\{]*\{)") - match = regex.search(css) - while match: - css = ''.join([ - css[:match.start()], - match.group().replace(":", "___PSEUDOCLASSCOLON___"), - css[match.end():]]) - match = regex.search(css) - return css - - css = pseudoclasscolon(css) - # Remove spaces from before things. - css = re.sub(r"\s+([!{};:>+\(\)\],])", r"\1", css) - - # If there is a `@charset`, then only allow one, and move to the beginning. - css = re.sub(r"^(.*)(@charset \"[^\"]*\";)", r"\2\1", css) - css = re.sub(r"^(\s*@charset [^;]+;\s*)+", r"\1", css) - - # Put the space back in for a few cases, such as `@media screen` and - # `(-webkit-min-device-pixel-ratio:0)`. - css = re.sub(r"\band\(", "and (", css) - - # Put the colons back. - css = css.replace('___PSEUDOCLASSCOLON___', ':') - - # Remove spaces from after things. - css = re.sub(r"([!{}:;>+\(\[,])\s+", r"\1", css) - - return css - - -def remove_unnecessary_semicolons(css): - """Remove unnecessary semicolons.""" - - return re.sub(r";+\}", "}", css) - - -def remove_empty_rules(css): - """Remove empty rules.""" - - return re.sub(r"[^\}\{]+\{\}", "", css) - - -def normalize_rgb_colors_to_hex(css): - """Convert `rgb(51,102,153)` to `#336699`.""" - - regex = re.compile(r"rgb\s*\(\s*([0-9,\s]+)\s*\)") - match = regex.search(css) - while match: - colors = match.group(1).split(",") - hexcolor = '#%.2x%.2x%.2x' % tuple(map(int, colors)) - css = css.replace(match.group(), hexcolor) - match = regex.search(css) - return css - - -def condense_zero_units(css): - """Replace `0(px, em, %, etc)` with `0`.""" - - return re.sub(r"([\s:])(0)(px|em|%|in|cm|mm|pc|pt|ex)", r"\1\2", css) - - -def condense_multidimensional_zeros(css): - """Replace `:0 0 0 0;`, `:0 0 0;` etc. with `:0;`.""" - - css = css.replace(":0 0 0 0;", ":0;") - css = css.replace(":0 0 0;", ":0;") - css = css.replace(":0 0;", ":0;") - - # Revert `background-position:0;` to the valid `background-position:0 0;`. - css = css.replace("background-position:0;", "background-position:0 0;") - - return css - - -def condense_floating_points(css): - """Replace `0.6` with `.6` where possible.""" - - return re.sub(r"(:|\s)0+\.(\d+)", r"\1.\2", css) - - -def condense_hex_colors(css): - """Shorten colors from #AABBCC to #ABC where possible.""" - - regex = re.compile(r"([^\"'=\s])(\s*)#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])") - match = regex.search(css) - while match: - first = match.group(3) + match.group(5) + match.group(7) - second = match.group(4) + match.group(6) + match.group(8) - if first.lower() == second.lower(): - css = css.replace(match.group(), match.group(1) + match.group(2) + '#' + first) - match = regex.search(css, match.end() - 3) - else: - match = regex.search(css, match.end()) - return css - - -def condense_whitespace(css): - """Condense multiple adjacent whitespace characters into one.""" - - return re.sub(r"\s+", " ", css) - - -def condense_semicolons(css): - """Condense multiple adjacent semicolon characters into one.""" - - return re.sub(r";;+", ";", css) - - -def wrap_css_lines(css, line_length): - """Wrap the lines of the given CSS to an approximate length.""" - - lines = [] - line_start = 0 - for i, char in enumerate(css): - # It's safe to break after `}` characters. - if char == '}' and (i - line_start >= line_length): - lines.append(css[line_start:i + 1]) - line_start = i + 1 - - if line_start < len(css): - lines.append(css[line_start:]) - return '\n'.join(lines) - - -def cssmin(css, wrap = None): - css = remove_comments(css) - css = condense_whitespace(css) - # A pseudo class for the Box Model Hack - # (see http://tantek.com/CSS/Examples/boxmodelhack.html) - css = css.replace('"\\"}\\""', "___PSEUDOCLASSBMH___") - #css = remove_unnecessary_whitespace(css) - css = remove_unnecessary_semicolons(css) - css = condense_zero_units(css) - css = condense_multidimensional_zeros(css) - css = condense_floating_points(css) - css = normalize_rgb_colors_to_hex(css) - css = condense_hex_colors(css) - if wrap is not None: - css = wrap_css_lines(css, wrap) - css = css.replace("___PSEUDOCLASSBMH___", '"\\"}\\""') - css = condense_semicolons(css) - return css.strip() diff --git a/libs/minify/jsmin.py b/libs/minify/jsmin.py deleted file mode 100644 index a1b81f9..0000000 --- a/libs/minify/jsmin.py +++ /dev/null @@ -1,218 +0,0 @@ -#!/usr/bin/python - -# This code is original from jsmin by Douglas Crockford, it was translated to -# Python by Baruch Even. The original code had the following copyright and -# license. -# -# /* jsmin.c -# 2007-05-22 -# -# Copyright (c) 2002 Douglas Crockford (www.crockford.com) -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -# of the Software, and to permit persons to whom the Software is furnished to do -# so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# The Software shall be used for Good, not Evil. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# */ - -from StringIO import StringIO - -def jsmin(js): - ins = StringIO(js) - outs = StringIO() - JavascriptMinify().minify(ins, outs) - str = outs.getvalue() - if len(str) > 0 and str[0] == '\n': - str = str[1:] - return str - -def isAlphanum(c): - """return true if the character is a letter, digit, underscore, - dollar sign, or non-ASCII character. - """ - return ((c >= 'a' and c <= 'z') or (c >= '0' and c <= '9') or - (c >= 'A' and c <= 'Z') or c == '_' or c == '$' or c == '\\' or (c is not None and ord(c) > 126)); - -class UnterminatedComment(Exception): - pass - -class UnterminatedStringLiteral(Exception): - pass - -class UnterminatedRegularExpression(Exception): - pass - -class JavascriptMinify(object): - - def _outA(self): - self.outstream.write(self.theA) - def _outB(self): - self.outstream.write(self.theB) - - def _get(self): - """return the next character from stdin. Watch out for lookahead. If - the character is a control character, translate it to a space or - linefeed. - """ - c = self.theLookahead - self.theLookahead = None - if c == None: - c = self.instream.read(1) - if c >= ' ' or c == '\n': - return c - if c == '': # EOF - return '\000' - if c == '\r': - return '\n' - return ' ' - - def _peek(self): - self.theLookahead = self._get() - return self.theLookahead - - def _next(self): - """get the next character, excluding comments. peek() is used to see - if a '/' is followed by a '/' or '*'. - """ - c = self._get() - if c == '/': - p = self._peek() - if p == '/': - c = self._get() - while c > '\n': - c = self._get() - return c - if p == '*': - c = self._get() - while 1: - c = self._get() - if c == '*': - if self._peek() == '/': - self._get() - return ' ' - if c == '\000': - raise UnterminatedComment() - - return c - - def _action(self, action): - """do something! What you do is determined by the argument: - 1 Output A. Copy B to A. Get the next B. - 2 Copy B to A. Get the next B. (Delete A). - 3 Get the next B. (Delete B). - action treats a string as a single character. Wow! - action recognizes a regular expression if it is preceded by ( or , or =. - """ - if action <= 1: - self._outA() - - if action <= 2: - self.theA = self.theB - if self.theA == "'" or self.theA == '"': - while 1: - self._outA() - self.theA = self._get() - if self.theA == self.theB: - break - if self.theA <= '\n': - raise UnterminatedStringLiteral() - if self.theA == '\\': - self._outA() - self.theA = self._get() - - - if action <= 3: - self.theB = self._next() - if self.theB == '/' and (self.theA == '(' or self.theA == ',' or - self.theA == '=' or self.theA == ':' or - self.theA == '[' or self.theA == '?' or - self.theA == '!' or self.theA == '&' or - self.theA == '|' or self.theA == ';' or - self.theA == '{' or self.theA == '}' or - self.theA == '\n'): - self._outA() - self._outB() - while 1: - self.theA = self._get() - if self.theA == '/': - break - elif self.theA == '\\': - self._outA() - self.theA = self._get() - elif self.theA <= '\n': - raise UnterminatedRegularExpression() - self._outA() - self.theB = self._next() - - - def _jsmin(self): - """Copy the input to the output, deleting the characters which are - insignificant to JavaScript. Comments will be removed. Tabs will be - replaced with spaces. Carriage returns will be replaced with linefeeds. - Most spaces and linefeeds will be removed. - """ - self.theA = '\n' - self._action(3) - - while self.theA != '\000': - if self.theA == ' ': - if isAlphanum(self.theB): - self._action(1) - else: - self._action(2) - elif self.theA == '\n': - if self.theB in ['{', '[', '(', '+', '-']: - self._action(1) - elif self.theB == ' ': - self._action(3) - else: - if isAlphanum(self.theB): - self._action(1) - else: - self._action(2) - else: - if self.theB == ' ': - if isAlphanum(self.theA): - self._action(1) - else: - self._action(3) - elif self.theB == '\n': - if self.theA in ['}', ']', ')', '+', '-', '"', '\'']: - self._action(1) - else: - if isAlphanum(self.theA): - self._action(1) - else: - self._action(3) - else: - self._action(1) - - def minify(self, instream, outstream): - self.instream = instream - self.outstream = outstream - self.theA = '\n' - self.theB = None - self.theLookahead = None - - self._jsmin() - self.instream.close() - -if __name__ == '__main__': - import sys - jsm = JavascriptMinify() - jsm.minify(sys.stdin, sys.stdout)