File size: 6,785 Bytes
27867f1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
MIT License

Copyright (C) 2023 ROCKY4546
https://github.com/rocky4546

This file is part of Cabernet

Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
"""

import logging
import json
import importlib
import importlib.resources
import os
import pathlib
import requests
import urllib

import lib.common.exceptions as exceptions
import lib.common.utils as utils
from lib.db.db_plugins import DBPlugins
from lib.common.decorators import handle_url_except
from lib.common.decorators import handle_json_except


class RepoHandler:

    http_session = requests.session()
    logger = None

    def __init__(self, _config_obj):
        self.config_obj = _config_obj
        if RepoHandler.logger is None:
            RepoHandler.logger = logging.getLogger(__name__)
        self.plugin_db = DBPlugins(_config_obj.data)



    def load_cabernet_repo(self):
        """
        Loads the manifest which points to the plugin.json list of plugins
        Will update the database on the manifest and plugin list
        If there is a plugin that is no longer in the list, will tag for
        deletion. (don't know at this point if it is installed.)
        """
        repo_settings = self.import_cabernet_manifest()
        self.save_repo(repo_settings)
        self.update_plugins(repo_settings)

    def import_cabernet_manifest(self):
        """
        Loads the manifest for cabernet repo
        """
        json_settings = importlib.resources.read_text(self.config_obj.data['paths']['resources_pkg'], utils.CABERNET_REPO)
        settings = json.loads(json_settings)
        if settings:
            settings = settings['plugin']
            settings['repo_url'] = utils.CABERNET_REPO
            self.plugin_db.get_repos(utils.CABERNET_ID)
        return settings

    def save_repo(self, _repo):
        """
        Saves to DB the repo json settings
        """
        self.plugin_db.save_repo(_repo)


    def cache_thumbnails(self, _plugin_defn):
        """
        Determine if the cache area has the thumbnail, if not
        will download and store the thumbnail
        """
        # path = thumbnail cache path + plugin_id + icon or fanart path
        thumbnail_path = self.config_obj.data['paths']['thumbnails_dir']
        plugin_id = _plugin_defn['id']
        icon_path = _plugin_defn['icon']
        fanart_path = _plugin_defn['fanart']
        
        repoid = _plugin_defn['repoid']
        repo_defn = self.plugin_db.get_repos(repoid)
        if not repo_defn:
            self.logger.notice('Repo not defined for plugin {}, unable to cache thumbnails'
                .format(plugin_id))
            return
        datadir = repo_defn[0]['dir']['datadir']['url']
        self.cache_thumbnail(datadir, plugin_id, icon_path, thumbnail_path)
        self.cache_thumbnail(datadir, plugin_id, fanart_path, thumbnail_path)

    def cache_thumbnail(self, _datadir, _plugin_id, _image_relpath, _thumbnail_path):
        """
        _datadir: datadir url from the repo definition
        _plugin_id: plugin id which is also the folder name
        _image_repath: relative path found in the plugin definition
        _thumbnail_path: config setting to the thumbnail path area
        """
        full_repo = '/'.join([
            _datadir, _plugin_id, _image_relpath])
        full_cache = pathlib.Path(
            _thumbnail_path, _plugin_id, _image_relpath)
        if not full_cache.exists():
            image = self.get_uri_data(full_repo, 2)
            self.save_file(image, full_cache)

    def update_plugins(self, _repo_settings):
        """
        Gets the list of plugins for this repo from [dir][info] and updates the db
        """
        uri = _repo_settings['dir']['info']
        plugin_json = self.get_uri_json_data(uri)
        if plugin_json:
            plugin_json = plugin_json['plugins']
            for plugin in plugin_json:
                plugin = plugin['plugin']
                if 'repository' in plugin['category']:
                    continue
                # pull the db item. merge them and then update the db with new data.
                plugin_data = self.plugin_db.get_plugins(_installed=None, _repo_id=_repo_settings['id'], _plugin_id=plugin['id'])
                if plugin_data:
                    plugin_data = plugin_data[0]
                    plugin['repoid'] = _repo_settings['id']
                    plugin['version']['installed'] = plugin_data['version']['installed']
                    plugin['version']['latest'] = plugin['version']['current']
                    plugin['version']['current'] = plugin_data['version']['current']
                    plugin['changelog'] = plugin.get('changelog')
                    if plugin_data.get('external'):
                        plugin['external'] = plugin_data['external']
                    else:
                        plugin['external'] = True
                else:
                    plugin['repoid'] = _repo_settings['id']
                    plugin['version']['installed'] = False
                    plugin['version']['latest'] = plugin['version']['current']
                    plugin['version']['current'] = None
                    plugin['external'] = True
                self.cache_thumbnails(plugin)
                self.plugin_db.save_plugin(plugin)

    @handle_url_except()
    def get_uri_data(self, _uri, _retries):
        header = {
            'User-agent': utils.DEFAULT_USER_AGENT}
        resp = RepoHandler.http_session.get(_uri, headers=header, timeout=(2, 8))
        x = resp.content
        resp.raise_for_status()
        return x

    @handle_url_except()
    @handle_json_except
    def get_uri_json_data(self, _uri):
        header = {
            'Content-Type': 'application/json',
            'User-agent': utils.DEFAULT_USER_AGENT}
        req = urllib.request.Request(_uri, headers=header)
        with urllib.request.urlopen(req, timeout=10.0) as resp:
            return json.load(resp)


    def save_file(self, _data, _file):
        try:
            os.makedirs(os.path.dirname(_file), exist_ok=True)
            
            open(os.path.join(_file), 'wb').write(_data)
        except Exception as e:
            self.logger.warning("An error occurred saving %s file\n%s" % (_file, e))
            raise