1# ##### BEGIN GPL LICENSE BLOCK #####
2#
3#  This program is free software; you can redistribute it and/or
4#  modify it under the terms of the GNU General Public License
5#  as published by the Free Software Foundation; either version 2
6#  of the License, or (at your option) any later version.
7#
8#  This program is distributed in the hope that it will be useful,
9#  but WITHOUT ANY WARRANTY; without even the implied warranty of
10#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11#  GNU General Public License for more details.
12#
13#  You should have received a copy of the GNU General Public License
14#  along with this program; if not, write to the Free Software Foundation,
15#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16#
17# ##### END GPL LICENSE BLOCK #####
18
19import bpy, os, sys, tempfile, shutil
20from blenderkit import tasks_queue, ui
21
22_presets = os.path.join(bpy.utils.user_resource('SCRIPTS'), "presets")
23BLENDERKIT_LOCAL = "http://localhost:8001"
24BLENDERKIT_MAIN = "https://www.blenderkit.com"
25BLENDERKIT_DEVEL = "https://devel.blenderkit.com"
26BLENDERKIT_API = "/api/v1/"
27BLENDERKIT_REPORT_URL = "usage_report/"
28BLENDERKIT_USER_ASSETS = "/my-assets"
29BLENDERKIT_PLANS = "/plans/pricing/"
30BLENDERKIT_MANUAL = "https://youtu.be/1hVgcQhIAo8"
31BLENDERKIT_MODEL_UPLOAD_INSTRUCTIONS_URL = "https://www.blenderkit.com/docs/upload/"
32BLENDERKIT_MATERIAL_UPLOAD_INSTRUCTIONS_URL = "https://www.blenderkit.com/docs/uploading-material/"
33BLENDERKIT_BRUSH_UPLOAD_INSTRUCTIONS_URL = "https://www.blenderkit.com/docs/uploading-brush/"
34BLENDERKIT_LOGIN_URL = "https://www.blenderkit.com/accounts/login"
35BLENDERKIT_OAUTH_LANDING_URL = "/oauth-landing/"
36BLENDERKIT_SIGNUP_URL = "https://www.blenderkit.com/accounts/register"
37BLENDERKIT_SETTINGS_FILENAME = os.path.join(_presets, "bkit.json")
38
39def cleanup_old_folders():
40    '''function to clean up any historical folders for BlenderKit. By now removes the temp folder.'''
41    orig_temp = os.path.join(os.path.expanduser('~'), 'blenderkit_data', 'temp')
42    if os.path.isdir(orig_temp):
43        try:
44            shutil.rmtree(orig_temp)
45        except Exception as e:
46            print(e)
47            print("couldn't delete old temp directory")
48
49def get_bkit_url():
50    # bpy.app.debug_value = 2
51    d = bpy.app.debug_value
52    # d = 2
53    if d == 1:
54        url = BLENDERKIT_LOCAL
55    elif d == 2:
56        url = BLENDERKIT_DEVEL
57    else:
58        url = BLENDERKIT_MAIN
59    return url
60
61
62def find_in_local(text=''):
63    fs = []
64    for p, d, f in os.walk('.'):
65        for file in f:
66            if text in file:
67                fs.append(file)
68    return fs
69
70
71def get_api_url():
72    return get_bkit_url() + BLENDERKIT_API
73
74
75def get_oauth_landing_url():
76    return get_bkit_url() + BLENDERKIT_OAUTH_LANDING_URL
77
78def get_author_gallery_url(author_id):
79    return f'{get_bkit_url()}/asset-gallery?query=author_id:{author_id}'
80
81
82def default_global_dict():
83    from os.path import expanduser
84    home = expanduser("~")
85    return home + os.sep + 'blenderkit_data'
86
87
88def get_categories_filepath():
89    tempdir = get_temp_dir()
90    return os.path.join(tempdir, 'categories.json')
91
92
93def get_temp_dir(subdir=None):
94    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
95
96    # tempdir = user_preferences.temp_dir
97    tempdir = os.path.join(tempfile.gettempdir(), 'bkit_temp')
98    if tempdir.startswith('//'):
99        tempdir = bpy.path.abspath(tempdir)
100    try:
101        if not os.path.exists(tempdir):
102            os.makedirs(tempdir)
103        if subdir is not None:
104            tempdir = os.path.join(tempdir, subdir)
105            if not os.path.exists(tempdir):
106                os.makedirs(tempdir)
107        cleanup_old_folders()
108    except:
109        tasks_queue.add_task((ui.add_report, ('Cache directory not found. Resetting Cache folder path.',)))
110
111        p = default_global_dict()
112        if p == user_preferences.global_dir:
113            message = 'Global dir was already default, plese set a global directory in addon preferences to a dir where you have write permissions.'
114            tasks_queue.add_task((ui.add_report, (message,)))
115            return None
116        user_preferences.global_dir = p
117        tempdir = get_temp_dir(subdir = subdir)
118    return tempdir
119
120
121def get_download_dirs(asset_type):
122    ''' get directories where assets will be downloaded'''
123    subdmapping = {'brush': 'brushes', 'texture': 'textures', 'model': 'models', 'scene': 'scenes',
124                   'material': 'materials'}
125
126    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
127    dirs = []
128    if user_preferences.directory_behaviour == 'BOTH' or 'GLOBAL':
129        ddir = user_preferences.global_dir
130        if ddir.startswith('//'):
131            ddir = bpy.path.abspath(ddir)
132        if not os.path.exists(ddir):
133            os.makedirs(ddir)
134
135        subdirs = ['brushes', 'textures', 'models', 'scenes', 'materials']
136        for subd in subdirs:
137            subdir = os.path.join(ddir, subd)
138            if not os.path.exists(subdir):
139                os.makedirs(subdir)
140            if subdmapping[asset_type] == subd:
141                dirs.append(subdir)
142    if (
143            user_preferences.directory_behaviour == 'BOTH' or user_preferences.directory_behaviour == 'LOCAL') and bpy.data.is_saved:  # it's important local get's solved as second, since for the linking process only last filename will be taken. For download process first name will be taken and if 2 filenames were returned, file will be copied to the 2nd path.
144        ddir = user_preferences.project_subdir
145        if ddir.startswith('//'):
146            ddir = bpy.path.abspath(ddir)
147            if not os.path.exists(ddir):
148                os.makedirs(ddir)
149
150        subdirs = ['textures', 'models', 'scenes', 'materials']  # brushes get stored only globally.
151        for subd in subdirs:
152            subdir = os.path.join(ddir, subd)
153            if not os.path.exists(subdir):
154                os.makedirs(subdir)
155            if subdmapping[asset_type] == subd:
156                dirs.append(subdir)
157
158    return dirs
159
160
161def slugify(slug):
162    """
163    Normalizes string, converts to lowercase, removes non-alpha characters,
164    and converts spaces to hyphens.
165    """
166    import unicodedata, re
167    slug = slug.lower()
168    slug = slug.replace('.', '_')
169    slug = slug.replace('"', '')
170    slug = slug.replace(' ', '_')
171    # import re
172    # slug = unicodedata.normalize('NFKD', slug)
173    # slug = slug.encode('ascii', 'ignore').lower()
174    slug = re.sub(r'[^a-z0-9]+.- ', '-', slug).strip('-')
175    slug = re.sub(r'[-]+', '-', slug)
176    slug = re.sub(r'/', '_', slug)
177    return slug
178
179
180def extract_filename_from_url(url):
181    if url is not None:
182        imgname = url.split('/')[-1]
183        imgname = imgname.split('?')[0]
184        return imgname
185    return ''
186
187
188def get_download_filenames(asset_data):
189    dirs = get_download_dirs(asset_data['assetType'])
190    file_names = []
191    # fn = asset_data['file_name'].replace('blend_', '')
192    if asset_data.get('url') is not None:
193        # this means asset is already in scene and we don't need to check
194
195        fn = extract_filename_from_url(asset_data['url'])
196        fn.replace('_blend', '')
197        n = slugify(asset_data['name']) + '_' + fn
198        # n = 'x.blend'
199        # strs = (n, asset_data['name'], asset_data['file_name'])
200        for d in dirs:
201            file_name = os.path.join(d, n)
202            file_names.append(file_name)
203    return file_names
204
205
206def delete_asset_debug(asset_data):
207    from blenderkit import download
208    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
209    api_key = user_preferences.api_key
210
211    download.get_download_url(asset_data, download.get_scene_id(), api_key)
212
213    file_names = get_download_filenames(asset_data)
214    for f in file_names:
215        if os.path.isfile(f):
216            try:
217                print(f)
218                os.remove(f)
219            except:
220                e = sys.exc_info()[0]
221                print(e)
222                pass;
223
224
225def get_clean_filepath():
226    script_path = os.path.dirname(os.path.realpath(__file__))
227    subpath = "blendfiles" + os.sep + "cleaned.blend"
228    cp = os.path.join(script_path, subpath)
229    return cp
230
231
232def get_thumbnailer_filepath():
233    script_path = os.path.dirname(os.path.realpath(__file__))
234    # fpath = os.path.join(p, subpath)
235    subpath = "blendfiles" + os.sep + "thumbnailer.blend"
236    return os.path.join(script_path, subpath)
237
238
239def get_material_thumbnailer_filepath():
240    script_path = os.path.dirname(os.path.realpath(__file__))
241    # fpath = os.path.join(p, subpath)
242    subpath = "blendfiles" + os.sep + "material_thumbnailer_cycles.blend"
243    return os.path.join(script_path, subpath)
244    """
245    for p in bpy.utils.script_paths():
246        testfname= os.path.join(p, subpath)#p + '%saddons%sobject_fracture%sdata.blend' % (s,s,s)
247        if os.path.isfile( testfname):
248            fname=testfname
249            return(fname)
250    return None
251    """
252
253
254def get_addon_file(subpath=''):
255    script_path = os.path.dirname(os.path.realpath(__file__))
256    # fpath = os.path.join(p, subpath)
257    return os.path.join(script_path, subpath)
258
259
260def get_addon_thumbnail_path(name):
261    script_path = os.path.dirname(os.path.realpath(__file__))
262    # fpath = os.path.join(p, subpath)
263    ext = name.split('.')[-1]
264    next = ''
265    if not (ext == 'jpg' or ext == 'png'):  # already has ext?
266        next = '.jpg'
267    subpath = "thumbnails" + os.sep + name + next
268    return os.path.join(script_path, subpath)
269