Node Wrangler: Add more specific poll methods
[blender-addons.git] / greasepencil_tools / import_brush_pack.py
blob9a7866e408136799bd0f104c6c37650b1447f102
1 # SPDX-FileCopyrightText: 2020-2023 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 import bpy
6 import ssl
7 import urllib.request
8 import urllib.parse
9 import zipfile
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
22 try:
23 urllib.request.urlretrieve(url, dest)
24 except Exception as e:
25 print('Error trying to download\n', e)
26 if fallback_url:
27 print('\nDownload page for manual install:', fallback_url)
28 return e
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]
35 # Add holdout
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"}
51 # @classmethod
52 # def poll(cls, context):
53 # return True
55 def _append_brushes(self, blend_fp):
56 bct = get_brushes(blend_fp)
57 if bct:
58 self.report({'INFO'}, f'{bct} brushes installed')
59 else:
60 self.report({'WARNING'}, 'Brushes already loaded')
62 def _install_from_zip(self):
63 ## get blend file name
64 blendname = None
65 with zipfile.ZipFile(self.brushzip, 'r') as zfd:
66 for f in zfd.namelist():
67 if f.endswith('.blend'):
68 blendname = f
69 break
70 if not blendname:
71 self.report({'ERROR'}, f'blend file not found in zip {self.brushzip}')
72 return
74 unzip(self.brushzip, self.temp)
76 self._append_brushes(Path(self.temp) / blendname)
78 def execute(self, context):
79 import tempfile
80 import os
82 temp = tempfile.gettempdir()
83 if not temp:
84 self.report({'ERROR'}, 'no os temporary directory found to download brush pack (using python tempfile.gettempdir())')
85 return {"CANCELLED"}
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
94 file_size = None
96 try:
97 with urllib.request.urlopen(dl_url) as response:
98 file_size = int(response.getheader('Content-Length'))
99 except:
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')]
102 if packs:
103 packs.sort()
104 self._append_brushes(Path(self.temp) / packs[-1])
105 self.report({'WARNING'}, 'Brushes loaded from temp directory (No download)')
106 return {"FINISHED"}
108 self.report({'ERROR'}, f'Check your internet connection, impossible to connect to url: {dl_url}')
109 return {"CANCELLED"}
111 if file_size is None:
112 self.report({'ERROR'}, f'No response read from: {dl_url}')
113 return {"CANCELLED"}
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()
126 return {"FINISHED"}
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)
134 if err:
135 self.report({'ERROR'}, 'Could not download brush pack. Check your internet connection. (see console for detail)')
136 return {"CANCELLED"}
137 else:
138 print('Done')
139 self._install_from_zip()
140 return {"FINISHED"}
143 def register():
144 bpy.utils.register_class(GP_OT_install_brush_pack)
146 def unregister():
147 bpy.utils.unregister_class(GP_OT_install_brush_pack)