File indexing completed on 2024-05-26 04:34:18

0001 # SPDX-FileCopyrightText: 2029 Rebecca Breu <rebecca@rbreu.de>
0002 
0003 # This file is part of Krita.
0004 
0005 # Krita is free software: you can redistribute it and/or modify
0006 # it under the terms of the GNU General Public License as published by
0007 # the Free Software Foundation, either version 3 of the License, or
0008 # (at your option) any later version.
0009 
0010 # Krita is distributed in the hope that it will be useful,
0011 # but WITHOUT ANY WARRANTY; without even the implied warranty of
0012 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013 # GNU General Public License for more details.
0014 
0015 # You should have received a copy of the GNU General Public License
0016 # along with Krita.  If not, see <https://www.gnu.org/licenses/>.
0017 
0018 import mimetypes
0019 import os
0020 import urllib
0021 import urllib.request
0022 
0023 
0024 class PluginDownloadError(Exception):
0025     """Base class for all exceptions of this module."""
0026     pass
0027 
0028 
0029 def is_zip(url):
0030     """Check if the given URL is a direct link to a zip file"""
0031 
0032     MTYPE = 'application/zip'
0033 
0034     # This just goes by the ending of the url string:
0035     if mimetypes.guess_type(url)[0] == MTYPE:
0036         return True
0037 
0038     # Could still be a zip, so check the HTTP headers:
0039     try:
0040         request = urllib.request.Request(url, method='HEAD')
0041         response = urllib.request.urlopen(request)
0042     except Exception as e:
0043         raise PluginDownloadError(str(e))
0044 
0045     return response.getheader('Content-Type') == MTYPE
0046 
0047 
0048 def get_zipurl_github(base_path):
0049     """Guess the zip location from a github url"""
0050 
0051     url = None
0052     split = base_path.split('/')
0053     if len(split) > 2:
0054         url = (f'https://api.github.com/repos/{split[1]}/{split[2]}/'
0055                'zipball/master')
0056     return (url, {'Accept': 'application/vnd.github.v3+json'})
0057 
0058 
0059 def get_zipurl(url):
0060     """Guess the zip location from a given URL."""
0061 
0062     if is_zip(url):
0063         return (url, {})
0064 
0065     parsed = urllib.parse.urlparse(url)
0066     if parsed.netloc == 'github.com':
0067         return get_zipurl_github(parsed.path)
0068 
0069     raise PluginDownloadError(
0070         i18n('Could not determine download link from URL'))
0071 
0072 
0073 def download_plugin(url, dest_dir):
0074     """Download a plugin from a given URL into the given directory.
0075 
0076     ``url`` may either point directly to a zip location (on any site),
0077     or to a github repository.
0078 
0079     Returns full path of the downloaded zip file.
0080     """
0081 
0082     dest_path = os.path.join(dest_dir, 'plugin.zip')
0083     zip_url, headers = get_zipurl(url)
0084     headers['User-Agent'] = 'krita-plugin-importer'
0085 
0086     try:
0087         request = urllib.request.Request(zip_url, headers=headers)
0088         with urllib.request.urlopen(request) as source:
0089             with open(dest_path, 'wb') as destination:
0090                 destination.write(source.read())
0091     except Exception as e:
0092         raise PluginDownloadError(str(e))
0093     return dest_path