Welcome to mirror list, hosted at ThFree Co, Russian Federation.

import_brush_pack.py « greasepencil_tools - git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: b1306bed338e6d1b400a5b2e93becfd07b898622 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
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 = "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"}

    # @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"}


def register():
    bpy.utils.register_class(GP_OT_install_brush_pack)

def unregister():
    bpy.utils.unregister_class(GP_OT_install_brush_pack)