|
| 1 | +import sys |
| 2 | +import os |
| 3 | +from PyQt5 import QtCore |
| 4 | +from PyQt5 import uic |
| 5 | +from PyQt5 import QtWidgets, QtGui |
| 6 | +from PyQt5.QtCore import QCoreApplication |
| 7 | + |
| 8 | +#from urllib.request import Request, urlopen, urlretrieve |
| 9 | +#from bs4 import BeautifulSoup |
| 10 | +import json |
| 11 | +import traceback |
| 12 | +import markdown2 |
| 13 | +#import urllib.request |
| 14 | +# import requests |
| 15 | +import base64 |
| 16 | +try: |
| 17 | + from .data.lib import pyqt_customlib as pyqtlib |
| 18 | +except ImportError: |
| 19 | + from data.lib import pyqt_customlib as pyqtlib |
| 20 | + |
| 21 | +from github import Github |
| 22 | + |
| 23 | +translate = QCoreApplication.translate |
| 24 | + |
| 25 | +class PluginDownloader(QtWidgets.QWidget): |
| 26 | + def __init__(self, userpath, repo='Haschtl/RTOC-Plugins'): |
| 27 | + super(PluginDownloader, self).__init__() |
| 28 | + self.repo = None |
| 29 | + self.repoName = None |
| 30 | + self.onlinePlugins = [] |
| 31 | + self.localPlugins = {} |
| 32 | + self.localPluginInfos = {} |
| 33 | + self.pluginInfos ={} |
| 34 | + self.userpath = userpath |
| 35 | + |
| 36 | + self.currentname = '' |
| 37 | + self.installed = False |
| 38 | + self.uptodate = False |
| 39 | + |
| 40 | + if getattr(sys, 'frozen', False): |
| 41 | + # frozen |
| 42 | + packagedir = os.path.dirname(sys.executable) |
| 43 | + else: |
| 44 | + # unfrozen |
| 45 | + packagedir = os.path.dirname(os.path.realpath(__file__)) |
| 46 | + uic.loadUi(packagedir+"/data/ui/getPlugins.ui", self) |
| 47 | + |
| 48 | + self.pluginList.currentTextChanged.connect(self.loadPlugin) |
| 49 | + self.installButton.clicked.connect(self.installPlugin) |
| 50 | + self.removeButton.clicked.connect(self.removePlugin) |
| 51 | + self.loadRepo(repo) |
| 52 | + self.loadLocalPlugins(userpath) |
| 53 | + print(self.localPlugins) |
| 54 | + |
| 55 | + def loadLocalPlugins(self, userpath): |
| 56 | + self.localPlugins = {} |
| 57 | + self.localPluginInfos = {} |
| 58 | + sys.path.insert(0, userpath) |
| 59 | + import devices |
| 60 | + |
| 61 | + subfolders = [f.name for f in os.scandir(list(devices.__path__)[0]) if f.is_dir()] |
| 62 | + for folder in subfolders: |
| 63 | + if folder not in ['', '__pycache__', '.git']: |
| 64 | + a =__import__(devices.__name__+"."+ folder) |
| 65 | + #for finder, name, ispkg in loggerlib.iter_namespace(devices): |
| 66 | + #fullpath = pkgutil.extend_path(list(devices.__path__)[0], folder) |
| 67 | + #print(fullpath) |
| 68 | + #for finder, name, ispkg in pkgutil.iter_modules(fullpath,devices.__name__+'.'+folder+ "."): |
| 69 | + #for root, dirs, files in os.walklevel(list(devices.__path__)[0], level=1): |
| 70 | + for files in os.listdir(list(devices.__path__)[0]+"/"+folder): |
| 71 | + if files.endswith('.py'): |
| 72 | + name = devices.__name__+'.'+folder+"."+files.replace('.py','') |
| 73 | + namesplit = name.split('.') |
| 74 | + print(name) |
| 75 | + if namesplit[-1] not in ["LoggerPlugin"]: |
| 76 | + self.localPlugins[namesplit[-1]] = list(devices.__path__)[0]+'/'+folder |
| 77 | + for plug in self.localPlugins.keys(): |
| 78 | + #localPluginInfos |
| 79 | + if os.path.exists(self.localPlugins[plug]+"/info.json"): |
| 80 | + with open(self.localPlugins[plug]+"/info.json") as f: |
| 81 | + data = json.load(f) |
| 82 | + self.localPluginInfos[plug] = data |
| 83 | + else: |
| 84 | + print('Plugin '+plug+' was not installed from any repository') |
| 85 | + self.localPluginInfos[plug] = False |
| 86 | + |
| 87 | + def loadRepo(self, repo): |
| 88 | + self.repoName = repo |
| 89 | + self.github = Github('RTOC-Downloader','thisissupersave123') |
| 90 | + self.repo = self.github.get_repo(self.repoName) |
| 91 | + dirs = self.repo.get_contents('') |
| 92 | + for dir in dirs: |
| 93 | + try: |
| 94 | + realdir = dir.path |
| 95 | + if realdir.find('.')==-1 and realdir != '__pycache__': |
| 96 | + info = self.repo.get_contents(realdir+"/info.json") |
| 97 | + data = json.loads(info.decoded_content.decode('utf-8')) |
| 98 | + #print(data) |
| 99 | + self.pluginInfos[realdir]=data |
| 100 | + self.onlinePlugins.append(realdir) |
| 101 | + except: |
| 102 | + print(info.decoded_content.decode('utf-8')) |
| 103 | + tb = traceback.format_exc() |
| 104 | + #print(tb) |
| 105 | + print('Error in '+dir.path) |
| 106 | + |
| 107 | + for p in self.onlinePlugins: |
| 108 | + self.pluginList.addItem(p) |
| 109 | + |
| 110 | + def loadPlugin(self, strung): |
| 111 | + self.currentname = strung |
| 112 | + self.installed = False |
| 113 | + self.uptodate = False |
| 114 | + try: |
| 115 | + info = self.pluginInfos[strung] |
| 116 | + print(strung) |
| 117 | + strung = "#"+strung+"\n\n" |
| 118 | + strung += "### Version: "+info['version'] |
| 119 | + if self.currentname in self.localPluginInfos.keys(): |
| 120 | + self.installed = True |
| 121 | + if self.localPluginInfos[self.currentname] != False: |
| 122 | + strung += ' (Installed: '+ self.localPluginInfos[self.currentname]['version']+')' |
| 123 | + else: |
| 124 | + strung += ' (was not installed from repo)' |
| 125 | + if info['version'] == self.localPluginInfos[self.currentname]['version']: |
| 126 | + self.uptodate = True |
| 127 | + strung += "\n\n" |
| 128 | + strung += "*OS:* "+info['OS']+"\n\n" |
| 129 | + strung += "*GUI:* "+str(info['GUI'])+"\n\n" |
| 130 | + strung += "###Info:\n"+info['Info'].replace('\n','\n\n') |
| 131 | + except: |
| 132 | + strung = "# Error loading description from repo\n\n" |
| 133 | + tb = traceback.format_exc() |
| 134 | + strung += tb |
| 135 | + |
| 136 | + self.pluginInfo.setText(markdown2.markdown(strung)) |
| 137 | + |
| 138 | + if self.installed and self.uptodate: |
| 139 | + self.installButton.hide() |
| 140 | + self.removeButton.show() |
| 141 | + if self.installed and not self.uptodate: |
| 142 | + self.installButton.show() |
| 143 | + self.removeButton.show() |
| 144 | + if not self.installed: |
| 145 | + self.installButton.show() |
| 146 | + self.removeButton.hide() |
| 147 | + |
| 148 | + def installPlugin(self): |
| 149 | + strung = translate('Downloader',"Aktuelle Version: ")+self.pluginInfos[self.currentname]['version'] |
| 150 | + if self.currentname in self.localPluginInfos.keys(): |
| 151 | + self.installed = True |
| 152 | + if self.localPluginInfos[self.currentname] != False: |
| 153 | + strung += translate('Downloader',' (Installiert: ')+ self.localPluginInfos[self.currentname]['version']+')' |
| 154 | + else: |
| 155 | + strung += translate('Downloader',' (Wurde nicht mit der RTOC-Repository installiert)') |
| 156 | + ok = pyqtlib.alert_message("Install plugin", "Möchtest du wirklich "+self.currentname+ " installieren", strung) |
| 157 | + if ok: |
| 158 | + print('install') |
| 159 | + url = 'https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/'+self.repoName+'/tree/master/'+self.currentname |
| 160 | + print(url) |
| 161 | + #urllib.request.urlretrieve(url, self.userpath+'/temp.zip') |
| 162 | + |
| 163 | + # f = open(self.userpath+'/temp.zip','wb') |
| 164 | + # f.write(urllib.request.urlopen(url).read()) |
| 165 | + # f.close() |
| 166 | + |
| 167 | + # r = requests.get(url) |
| 168 | + # |
| 169 | + # with open(self.userpath+'/temp.zip', "wb") as code: |
| 170 | + # code.write(r.content) |
| 171 | + self.download_directory(self.currentname) |
| 172 | + print('Download finished') |
| 173 | + pyqtlib.info_message(translate('Downloader',"Fertig"), translate('Downloader',"Installation abgeschlossen"), translate('Downloader',"Bitte starte RTOC neu, um neue Plugins zu benutzen.")) |
| 174 | + |
| 175 | + if self.localPluginInfos[self.currentname] != False: |
| 176 | + if self.localPluginInfos[self.currentname]['dependencies'] != []: |
| 177 | + info = '\n'.join(self.localPluginInfos[self.currentname]['dependencies']) |
| 178 | + pyqtlib.info_message(translate('Abhängigkeiten'), "Dieses plugin benötigt einige Abhängigkeiten, die mittels 'pip3 install PACKAGE' installiert werden müssen.", info) |
| 179 | + |
| 180 | + def removePlugin(self): |
| 181 | + ok = pyqtlib.alert_message(translate('Downloader',"Plugin entfernen"), translate('Downloader',"Möchtest du wirklich ")+self.currentname+ translate('Downloader'," entfernen"), "") |
| 182 | + if ok: |
| 183 | + print('remove') |
| 184 | + if os.path.exists(self.userpath+"/devices/"+self.currentname): |
| 185 | + import shutil |
| 186 | + shutil.rmtree(self.userpath+"/devices/"+self.currentname) |
| 187 | + #os.removedirs(self.userpath+"/devices/"+self.currentname) |
| 188 | + self.loadLocalPlugins(self.userpath) |
| 189 | + self.loadPlugin(self.currentname) |
| 190 | + |
| 191 | + def download_directory(self, server_path): |
| 192 | + "Download all contents at server_path with commit tag sha in the repository." |
| 193 | + contents = self.repo.get_dir_contents(server_path) |
| 194 | + if not os.path.exists(self.userpath+"/devices/"+self.currentname): |
| 195 | + os.mkdir(self.userpath+"/devices/"+self.currentname) |
| 196 | + for content in contents: |
| 197 | + print("Processing "+ content.path) |
| 198 | + if content.type == 'dir' and '__pycache__' not in content.path: |
| 199 | + if not os.path.exists(self.userpath+"/devices/"+content.path): |
| 200 | + os.mkdir(self.userpath+"/devices/"+content.path) |
| 201 | + self.download_directory(content.path) |
| 202 | + elif '__pycache__' not in content.path: |
| 203 | + try: |
| 204 | + path = content.path |
| 205 | + file_content = self.repo.get_contents(path) |
| 206 | + file_data = base64.b64decode(file_content.content) |
| 207 | + file_out = open(self.userpath+"/devices/"+content.path, "w") |
| 208 | + file_out.write(file_data.decode('utf-8')) |
| 209 | + file_out.close() |
| 210 | + except IOError as exc: |
| 211 | + print('Error processing %s: %s', content.path, exc) |
| 212 | + |
| 213 | + self.loadLocalPlugins(self.userpath) |
| 214 | + self.loadPlugin(self.currentname) |
| 215 | + # def read_url(self, url): |
| 216 | + # url = url.replace(" ","%20") |
| 217 | + # req = Request(url) |
| 218 | + # a = urlopen(req).read() |
| 219 | + # soup = BeautifulSoup(a, 'html.parser') |
| 220 | + # x = (soup.find_all('a')) |
| 221 | + # for i in x: |
| 222 | + # file_name = i.extract().get_text() |
| 223 | + # url_new = url + file_name |
| 224 | + # url_new = url_new.replace(" ","%20") |
| 225 | + # if len(file_name)>1: |
| 226 | + # if(file_name[-1]=='/' and file_name[0]!='.'): |
| 227 | + # self.read_url(url_new+"/") |
| 228 | + # print(url_new) |
| 229 | + |
| 230 | +if __name__ == "__main__": |
| 231 | + import sys |
| 232 | + userpath = os.path.expanduser('~/.RTOC') |
| 233 | + if not os.path.exists(userpath): |
| 234 | + os.mkdir(userpath) |
| 235 | + if not os.path.exists(userpath+'/devices'): |
| 236 | + os.mkdir(userpath+'/devices') |
| 237 | + app = QtWidgets.QApplication(sys.argv) |
| 238 | + app.setApplicationName('MyWindow') |
| 239 | + main = PluginDownloader(userpath) |
| 240 | + main.setWindowTitle("Plugin Downloader") |
| 241 | + main.show() |
| 242 | + |
| 243 | + sys.exit(app.exec_()) |
0 commit comments