├── README.md ├── TODO.md ├── gitrepo.py ├── gitrepo.pyui └── gitrepo.uipack.py /README.md: -------------------------------------------------------------------------------- 1 | gitrepo 2 | ======= 3 | 4 | Small Pythonista utility to easily download repos and releases from GitHub
5 | Use [gitrepo.uipack.py](https://github.com/Vik2015/gitrepo/blob/master/gitrepo.uipack.py) to get both .py and .pyui files at once. 6 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | TODO 2 | ==== 3 | 4 | + Add a search bar to the `Choose a repo/release/gist view` 5 | + Add a possibility to choose download folder 6 | 7 | * Fix laggy scrolling 8 | -------------------------------------------------------------------------------- /gitrepo.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | import clipboard, console, requests, ui, urlparse, zipfile, re, os, string 4 | try: 5 | from cStringIO import StringIO 6 | except ImportError: 7 | from StringIO import StringIO 8 | 9 | class Delegate (object): 10 | def __init__(self): 11 | self.selected_item = None 12 | 13 | def tableview_did_select(self, tableview, section, row): 14 | self.selected_item = tableview.data_source.items[row] 15 | tableview.superview.close() 16 | 17 | repolink = "https://github.com/{}/{}/archive/{}.zip" 18 | gistslink = "https://api.github.com/users/{}/gists" 19 | browselink = "https://api.github.com/users/{}/repos" 20 | releaselink = "https://api.github.com/repos/{}/{}/releases" 21 | parselink = re.compile(r'<[\S]*?page=(\d+)>; rel="last"').search 22 | 23 | def error_alert(msg="General error"): 24 | console.alert("Error", msg, "OK", hide_cancel_button=True) 25 | 26 | def get_page_num(link_header): 27 | return int(parselink(link_header).group(1)) 28 | 29 | @ui.in_background 30 | def save_zip(data, name, unzip): 31 | if unzip: 32 | io = StringIO(data) 33 | with zipfile.ZipFile(io) as zp: 34 | zp.extractall() 35 | else: 36 | with open(name + ".zip", "wb") as zp: 37 | zp.write(data) 38 | 39 | @ui.in_background 40 | def download_repo(username, repo, branch, unzip): 41 | url = repolink.format(username, repo, branch) 42 | data = requests.get(url) 43 | if isinstance(data, dict) and data["message"] == "Not Found": 44 | return error_alert("User '{}' not found".format(username)) 45 | elif not data: 46 | return error_alert("Repo '{}' not found".format(repo)) 47 | try: 48 | save_zip(data.content, repo, unzip) 49 | except Exception as err: 50 | return error_alert("Error downloading repo: {}".format(err)) 51 | console.hud_alert("Done!") 52 | 53 | @ui.in_background 54 | def download_release(username, repo, unzip): 55 | url = releaselink.format(username, repo) 56 | data = requests.get(url).json() 57 | if not data: 58 | return error_alert("Repo '{}' has no releases".format(repo)) 59 | elif "message" in data and data["message"] == "Not Found": 60 | return error_alert("Repo '{}' not found".format(repo)) 61 | vers = sorted([i["tag_name"] for i in data]) 62 | rview = data_view("release", vers) 63 | rview.present("sheet") 64 | rview.wait_modal() 65 | tapped_text = rview["rtable"].delegate.selected_item 66 | if tapped_text: 67 | for d in data: 68 | if d["tag_name"] == tapped_text: 69 | zipurl = d["zipball_url"] 70 | save_zip(requests.get(zipurl).content, tapped_text, unzip) 71 | return console.hud_alert("Done!") 72 | 73 | @ui.in_background 74 | def download_gist(username, gist): 75 | url = gistslink.format(username, gist) 76 | req = requests.get(url) 77 | data = req.json() 78 | req.close() 79 | 80 | info = [i for i in data if i["id"] == gist] 81 | if not info: 82 | return error_alert("Gist '{}' not found".format(gist)) 83 | info = info[0] 84 | files = info["files"] 85 | try: 86 | os.mkdir(gist) 87 | except: 88 | pass 89 | for fpinfo in files.values(): 90 | data = requests.get(fpinfo["raw_url"]).content 91 | with open(os.path.join(gist, 92 | fpinfo["filename"]), "wb") as fp: 93 | fp.write(data) 94 | return console.hud_alert("Done!") 95 | 96 | @ui.in_background 97 | def gitdownload(button): 98 | index = view["sgcontrol"].selected_index 99 | username = view["username"].text = view["username"].text.strip() 100 | reponame = view["reponame"].text = view["reponame"].text.strip() 101 | if '/' in reponame: 102 | reponame, branch = string.split(reponame, '/', maxsplit=1) 103 | if not branch: branch = 'master' 104 | else: 105 | branch = 'master' 106 | unzip = view["dounzip"].value 107 | if not username: 108 | return error_alert("Please enter username") 109 | if not reponame: 110 | return error_alert("Please enter repo name") 111 | console.show_activity() 112 | if index == 0: 113 | download_repo(username, reponame, branch, unzip) 114 | elif index == 1: 115 | download_release(username, reponame, unzip) 116 | elif index == 2: 117 | download_gist(username, reponame) 118 | console.hide_activity() 119 | 120 | @ui.in_background 121 | def gitbrowse(sender): 122 | username = view["username"].text = view["username"].text.strip() 123 | if not username: 124 | return error_alert("Please enter username") 125 | index = view["sgcontrol"].selected_index 126 | if index == 2: 127 | url = gistslink.format(username) 128 | else: 129 | url = browselink.format(username) 130 | try: 131 | req = requests.get(url) 132 | data = req.json() # normally returns a list of dicts 133 | except requests.HTTPError as err: 134 | return error_alert("User '{}' not found".format(username)) 135 | except Exception as err: 136 | return error_alert("Error downloading metadata: {}".format(err)) 137 | if isinstance(data, dict) and data["message"] == "Not Found": 138 | return error_alert("User '{}' not found".format(username)) 139 | finaldata = data 140 | if "link" in req.headers: 141 | pages = get_page_num(req.headers["link"]) 142 | for lnk in range(2, pages + 1): 143 | link = browselink.format(username) + "?page=%d" % lnk 144 | req = requests.get(link) 145 | finaldata += req.json() 146 | 147 | if index == 2: 148 | nameid_dict = {} 149 | for fpinfo in finaldata: 150 | nameid_dict[", ".join(fpinfo["files"].keys())] = fpinfo["id"] 151 | names = nameid_dict.keys() 152 | else: 153 | names = sorted([i["name"] for i in finaldata]) 154 | 155 | name = {0: "repos", 1: "repos", 2: "gists"}[index] 156 | if not names: 157 | return error_alert("User '{}' has no {}".format(username, name)) 158 | rview = data_view(name[:-1], names) 159 | rview.present("sheet") 160 | rview.wait_modal() 161 | tapped_text = rview["rtable"].delegate.selected_item 162 | if tapped_text: 163 | if index == 2: 164 | view["reponame"].text = nameid_dict[tapped_text] 165 | else: 166 | view["reponame"].text = tapped_text 167 | 168 | def data_view(name, data): 169 | rview = ui.View(name="Choose a " + name) 170 | table = ui.TableView() 171 | table.name = "rtable" 172 | table.flex = "WH" 173 | table.data_source = ui.ListDataSource(data) 174 | table.data_source.delete_enabled = False 175 | table.delegate = Delegate() 176 | rview.add_subview(table) 177 | return rview 178 | 179 | def segchange(sender): 180 | index = sender.selected_index 181 | if index == 2: # Gist 182 | view["repolabel"].text = "Gist ID:" 183 | view["bbutton"].title = "Browse gists" 184 | else: 185 | view["repolabel"].text = "Repo:" 186 | view["bbutton"].title = "Browse repos" 187 | 188 | view = ui.load_view('gitrepo') 189 | for name in 'username reponame'.split(): 190 | view[name].autocapitalization_type = ui.AUTOCAPITALIZE_NONE 191 | parse = urlparse.urlparse(clipboard.get().strip()) 192 | if parse.netloc in "www.github.com github.com".split(): 193 | path = [i for i in parse.path.split("/") if i] 194 | if len(path) >= 2: 195 | view["username"].text, view["reponame"].text = path[:2] 196 | if len(path) >= 4: 197 | view["reponame"].text += '/' + path[3] 198 | 199 | view["sgcontrol"].action = segchange 200 | view.present('popover') 201 | -------------------------------------------------------------------------------- /gitrepo.pyui: -------------------------------------------------------------------------------- 1 | [{"class":"View","attributes":{"name":"gitrepo","background_color":"RGBA(1.000000,1.000000,1.000000,1.000000)","tint_color":"RGBA(0.000000,0.478000,1.000000,1.000000)","enabled":true,"border_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","flex":""},"frame":"{{0, 0}, {341, 250}}","nodes":[{"class":"SegmentedControl","attributes":{"name":"sgcontrol","border_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","uuid":"308A3491-ABAA-43BC-8D2C-1319469FF3C9","enabled":true,"segments":"Repo|Release|Gist","flex":"LR"},"frame":"{{16, 6}, {196.5, 29}}","nodes":[]},{"class":"Label","attributes":{"font_size":20,"enabled":true,"text":"Username:","flex":"","name":"label1","border_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","text_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","alignment":"left","uuid":"7C45FE1B-8084-4257-A1D1-DE573BC8299A"},"frame":"{{16.5, 57.5}, {96, 35.5}}","nodes":[]},{"class":"TextField","attributes":{"uuid":"18AD549C-48DF-40CF-B008-5E2C283AD3EA","alignment":"left","autocorrection_type":"no","font_size":17,"font_name":"Avenir-Book","enabled":true,"flex":"","border_color":"RGBA(0.571429,0.571429,0.571429,1.000000)","text_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","corner_radius":2,"secure":false,"border_width":1,"border_style":3,"name":"username","spellchecking_type":"no"},"frame":"{{120.5, 57.5}, {200, 36}}","nodes":[]},{"class":"Label","attributes":{"font_size":20,"enabled":true,"text":"Repo:","flex":"","name":"repolabel","border_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","text_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","alignment":"left","uuid":"97359D8F-3BD5-4D8F-8711-14B4565F9601"},"frame":"{{16.5, 102}, {96, 35}}","nodes":[]},{"class":"TextField","attributes":{"name":"reponame","alignment":"left","autocorrection_type":"no","font_size":17,"font_name":"Avenir-Book","enabled":true,"flex":"","border_color":"RGBA(0.571429,0.571429,0.571429,1.000000)","text_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","corner_radius":2,"secure":false,"uuid":"7BFD908D-CA67-4976-94DD-5CF0DB5EC360","border_style":3,"border_width":1,"spellchecking_type":"no"},"frame":"{{120, 101.5}, {200, 36}}","nodes":[]},{"class":"Button","attributes":{"font_size":16,"enabled":true,"flex":"","font_bold":false,"name":"dbutton","corner_radius":9,"border_color":"RGBA(0.244898,0.520408,0.857143,1.000000)","border_width":1,"action":"gitdownload","uuid":"7C58793E-E2CA-4724-B2FC-3E779FD71890","title":"Download"},"frame":"{{16.5, 201}, {96, 31}}","nodes":[]},{"class":"Label","attributes":{"font_size":20,"enabled":true,"text":"Unzip archive:","flex":"","name":"label3","border_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","text_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","alignment":"left","uuid":"3A801AA2-D086-48E9-9262-E9880135E8EA"},"frame":"{{16.5, 145}, {137, 35}}","nodes":[]},{"class":"Switch","attributes":{"enabled":true,"flex":"","name":"dounzip","value":true,"alpha":1,"border_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","uuid":"40756EA8-214B-4247-9A47-F7D519C0BE88"},"frame":"{{161.5, 147}, {51, 31}}","nodes":[]},{"class":"Button","attributes":{"font_size":16,"enabled":true,"flex":"","font_bold":false,"name":"bbutton","corner_radius":9,"border_color":"RGBA(0.244898,0.520408,0.857143,1.000000)","border_width":1,"action":"gitbrowse","uuid":"127F82F8-97A9-4835-AD60-DF5FCDC942E3","title":"Browse repos"},"frame":"{{139, 201}, {119.5, 31}}","nodes":[]}]}] 2 | -------------------------------------------------------------------------------- /gitrepo.uipack.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ############################################################################### 3 | # This is a self-extracting UI application package for gitrepo. 4 | # Run this script once to extract the packaged application. 5 | # The files will be extracted to gitrepo.py and gitrepo.pyui. 6 | # Make sure that these files do not exist yet. 7 | # To update from an older version, move or delete the old files first. 8 | # After extracting, the application can be found at gitrepo.py. 9 | # This bundle can be deleted after extraction. 10 | ############################################################################### 11 | # Packaged using PackUI by dgelessus 12 | # https://github.com/dgelessus/pythonista-scripts/blob/master/UI/PackUI.py 13 | ############################################################################### 14 | 15 | import console, os.path 16 | 17 | NAME = "gitrepo" 18 | PYFILE = """# coding: utf-8 19 | 20 | import clipboard, console, requests, ui, urlparse, zipfile, re, os, string 21 | try: 22 | from cStringIO import StringIO 23 | except ImportError: 24 | from StringIO import StringIO 25 | 26 | class Delegate (object): 27 | def __init__(self): 28 | self.selected_item = None 29 | 30 | def tableview_did_select(self, tableview, section, row): 31 | self.selected_item = tableview.data_source.items[row] 32 | tableview.superview.close() 33 | 34 | repolink = "https://github.com/{}/{}/archive/{}.zip" 35 | gistslink = "https://api.github.com/users/{}/gists" 36 | browselink = "https://api.github.com/users/{}/repos" 37 | releaselink = "https://api.github.com/repos/{}/{}/releases" 38 | parselink = re.compile(r'<[\\S]*?page=(\\d+)>; rel="last"').search 39 | 40 | def error_alert(msg="General error"): 41 | console.alert("Error", msg, "OK", hide_cancel_button=True) 42 | 43 | def get_page_num(link_header): 44 | return int(parselink(link_header).group(1)) 45 | 46 | @ui.in_background 47 | def save_zip(data, name, unzip): 48 | if unzip: 49 | io = StringIO(data) 50 | with zipfile.ZipFile(io) as zp: 51 | zp.extractall() 52 | else: 53 | with open(name + ".zip", "wb") as zp: 54 | zp.write(data) 55 | 56 | @ui.in_background 57 | def download_repo(username, repo, branch, unzip): 58 | url = repolink.format(username, repo, branch) 59 | data = requests.get(url) 60 | if isinstance(data, dict) and data["message"] == "Not Found": 61 | return error_alert("User '{}' not found".format(username)) 62 | elif not data: 63 | return error_alert("Repo '{}' not found".format(repo)) 64 | try: 65 | save_zip(data.content, repo, unzip) 66 | except Exception as err: 67 | return error_alert("Error downloading repo: {}".format(err)) 68 | console.hud_alert("Done!") 69 | 70 | @ui.in_background 71 | def download_release(username, repo, unzip): 72 | url = releaselink.format(username, repo) 73 | data = requests.get(url).json() 74 | if not data: 75 | return error_alert("Repo '{}' has no releases".format(repo)) 76 | elif "message" in data and data["message"] == "Not Found": 77 | return error_alert("Repo '{}' not found".format(repo)) 78 | vers = sorted([i["tag_name"] for i in data]) 79 | rview = data_view("release", vers) 80 | rview.present("sheet") 81 | rview.wait_modal() 82 | tapped_text = rview["rtable"].delegate.selected_item 83 | if tapped_text: 84 | for d in data: 85 | if d["tag_name"] == tapped_text: 86 | zipurl = d["zipball_url"] 87 | save_zip(requests.get(zipurl).content, tapped_text, unzip) 88 | return console.hud_alert("Done!") 89 | 90 | @ui.in_background 91 | def download_gist(username, gist): 92 | url = gistslink.format(username, gist) 93 | req = requests.get(url) 94 | data = req.json() 95 | req.close() 96 | 97 | info = [i for i in data if i["id"] == gist] 98 | if not info: 99 | return error_alert("Gist '{}' not found".format(gist)) 100 | info = info[0] 101 | files = info["files"] 102 | try: 103 | os.mkdir(gist) 104 | except: 105 | pass 106 | for fpinfo in files.values(): 107 | data = requests.get(fpinfo["raw_url"]).content 108 | with open(os.path.join(gist, 109 | fpinfo["filename"]), "wb") as fp: 110 | fp.write(data) 111 | return console.hud_alert("Done!") 112 | 113 | @ui.in_background 114 | def gitdownload(button): 115 | index = view["sgcontrol"].selected_index 116 | username = view["username"].text = view["username"].text.strip() 117 | reponame = view["reponame"].text = view["reponame"].text.strip() 118 | if '/' in reponame: 119 | reponame, branch = string.split(reponame, '/', maxsplit=1) 120 | if not branch: branch = 'master' 121 | else: 122 | branch = 'master' 123 | unzip = view["dounzip"].value 124 | if not username: 125 | return error_alert("Please enter username") 126 | if not reponame: 127 | return error_alert("Please enter repo name") 128 | console.show_activity() 129 | if index == 0: 130 | download_repo(username, reponame, branch, unzip) 131 | elif index == 1: 132 | download_release(username, reponame, unzip) 133 | elif index == 2: 134 | download_gist(username, reponame) 135 | console.hide_activity() 136 | 137 | @ui.in_background 138 | def gitbrowse(sender): 139 | username = view["username"].text = view["username"].text.strip() 140 | if not username: 141 | return error_alert("Please enter username") 142 | index = view["sgcontrol"].selected_index 143 | if index == 2: 144 | url = gistslink.format(username) 145 | else: 146 | url = browselink.format(username) 147 | try: 148 | req = requests.get(url) 149 | data = req.json() # normally returns a list of dicts 150 | except requests.HTTPError as err: 151 | return error_alert("User '{}' not found".format(username)) 152 | except Exception as err: 153 | return error_alert("Error downloading metadata: {}".format(err)) 154 | if isinstance(data, dict) and data["message"] == "Not Found": 155 | return error_alert("User '{}' not found".format(username)) 156 | finaldata = data 157 | if "link" in req.headers: 158 | pages = get_page_num(req.headers["link"]) 159 | for lnk in range(2, pages + 1): 160 | link = browselink.format(username) + "?page=%d" % lnk 161 | req = requests.get(link) 162 | finaldata += req.json() 163 | 164 | if index == 2: 165 | nameid_dict = {} 166 | for fpinfo in finaldata: 167 | nameid_dict[", ".join(fpinfo["files"].keys())] = fpinfo["id"] 168 | names = nameid_dict.keys() 169 | else: 170 | names = sorted([i["name"] for i in finaldata]) 171 | 172 | name = {0: "repos", 1: "repos", 2: "gists"}[index] 173 | if not names: 174 | return error_alert("User '{}' has no {}".format(username, name)) 175 | rview = data_view(name[:-1], names) 176 | rview.present("sheet") 177 | rview.wait_modal() 178 | tapped_text = rview["rtable"].delegate.selected_item 179 | if tapped_text: 180 | if index == 2: 181 | view["reponame"].text = nameid_dict[tapped_text] 182 | else: 183 | view["reponame"].text = tapped_text 184 | 185 | def data_view(name, data): 186 | rview = ui.View(name="Choose a " + name) 187 | table = ui.TableView() 188 | table.name = "rtable" 189 | table.flex = "WH" 190 | table.data_source = ui.ListDataSource(data) 191 | table.data_source.delete_enabled = False 192 | table.delegate = Delegate() 193 | rview.add_subview(table) 194 | return rview 195 | 196 | def segchange(sender): 197 | index = sender.selected_index 198 | if index == 2: # Gist 199 | view["repolabel"].text = "Gist ID:" 200 | view["bbutton"].title = "Browse gists" 201 | else: 202 | view["repolabel"].text = "Repo:" 203 | view["bbutton"].title = "Browse repos" 204 | 205 | view = ui.load_view('gitrepo') 206 | for name in 'username reponame'.split(): 207 | view[name].autocapitalization_type = ui.AUTOCAPITALIZE_NONE 208 | parse = urlparse.urlparse(clipboard.get().strip()) 209 | if parse.netloc in "www.github.com github.com".split(): 210 | path = [i for i in parse.path.split("/") if i] 211 | if len(path) >= 2: 212 | view["username"].text, view["reponame"].text = path[:2] 213 | if len(path) >= 4: 214 | view["reponame"].text += '/' + path[3] 215 | 216 | view["sgcontrol"].action = segchange 217 | view.present('popover') 218 | """ 219 | PYUIFILE = """[{"class":"View","attributes":{"name":"gitrepo","background_color":"RGBA(1.000000,1.000000,1.000000,1.000000)","tint_color":"RGBA(0.000000,0.478000,1.000000,1.000000)","enabled":true,"border_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","flex":""},"frame":"{{0, 0}, {341, 250}}","nodes":[{"class":"SegmentedControl","attributes":{"name":"sgcontrol","border_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","uuid":"308A3491-ABAA-43BC-8D2C-1319469FF3C9","enabled":true,"segments":"Repo|Release|Gist","flex":"LR"},"frame":"{{16, 6}, {196.5, 29}}","nodes":[]},{"class":"Label","attributes":{"font_size":20,"enabled":true,"text":"Username:","flex":"","name":"label1","border_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","text_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","alignment":"left","uuid":"7C45FE1B-8084-4257-A1D1-DE573BC8299A"},"frame":"{{16.5, 57.5}, {96, 35.5}}","nodes":[]},{"class":"TextField","attributes":{"uuid":"18AD549C-48DF-40CF-B008-5E2C283AD3EA","alignment":"left","autocorrection_type":"no","font_size":17,"font_name":"Avenir-Book","enabled":true,"flex":"","border_color":"RGBA(0.571429,0.571429,0.571429,1.000000)","text_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","corner_radius":2,"secure":false,"border_width":1,"border_style":3,"name":"username","spellchecking_type":"no"},"frame":"{{120.5, 57.5}, {200, 36}}","nodes":[]},{"class":"Label","attributes":{"font_size":20,"enabled":true,"text":"Repo:","flex":"","name":"repolabel","border_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","text_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","alignment":"left","uuid":"97359D8F-3BD5-4D8F-8711-14B4565F9601"},"frame":"{{16.5, 102}, {96, 35}}","nodes":[]},{"class":"TextField","attributes":{"name":"reponame","alignment":"left","autocorrection_type":"no","font_size":17,"font_name":"Avenir-Book","enabled":true,"flex":"","border_color":"RGBA(0.571429,0.571429,0.571429,1.000000)","text_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","corner_radius":2,"secure":false,"uuid":"7BFD908D-CA67-4976-94DD-5CF0DB5EC360","border_style":3,"border_width":1,"spellchecking_type":"no"},"frame":"{{120, 101.5}, {200, 36}}","nodes":[]},{"class":"Button","attributes":{"font_size":16,"enabled":true,"flex":"","font_bold":false,"name":"dbutton","corner_radius":9,"border_color":"RGBA(0.244898,0.520408,0.857143,1.000000)","border_width":1,"action":"gitdownload","uuid":"7C58793E-E2CA-4724-B2FC-3E779FD71890","title":"Download"},"frame":"{{16.5, 201}, {96, 31}}","nodes":[]},{"class":"Label","attributes":{"font_size":20,"enabled":true,"text":"Unzip archive:","flex":"","name":"label3","border_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","text_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","alignment":"left","uuid":"3A801AA2-D086-48E9-9262-E9880135E8EA"},"frame":"{{16.5, 145}, {137, 35}}","nodes":[]},{"class":"Switch","attributes":{"enabled":true,"flex":"","name":"dounzip","value":true,"alpha":1,"border_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","uuid":"40756EA8-214B-4247-9A47-F7D519C0BE88"},"frame":"{{161.5, 147}, {51, 31}}","nodes":[]},{"class":"Button","attributes":{"font_size":16,"enabled":true,"flex":"","font_bold":false,"name":"bbutton","corner_radius":9,"border_color":"RGBA(0.244898,0.520408,0.857143,1.000000)","border_width":1,"action":"gitbrowse","uuid":"127F82F8-97A9-4835-AD60-DF5FCDC942E3","title":"Browse repos"},"frame":"{{139, 201}, {119.5, 31}}","nodes":[]}]}] 220 | """ 221 | 222 | def fix_quotes_out(s): 223 | return s.replace("\\\"\\\"\\\"", "\"\"\"").replace("\\\\", "\\") 224 | 225 | def main(): 226 | if os.path.exists(NAME + ".py"): 227 | console.alert("Failed to Extract", NAME + ".py already exists.") 228 | return 229 | 230 | if os.path.exists(NAME + ".pyui"): 231 | console.alert("Failed to Extract", NAME + ".pyui already exists.") 232 | return 233 | 234 | with open(NAME + ".py", "w") as f: 235 | f.write(fix_quotes_out(PYFILE)) 236 | 237 | with open(NAME + ".pyui", "w") as f: 238 | f.write(fix_quotes_out(PYUIFILE)) 239 | 240 | msg = NAME + ".py and " + NAME + ".pyui were successfully extracted!" 241 | console.alert("Extraction Successful", msg, "OK", hide_cancel_button=True) 242 | 243 | if __name__ == "__main__": 244 | main() 245 | --------------------------------------------------------------------------------