diff options
author | Pullusb <bernou.samuel@gmail.com> | 2020-10-25 18:52:26 +0300 |
---|---|---|
committer | Pullusb <bernou.samuel@gmail.com> | 2020-10-25 18:52:26 +0300 |
commit | 3d480318fbbfe1c32372533a9aafe1d5a4617c26 (patch) | |
tree | 5a2e513de7cdd42cd87b0b370bbed2d39c5e7a52 /greasepencil_tools/import_brush_pack.py | |
parent | e00751ae47f85f90aa232b9cb042bd8b02f2779d (diff) |
Removed bundled brush pack
Update following concern raised by Campbell Barton (https://developer.blender.org/rBA9da77e9af4cbf4d91d043c0a670b6e507531b67d)
Blend file and related ico files were removed.
Import brush pack operator was adapted so user can download and install from a public external url.
Diffstat (limited to 'greasepencil_tools/import_brush_pack.py')
-rw-r--r-- | greasepencil_tools/import_brush_pack.py | 206 |
1 files changed, 182 insertions, 24 deletions
diff --git a/greasepencil_tools/import_brush_pack.py b/greasepencil_tools/import_brush_pack.py index fbeb25f1..90d186c3 100644 --- a/greasepencil_tools/import_brush_pack.py +++ b/greasepencil_tools/import_brush_pack.py @@ -1,35 +1,193 @@ import bpy +import re +import ssl +import urllib.request +import urllib.parse +import zipfile +from pathlib import Path + +def unzip(zip_path, extract_dir_path): + '''Get a zip path and a directory path to extract to''' + with zipfile.ZipFile(zip_path, 'r') as zip_ref: + zip_ref.extractall(extract_dir_path) + +def simple_dl_url(url, dest, fallback_url=None): + ## need to import urlib.request or linux module does not found 'request' using urllib directly + ## need to create an SSl context or linux fail returning unverified ssl + # ssl._create_default_https_context = ssl._create_unverified_context + + try: + urllib.request.urlretrieve(url, dest) + except Exception as e: + print('Error trying to download\n', e) + if fallback_url: + print('\nDownload page for manual install:', fallback_url) + return e + +def download_url(url, dest): + '''download passed url to dest file (include filename)''' + import shutil + import time + ssl._create_default_https_context = ssl._create_unverified_context + start_time = time.time() + + try: + with urllib.request.urlopen(url) as response, open(dest, 'wb') as out_file: + shutil.copyfileobj(response, out_file) + except Exception as e: + print('Error trying to download\n', e) + return e + + print(f"Download time {time.time() - start_time:.2f}s",) + + +def get_brushes(blend_fp): + cur_brushes = [b.name for b in bpy.data.brushes] + with bpy.data.libraries.load(str(blend_fp), link=False) as (data_from, data_to): + # load brushes starting with 'tex' prefix if there are not already there + data_to.brushes = [b for b in data_from.brushes if b.startswith('tex_') and not b in cur_brushes] + # Add holdout + if 'z_holdout' in data_from.brushes and not 'z_holdout' in cur_brushes: + data_to.brushes.append('z_holdout') + + ## force fake user for the brushes + for b in data_to.brushes: + b.use_fake_user = True + + return len(data_to.brushes) class GP_OT_install_brush_pack(bpy.types.Operator): bl_idname = "gp.import_brush_pack" - bl_label = "Import texture brush pack" - bl_description = "import Grease Pencil brush pack from Grease Pencil addon" + bl_label = "Download and import texture brush pack" + bl_description = "Download and import Grease Pencil brush pack from the web (~3.7 Mo)" bl_options = {"REGISTER", "INTERNAL"} - def execute(self, context): - from pathlib import Path - - blendname = 'Official_GP_brush_pack_V1.blend' - blend_fp = Path(__file__).parent / blendname - print('blend_fp: ', blend_fp) - - cur_brushes = [b.name for b in bpy.data.brushes] - with bpy.data.libraries.load(str(blend_fp), link=False) as (data_from, data_to): - # load brushes starting with 'tex' prefix if there are not already there - data_to.brushes = [b for b in data_from.brushes if b.startswith('tex_') and not b in cur_brushes] - # Add holdout - if 'z_holdout' in data_from.brushes: - data_to.brushes.append('z_holdout') - - brush_count = len(data_to.brushes) - ## force fake user for the brushes - for b in data_to.brushes: - b.use_fake_user = True - - if brush_count: - self.report({'INFO'}, f'{brush_count} brushes installed') + # @classmethod + # def poll(cls, context): + # return True + + def _append_brushes(self, blend_fp): + bct = get_brushes(blend_fp) + if bct: + self.report({'INFO'}, f'{bct} brushes installed') else: self.report({'WARNING'}, 'Brushes already loaded') + + def _install_from_zip(self): + ## get blend file name + blendname = None + with zipfile.ZipFile(self.brushzip, 'r') as zfd: + for f in zfd.namelist(): + if f.endswith('.blend'): + blendname = f + break + if not blendname: + self.report({'ERROR'}, f'blend file not found in zip {self.brushzip}') + return + + unzip(self.brushzip, self.temp) + + self._append_brushes(Path(self.temp) / blendname) + + def execute(self, context): + + import tempfile + import json + import hashlib + import os + + ## get temp dir + temp = tempfile.gettempdir() + if not temp: + self.report({'ERROR'}, 'no os temporary directory found to download brush pack (using python tempfile.gettempdir())') + return {"CANCELLED"} + + self.temp = Path(temp) + + ## download link from gitlab + # brush pack project https://gitlab.com/pepe-school-land/gp-brush-pack + repo_url = r'https://gitlab.com/api/v4/projects/21994857' + tree_url = f'{repo_url}/repository/tree' + + ## need to create an SSl context or linux fail and raise unverified ssl + ssl._create_default_https_context = ssl._create_unverified_context + + try: + with urllib.request.urlopen(tree_url) as response: + html = response.read() + except: + ## try loading from tempdir + packs = [f for f in os.listdir(self.temp) if 'GP_brush_pack' in f and f.endswith('.blend')] + if packs: + packs.sort() + self._append_brushes(Path(self.temp) / packs[-1]) + self.report({'WARNING'}, 'Brushes loaded from temp directory (No download)') + # print('Could not reach web url : Brushes were loaded from temp directory file (No download)') + return {"FINISHED"} + + self.report({'ERROR'}, f'Check your internet connexion, Impossible to connect to url: {tree_url}') + return {"CANCELLED"} + + if not html: + self.report({'ERROR'}, f'No response read from: {tree_url}') + return {"CANCELLED"} + + tree_dic = json.loads(html) + zips = [fi for fi in tree_dic if fi['type'] == 'blob' and fi['name'].endswith('.zip')] + + if not zips: + print(f'no zip file found in {tree_url}') + return {"CANCELLED"} + + ## sort by name to get last + zips.sort(key=lambda x: x['name']) + last_zip = zips[-1] + zipname = last_zip['name'] + id_num = last_zip['id'] + + + ## url by filename + # filepath_encode = urllib.parse.quote(zipname, safe='')# need safe to convert possible '/' + # dl_url = f'{repo_url}/repository/files/{filepath_encode}/raw?ref=master' + + ## url by blobs + dl_url = f"{repo_url}/repository/blobs/{id_num}/raw" + + self.brushzip = self.temp / zipname + + + ### Load existing files instead of redownloading if exists and up to date (same hash) + if self.brushzip.exists(): + ### Test the hash against online git hash (check for update) + BLOCK_SIZE = 524288# 512 Kb buf size + file_hash = hashlib.sha1() + file_hash.update(("blob %u\0" % os.path.getsize(self.brushzip)).encode('utf-8')) + with open(self.brushzip, 'rb') as f: + fb = f.read(BLOCK_SIZE) + while len(fb) > 0: + file_hash.update(fb) + fb = f.read(BLOCK_SIZE) + + if file_hash.hexdigest() == id_num: # same git SHA1 + ## is up to date, install + print(f'{self.brushzip} is up do date, appending brushes') + self._install_from_zip() + return {"FINISHED"} + + ## Download, unzip, use blend + print(f'Downloading brushpack in {self.brushzip}') + ## https://cloud.blender.org/p/gallery/5f235cc297f8815e74ffb90b + + fallback_url='https://gitlab.com/pepe-school-land/gp-brush-pack/-/blob/master/Official_GP_brush_pack_v01.zip' + err = simple_dl_url(dl_url, str(self.brushzip), fallback_url) + # err = download_url(dl_url, str(self.brushzip), fallback_url) + + if err: + self.report({'ERROR'}, 'Could not download brush pack. Check your internet connection. (see console for detail)') + return {"CANCELLED"} + else: + print('Done') + self._install_from_zip() return {"FINISHED"} |