1 # SPDX-License-Identifier: GPL-2.0-or-later
9 from pathlib
import Path
11 def unzip(zip_path
, extract_dir_path
):
12 '''Get a zip path and a directory path to extract to'''
13 with zipfile
.ZipFile(zip_path
, 'r') as zip_ref
:
14 zip_ref
.extractall(extract_dir_path
)
16 def simple_dl_url(url
, dest
, fallback_url
=None):
17 ## need to import urlib.request or linux module does not found 'request' using urllib directly
18 ## need to create an SSl context or linux fail returning unverified ssl
19 # ssl._create_default_https_context = ssl._create_unverified_context
22 urllib
.request
.urlretrieve(url
, dest
)
23 except Exception as e
:
24 print('Error trying to download\n', e
)
26 print('\nDownload page for manual install:', fallback_url
)
29 def download_url(url
, dest
):
30 '''download passed url to dest file (include filename)'''
33 ssl
._create
_default
_https
_context
= ssl
._create
_unverified
_context
34 start_time
= time
.time()
37 with urllib
.request
.urlopen(url
) as response
, open(dest
, 'wb') as out_file
:
38 shutil
.copyfileobj(response
, out_file
)
39 except Exception as e
:
40 print('Error trying to download\n', e
)
43 print(f
"Download time {time.time() - start_time:.2f}s",)
46 def get_brushes(blend_fp
):
47 cur_brushes
= [b
.name
for b
in bpy
.data
.brushes
]
48 with bpy
.data
.libraries
.load(str(blend_fp
), link
=False) as (data_from
, data_to
):
49 # load brushes starting with 'tex' prefix if there are not already there
50 data_to
.brushes
= [b
for b
in data_from
.brushes
if b
.startswith('tex_') and not b
in cur_brushes
]
52 if 'z_holdout' in data_from
.brushes
and not 'z_holdout' in cur_brushes
:
53 data_to
.brushes
.append('z_holdout')
55 ## force fake user for the brushes
56 for b
in data_to
.brushes
:
57 b
.use_fake_user
= True
59 return len(data_to
.brushes
)
61 class GP_OT_install_brush_pack(bpy
.types
.Operator
):
62 bl_idname
= "gp.import_brush_pack"
63 bl_label
= "Download and import texture brush pack"
64 bl_description
= "Download and import Grease Pencil brush pack from the web (~3.7 Mo)"
65 bl_options
= {"REGISTER", "INTERNAL"}
68 # def poll(cls, context):
71 def _append_brushes(self
, blend_fp
):
72 bct
= get_brushes(blend_fp
)
74 self
.report({'INFO'}, f
'{bct} brushes installed')
76 self
.report({'WARNING'}, 'Brushes already loaded')
78 def _install_from_zip(self
):
79 ## get blend file name
81 with zipfile
.ZipFile(self
.brushzip
, 'r') as zfd
:
82 for f
in zfd
.namelist():
83 if f
.endswith('.blend'):
87 self
.report({'ERROR'}, f
'blend file not found in zip {self.brushzip}')
90 unzip(self
.brushzip
, self
.temp
)
92 self
._append
_brushes
(Path(self
.temp
) / blendname
)
94 def execute(self
, context
):
102 temp
= tempfile
.gettempdir()
104 self
.report({'ERROR'}, 'no os temporary directory found to download brush pack (using python tempfile.gettempdir())')
107 self
.temp
= Path(temp
)
109 ## download link from gitlab
110 # brush pack project https://gitlab.com/pepe-school-land/gp-brush-pack
111 repo_url
= r
'https://gitlab.com/api/v4/projects/21994857'
112 tree_url
= f
'{repo_url}/repository/tree'
114 ## need to create an SSl context or linux fail and raise unverified ssl
115 ssl
._create
_default
_https
_context
= ssl
._create
_unverified
_context
118 with urllib
.request
.urlopen(tree_url
) as response
:
119 html
= response
.read()
121 ## try loading from tempdir
122 packs
= [f
for f
in os
.listdir(self
.temp
) if 'GP_brush_pack' in f
and f
.endswith('.blend')]
125 self
._append
_brushes
(Path(self
.temp
) / packs
[-1])
126 self
.report({'WARNING'}, 'Brushes loaded from temp directory (No download)')
127 # print('Could not reach web url : Brushes were loaded from temp directory file (No download)')
130 self
.report({'ERROR'}, f
'Check your internet connexion, Impossible to connect to url: {tree_url}')
134 self
.report({'ERROR'}, f
'No response read from: {tree_url}')
137 tree_dic
= json
.loads(html
)
138 zips
= [fi
for fi
in tree_dic
if fi
['type'] == 'blob' and fi
['name'].endswith('.zip')]
141 print(f
'no zip file found in {tree_url}')
144 ## sort by name to get last
145 zips
.sort(key
=lambda x
: x
['name'])
147 zipname
= last_zip
['name']
148 id_num
= last_zip
['id']
152 # filepath_encode = urllib.parse.quote(zipname, safe='')# need safe to convert possible '/'
153 # dl_url = f'{repo_url}/repository/files/{filepath_encode}/raw?ref=master'
156 dl_url
= f
"{repo_url}/repository/blobs/{id_num}/raw"
158 self
.brushzip
= self
.temp
/ zipname
161 ### Load existing files instead of redownloading if exists and up to date (same hash)
162 if self
.brushzip
.exists():
163 ### Test the hash against online git hash (check for update)
164 BLOCK_SIZE
= 524288# 512 Kb buf size
165 file_hash
= hashlib
.sha1()
166 file_hash
.update(("blob %u\0" % os
.path
.getsize(self
.brushzip
)).encode('utf-8'))
167 with
open(self
.brushzip
, 'rb') as f
:
168 fb
= f
.read(BLOCK_SIZE
)
171 fb
= f
.read(BLOCK_SIZE
)
173 if file_hash
.hexdigest() == id_num
: # same git SHA1
174 ## is up to date, install
175 print(f
'{self.brushzip} is up do date, appending brushes')
176 self
._install
_from
_zip
()
179 ## Download, unzip, use blend
180 print(f
'Downloading brushpack in {self.brushzip}')
181 ## https://cloud.blender.org/p/gallery/5f235cc297f8815e74ffb90b
183 fallback_url
='https://gitlab.com/pepe-school-land/gp-brush-pack/-/blob/master/Official_GP_brush_pack_v01.zip'
184 err
= simple_dl_url(dl_url
, str(self
.brushzip
), fallback_url
)
185 # err = download_url(dl_url, str(self.brushzip), fallback_url)
188 self
.report({'ERROR'}, 'Could not download brush pack. Check your internet connection. (see console for detail)')
192 self
._install
_from
_zip
()
197 bpy
.utils
.register_class(GP_OT_install_brush_pack
)
200 bpy
.utils
.unregister_class(GP_OT_install_brush_pack
)