|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2012 - 2019 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the downloader for GreaseMonkey scripts. |
|
8 """ |
|
9 |
|
10 from __future__ import unicode_literals |
|
11 |
|
12 import os |
|
13 |
|
14 from PyQt5.QtCore import pyqtSignal, QObject, QSettings, QRegExp, QUrl |
|
15 from PyQt5.QtWidgets import QDialog |
|
16 from PyQt5.QtNetwork import QNetworkReply |
|
17 |
|
18 from E5Gui import E5MessageBox |
|
19 |
|
20 import Helpviewer.HelpWindow |
|
21 from Helpviewer.Network.FollowRedirectReply import FollowRedirectReply |
|
22 |
|
23 |
|
24 class GreaseMonkeyDownloader(QObject): |
|
25 """ |
|
26 Class implementing the downloader for GreaseMonkey scripts. |
|
27 |
|
28 @signal finished() emitted to indicate the end of a script download |
|
29 """ |
|
30 finished = pyqtSignal() |
|
31 |
|
32 def __init__(self, request, manager): |
|
33 """ |
|
34 Constructor |
|
35 |
|
36 @param request reference to the request object (QNetworkRequest) |
|
37 @param manager reference to the GreaseMonkey manager |
|
38 (GreaseMonkeyManager) |
|
39 """ |
|
40 super(GreaseMonkeyDownloader, self).__init__() |
|
41 |
|
42 self.__manager = manager |
|
43 |
|
44 self.__reply = FollowRedirectReply( |
|
45 request.url(), |
|
46 Helpviewer.HelpWindow.HelpWindow.networkAccessManager()) |
|
47 self.__reply.finished.connect(self.__scriptDownloaded) |
|
48 |
|
49 self.__fileName = "" |
|
50 self.__requireUrls = [] |
|
51 |
|
52 def __scriptDownloaded(self): |
|
53 """ |
|
54 Private slot to handle the finished download of a script. |
|
55 """ |
|
56 response = bytes(self.__reply.readAll()).decode() |
|
57 |
|
58 if self.__reply.error() == QNetworkReply.NoError and \ |
|
59 "// ==UserScript==" in response: |
|
60 from Helpviewer import HelpUtilities |
|
61 filePath = os.path.join( |
|
62 self.__manager.scriptsDirectory(), |
|
63 HelpUtilities.getFileNameFromUrl(self.__reply.url())) |
|
64 self.__fileName = HelpUtilities.ensureUniqueFilename(filePath) |
|
65 |
|
66 try: |
|
67 f = open(self.__fileName, "w", encoding="utf-8") |
|
68 except (IOError, OSError) as err: |
|
69 E5MessageBox.critical( |
|
70 None, |
|
71 self.tr("GreaseMonkey Download"), |
|
72 self.tr( |
|
73 """<p>The file <b>{0}</b> could not be opened""" |
|
74 """ for writing.<br/>Reason: {1}</p>""").format( |
|
75 self.__fileName, str(err))) |
|
76 self.finished.emit() |
|
77 return |
|
78 f.write(response) |
|
79 f.close() |
|
80 |
|
81 settings = QSettings( |
|
82 os.path.join(self.__manager.requireScriptsDirectory(), |
|
83 "requires.ini"), |
|
84 QSettings.IniFormat) |
|
85 settings.beginGroup("Files") |
|
86 |
|
87 rx = QRegExp("@require(.*)\\n") |
|
88 rx.setMinimal(True) |
|
89 rx.indexIn(response) |
|
90 |
|
91 for i in range(1, rx.captureCount() + 1): |
|
92 url = rx.cap(i).strip() |
|
93 if url and not settings.contains(url): |
|
94 self.__requireUrls.append(QUrl(url)) |
|
95 |
|
96 self.__reply.deleteLater() |
|
97 self.__reply = None |
|
98 |
|
99 self.__downloadRequires() |
|
100 |
|
101 def __requireDownloaded(self): |
|
102 """ |
|
103 Private slot to handle the finished download of a required script. |
|
104 """ |
|
105 response = bytes(self.__reply.readAll()).decode() |
|
106 |
|
107 if self.__reply.error() == QNetworkReply.NoError and response: |
|
108 from Helpviewer import HelpUtilities |
|
109 filePath = os.path.join(self.__manager.requireScriptsDirectory(), |
|
110 "require.js") |
|
111 fileName = HelpUtilities.ensureUniqueFilename(filePath, "{0}") |
|
112 |
|
113 try: |
|
114 f = open(fileName, "w", encoding="utf-8") |
|
115 except (IOError, OSError) as err: |
|
116 E5MessageBox.critical( |
|
117 None, |
|
118 self.tr("GreaseMonkey Download"), |
|
119 self.tr( |
|
120 """<p>The file <b>{0}</b> could not be opened""" |
|
121 """ for writing.<br/>Reason: {1}</p>""").format( |
|
122 fileName, str(err))) |
|
123 self.finished.emit() |
|
124 return |
|
125 f.write(response) |
|
126 f.close() |
|
127 |
|
128 settings = QSettings( |
|
129 os.path.join(self.__manager.requireScriptsDirectory(), |
|
130 "requires.ini"), |
|
131 QSettings.IniFormat) |
|
132 settings.beginGroup("Files") |
|
133 settings.setValue(self.__reply.originalUrl().toString(), fileName) |
|
134 |
|
135 self.__reply.deleteLater() |
|
136 self.__reply = None |
|
137 |
|
138 self.__downloadRequires() |
|
139 |
|
140 def __downloadRequires(self): |
|
141 """ |
|
142 Private slot to initiate the download of required scripts. |
|
143 """ |
|
144 if self.__requireUrls: |
|
145 self.__reply = FollowRedirectReply( |
|
146 self.__requireUrls.pop(0), |
|
147 Helpviewer.HelpWindow.HelpWindow.networkAccessManager()) |
|
148 self.__reply.finished.connect(self.__requireDownloaded) |
|
149 else: |
|
150 from .GreaseMonkeyScript import GreaseMonkeyScript |
|
151 deleteScript = True |
|
152 script = GreaseMonkeyScript(self.__manager, self.__fileName) |
|
153 |
|
154 if script.isValid(): |
|
155 if not self.__manager.containsScript(script.fullName()): |
|
156 from .GreaseMonkeyAddScriptDialog import \ |
|
157 GreaseMonkeyAddScriptDialog |
|
158 dlg = GreaseMonkeyAddScriptDialog(self.__manager, script) |
|
159 deleteScript = dlg.exec_() != QDialog.Accepted |
|
160 else: |
|
161 E5MessageBox.information( |
|
162 None, |
|
163 self.tr("GreaseMonkey Download"), |
|
164 self.tr( |
|
165 """<p><b>{0}</b> is already installed.</p>""") |
|
166 .format(script.name())) |
|
167 |
|
168 if deleteScript: |
|
169 try: |
|
170 os.remove(self.__fileName) |
|
171 except (IOError, OSError): |
|
172 # ignore |
|
173 pass |
|
174 |
|
175 self.finished.emit() |