--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/GreaseMonkey/GreaseMonkeyScript.py Sun Feb 21 19:54:14 2016 +0100 @@ -0,0 +1,305 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the GreaseMonkey script. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import QUrl, QRegExp + +from .GreaseMonkeyUrlMatcher import GreaseMonkeyUrlMatcher + + +class GreaseMonkeyScript(object): + """ + Class implementing the GreaseMonkey script. + """ + DocumentStart = 0 + DocumentEnd = 1 + + def __init__(self, manager, path): + """ + Constructor + + @param manager reference to the manager object (GreaseMonkeyManager) + @param path path of the Javascript file (string) + """ + self.__manager = manager + + self.__name = "" + self.__namespace = "GreaseMonkeyNS" + self.__description = "" + self.__version = "" + + self.__include = [] + self.__exclude = [] + + self.__downloadUrl = QUrl() + self.__startAt = GreaseMonkeyScript.DocumentEnd + + self.__script = "" + self.__fileName = path + self.__enabled = True + self.__valid = False + self.__metaData = "" + + self.__parseScript(path) +## , m_fileWatcher(new DelayedFileWatcher(this)) +## connect(m_fileWatcher, SIGNAL(delayedFileChanged(QString)), this, SLOT(watchedFileChanged(QString))); + + def isValid(self): + """ + Public method to check the validity of the script. + + @return flag indicating a valid script (boolean) + """ + return self.__valid + + def name(self): + """ + Public method to get the name of the script. + + @return name of the script (string) + """ + return self.__name + + def nameSpace(self): + """ + Public method to get the name space of the script. + + @return name space of the script (string) + """ + return self.__namespace + + def fullName(self): + """ + Public method to get the full name of the script. + + @return full name of the script (string) + """ + return "{0}/{1}".format(self.__namespace, self.__name) + + def description(self): + """ + Public method to get the description of the script. + + @return description of the script (string) + """ + return self.__description + + def version(self): + """ + Public method to get the version of the script. + + @return version of the script (string) + """ + return self.__version + + def downloadUrl(self): + """ + Public method to get the download URL of the script. + + @return download URL of the script (QUrl) + """ + return QUrl(self.__downloadUrl) + + def startAt(self): + """ + Public method to get the start point of the script. + + @return start point of the script (DocumentStart or DocumentEnd) + """ + return self.__startAt + + def isEnabled(self): + """ + Public method to check, if the script is enabled. + + @return flag indicating an enabled state (boolean) + """ + return self.__enabled + + def setEnabled(self, enable): + """ + Public method to enable a script. + + @param enable flag indicating the new enabled state (boolean) + """ + self.__enabled = enable + + def include(self): + """ + Public method to get the list of included URLs. + + @return list of included URLs (list of strings) + """ + list = [] + for matcher in self.__include: + list.append(matcher.pattern()) + return list + + def exclude(self): + """ + Public method to get the list of excluded URLs. + + @return list of excluded URLs (list of strings) + """ + list = [] + for matcher in self.__exclude: + list.append(matcher.pattern()) + return list + + def script(self): + """ + Public method to get the Javascript source. + + @return Javascript source (string) + """ + return self.__script + +##QString GM_Script::metaData() const +##{ +## return m_metadata; +##} + + def fileName(self): + """ + Public method to get the path of the Javascript file. + + @return path path of the Javascript file (string) + """ + return self.__fileName + + def match(self, urlString): + """ + Public method to check, if the script matches the given URL. + + @param urlString URL (string) + @return flag indicating a match (boolean) + """ + if not self.__enabled: + return False + + for matcher in self.__exclude: + if matcher.match(urlString): + return False + + for matcher in self.__include: + if matcher.match(urlString): + return True + + return False + + def __parseScript(self, path): + """ + Private method to parse the given script and populate the data + structure. + + @param path path of the Javascript file (string) + """ + try: + f = open(path, "r", encoding="utf-8") + fileData = f.read() + f.close() + except (IOError, OSError): + # silently ignore because it shouldn't happen + return + + rx = QRegExp("// ==UserScript==(.*)// ==/UserScript==") + rx.indexIn(fileData) + metaDataBlock = rx.cap(1).strip() + + if metaDataBlock == "": + # invalid script file + return + + requireList = [] + for line in metaDataBlock.splitlines(): + if not line.startswith("// @"): + continue + + line = line[3:].replace("\t", " ") + index = line.find(" ") + if index < 0: + continue + + key = line[:index].strip() + value = line[index + 1:].strip() + + # Ignored values: @resource, @unwrap + + if not key or not value: + continue + + if key == "@name": + self.__name = value + + elif key == "@namespace": + self.__namespace = value + + elif key == "@description": + self.__description = value + + elif key == "@version": + self.__version = value + + elif key == "@updateURL": + self.__downloadUrl = QUrl(value) + + elif key in ["@include", "@match"]: + self.__include.append(GreaseMonkeyUrlMatcher(value)) + + elif key in ["@exclude", "@exclude_match"]: + self.__exclude.append(GreaseMonkeyUrlMatcher(value)) + + elif key == "@require": + requireList.append(value) + + elif key == "@run-at": + if value == "document-end": + self.__startAt = GreaseMonkeyScript.DocumentEnd + elif value == "document-start": + self.__startAt = GreaseMonkeyScript.DocumentStart + + elif key == "@downloadURL" and self.__downloadUrl.isEmpty(): + self.__downloadUrl = QUrl(value) + + if not self.__include: + self.__include.append(GreaseMonkeyUrlMatcher("*")) + + marker = "// ==/UserScript==" + index = fileData.find(marker) + len(marker) + self.__metaData = fileData[:index] + script = fileData[index:].strip() + script = "{0}{1}".format( + self.__manager.requireScripts(requireList), + script) + self.__script = "(function(){{{0}}})();".format(script) + self.__valid = len(script) > 0 +## const QString nspace = QCryptographicHash::hash(fullName().toUtf8(), QCryptographicHash::Md4).toHex(); +## const QString gmValues = m_manager->valuesScript().arg(nspace); +## +## m_script = QSL("(function(){%1\n%2\n%3\n})();").arg(gmValues, m_manager->requireScripts(requireList), script); +## m_valid = true; + + def webScript(self): + """ + Public method to create a script object + + @return prepared script object + @rtype QWebEngineScript + """ +##QWebEngineScript GM_Script::webScript() const +##{ +## QWebEngineScript script; +## script.setName(fullName()); +## script.setInjectionPoint(startAt() == DocumentStart ? QWebEngineScript::DocumentCreation : QWebEngineScript::DocumentReady); +## script.setWorldId(QWebEngineScript::MainWorld); +## script.setRunsOnSubFrames(!m_noframes); +## script.setSourceCode(QSL("%1\n%2\n%3").arg(m_metadata, m_manager->bootstrapScript(), m_script)); +## return script; +##}