1 # SPDX-FileCopyrightText: 2020-2023 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
10 from pathlib
import Path
12 def unzip(zip_path
, extract_dir_path
):
13 '''Get a zip path and a directory path to extract to'''
14 with zipfile
.ZipFile(zip_path
, 'r') as zip_ref
:
15 zip_ref
.extractall(extract_dir_path
)
17 def simple_dl_url(url
, dest
, fallback_url
=None):
18 ## need to import urlib.request or linux module does not found 'request' using urllib directly
19 ## need to create an SSl context or linux fail returning unverified ssl
20 # ssl._create_default_https_context = ssl._create_unverified_context
23 urllib
.request
.urlretrieve(url
, dest
)
24 except Exception as e
:
25 print('Error trying to download\n', e
)
27 print('\nDownload page for manual install:', fallback_url
)
30 def get_brushes(blend_fp
):
31 cur_brushes
= [b
.name
for b
in bpy
.data
.brushes
]
32 with bpy
.data
.libraries
.load(str(blend_fp
), link
=False) as (data_from
, data_to
):
33 # load brushes starting with 'tex' prefix if there are not already there
34 data_to
.brushes
= [b
for b
in data_from
.brushes
if b
.startswith('tex_') and not b
in cur_brushes
]
36 if 'z_holdout' in data_from
.brushes
and not 'z_holdout' in cur_brushes
:
37 data_to
.brushes
.append('z_holdout')
39 ## force fake user for the brushes
40 for b
in data_to
.brushes
:
41 b
.use_fake_user
= True
43 return len(data_to
.brushes
)
45 class GP_OT_install_brush_pack(bpy
.types
.Operator
):
46 bl_idname
= "gp.import_brush_pack"
47 bl_label
= "Download and import texture brush pack"
48 bl_description
= "Download and import Grease Pencil brush pack from the web (~3.7 Mo)"
49 bl_options
= {"REGISTER", "INTERNAL"}
52 # def poll(cls, context):
55 def _append_brushes(self
, blend_fp
):
56 bct
= get_brushes(blend_fp
)
58 self
.report({'INFO'}, f
'{bct} brushes installed')
60 self
.report({'WARNING'}, 'Brushes already loaded')
62 def _install_from_zip(self
):
63 ## get blend file name
65 with zipfile
.ZipFile(self
.brushzip
, 'r') as zfd
:
66 for f
in zfd
.namelist():
67 if f
.endswith('.blend'):
71 self
.report({'ERROR'}, f
'blend file not found in zip {self.brushzip}')
74 unzip(self
.brushzip
, self
.temp
)
76 self
._append
_brushes
(Path(self
.temp
) / blendname
)
78 def execute(self
, context
):
82 temp
= tempfile
.gettempdir()
84 self
.report({'ERROR'}, 'no os temporary directory found to download brush pack (using python tempfile.gettempdir())')
87 self
.temp
= Path(temp
)
89 dl_url
= 'https://download.blender.org/demo/bundles/bundles-3.0/grease-pencil-brush-pack.zip'
91 ## need to create an SSl context or linux fail and raise unverified ssl
92 ssl
._create
_default
_https
_context
= ssl
._create
_unverified
_context
97 with urllib
.request
.urlopen(dl_url
) as response
:
98 file_size
= int(response
.getheader('Content-Length'))
100 ## try loading from tempdir
101 packs
= [f
for f
in os
.listdir(self
.temp
) if 'gp_brush_pack' in f
.lower() and f
.endswith('.blend')]
104 self
._append
_brushes
(Path(self
.temp
) / packs
[-1])
105 self
.report({'WARNING'}, 'Brushes loaded from temp directory (No download)')
108 self
.report({'ERROR'}, f
'Check your internet connection, impossible to connect to url: {dl_url}')
111 if file_size
is None:
112 self
.report({'ERROR'}, f
'No response read from: {dl_url}')
115 self
.brushzip
= self
.temp
/ Path(dl_url
).name
117 ### Load existing files instead of redownloading if exists and up to date (same hash)
118 if self
.brushzip
.exists():
120 ### compare using file size with size from url header
121 disk_size
= self
.brushzip
.stat().st_size
122 if disk_size
== file_size
:
123 ## is up to date, install
124 print(f
'{self.brushzip} is up do date, appending brushes')
125 self
._install
_from
_zip
()
128 ## Download, unzip, use blend
129 print(f
'Downloading brushpack in {self.brushzip}')
131 fallback_url
='https://cloud.blender.org/p/gallery/5f235cc297f8815e74ffb90b'
132 err
= simple_dl_url(dl_url
, str(self
.brushzip
), fallback_url
)
135 self
.report({'ERROR'}, 'Could not download brush pack. Check your internet connection. (see console for detail)')
139 self
._install
_from
_zip
()
144 bpy
.utils
.register_class(GP_OT_install_brush_pack
)
147 bpy
.utils
.unregister_class(GP_OT_install_brush_pack
)