Merge branch 'blender-v3.6-release'
[blender-addons.git] / greasepencil_tools / import_brush_pack.py
blobad8a667fad1c49aaa01ebd51368717fa9933d638
1 # SPDX-License-Identifier: GPL-2.0-or-later
3 import bpy
4 import urllib.request
5 import urllib.parse
6 import zipfile
7 from pathlib import Path
9 def unzip(zip_path, extract_dir_path):
10 '''Get a zip path and a directory path to extract to'''
11 with zipfile.ZipFile(zip_path, 'r') as zip_ref:
12 zip_ref.extractall(extract_dir_path)
14 def simple_dl_url(url, dest, fallback_url=None):
15 ## need to import urlib.request or linux module does not found 'request' using urllib directly
16 ## need to create an SSl context or linux fail returning unverified ssl
17 # ssl._create_default_https_context = ssl._create_unverified_context
19 try:
20 urllib.request.urlretrieve(url, dest)
21 except Exception as e:
22 print('Error trying to download\n', e)
23 if fallback_url:
24 print('\nDownload page for manual install:', fallback_url)
25 return e
27 def get_brushes(blend_fp):
28 cur_brushes = [b.name for b in bpy.data.brushes]
29 with bpy.data.libraries.load(str(blend_fp), link=False) as (data_from, data_to):
30 # load brushes starting with 'tex' prefix if there are not already there
31 data_to.brushes = [b for b in data_from.brushes if b.startswith('tex_') and not b in cur_brushes]
32 # Add holdout
33 if 'z_holdout' in data_from.brushes and not 'z_holdout' in cur_brushes:
34 data_to.brushes.append('z_holdout')
36 ## force fake user for the brushes
37 for b in data_to.brushes:
38 b.use_fake_user = True
40 return len(data_to.brushes)
42 class GP_OT_install_brush_pack(bpy.types.Operator):
43 bl_idname = "gp.import_brush_pack"
44 bl_label = "Download and import texture brush pack"
45 bl_description = "Download and import Grease Pencil brush pack from the web (~3.7 Mo)"
46 bl_options = {"REGISTER", "INTERNAL"}
48 # @classmethod
49 # def poll(cls, context):
50 # return True
52 def _append_brushes(self, blend_fp):
53 bct = get_brushes(blend_fp)
54 if bct:
55 self.report({'INFO'}, f'{bct} brushes installed')
56 else:
57 self.report({'WARNING'}, 'Brushes already loaded')
59 def _install_from_zip(self):
60 ## get blend file name
61 blendname = None
62 with zipfile.ZipFile(self.brushzip, 'r') as zfd:
63 for f in zfd.namelist():
64 if f.endswith('.blend'):
65 blendname = f
66 break
67 if not blendname:
68 self.report({'ERROR'}, f'blend file not found in zip {self.brushzip}')
69 return
71 unzip(self.brushzip, self.temp)
73 self._append_brushes(Path(self.temp) / blendname)
75 def execute(self, context):
76 import ssl
77 import tempfile
78 import os
80 temp = tempfile.gettempdir()
81 if not temp:
82 self.report({'ERROR'}, 'no os temporary directory found to download brush pack (using python tempfile.gettempdir())')
83 return {"CANCELLED"}
85 self.temp = Path(temp)
87 dl_url = 'https://download.blender.org/demo/bundles/bundles-3.0/grease-pencil-brush-pack.zip'
89 ## need to create an SSl context or linux fail and raise unverified ssl
90 ssl._create_default_https_context = ssl._create_unverified_context
92 file_size = None
94 try:
95 with urllib.request.urlopen(dl_url) as response:
96 file_size = int(response.getheader('Content-Length'))
97 except:
98 ## try loading from tempdir
99 packs = [f for f in os.listdir(self.temp) if 'gp_brush_pack' in f.lower() and f.endswith('.blend')]
100 if packs:
101 packs.sort()
102 self._append_brushes(Path(self.temp) / packs[-1])
103 self.report({'WARNING'}, 'Brushes loaded from temp directory (No download)')
104 return {"FINISHED"}
106 self.report({'ERROR'}, f'Check your internet connection, impossible to connect to url: {dl_url}')
107 return {"CANCELLED"}
109 if file_size is None:
110 self.report({'ERROR'}, f'No response read from: {dl_url}')
111 return {"CANCELLED"}
113 self.brushzip = self.temp / Path(dl_url).name
115 ### Load existing files instead of redownloading if exists and up to date (same hash)
116 if self.brushzip.exists():
118 ### compare using file size with size from url header
119 disk_size = self.brushzip.stat().st_size
120 if disk_size == file_size:
121 ## is up to date, install
122 print(f'{self.brushzip} is up do date, appending brushes')
123 self._install_from_zip()
124 return {"FINISHED"}
126 ## Download, unzip, use blend
127 print(f'Downloading brushpack in {self.brushzip}')
129 fallback_url='https://cloud.blender.org/p/gallery/5f235cc297f8815e74ffb90b'
130 err = simple_dl_url(dl_url, str(self.brushzip), fallback_url)
132 if err:
133 self.report({'ERROR'}, 'Could not download brush pack. Check your internet connection. (see console for detail)')
134 return {"CANCELLED"}
135 else:
136 print('Done')
137 self._install_from_zip()
138 return {"FINISHED"}
141 def register():
142 bpy.utils.register_class(GP_OT_install_brush_pack)
144 def unregister():
145 bpy.utils.unregister_class(GP_OT_install_brush_pack)