kapsikkum-unmanic – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | #!/usr/bin/env python3 |
2 | # -*- coding: utf-8 -*- |
||
3 | |||
4 | """ |
||
5 | unmanic.plugins_api.py |
||
6 | |||
7 | Written by: Josh.5 <jsunnex@gmail.com> |
||
8 | Date: 03 Mar 2021, (12:10 PM) |
||
9 | |||
10 | Copyright: |
||
11 | Copyright (C) Josh Sunnex - All Rights Reserved |
||
12 | |||
13 | Permission is hereby granted, free of charge, to any person obtaining a copy |
||
14 | of this software and associated documentation files (the "Software"), to deal |
||
15 | in the Software without restriction, including without limitation the rights |
||
16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||
17 | copies of the Software, and to permit persons to whom the Software is |
||
18 | furnished to do so, subject to the following conditions: |
||
19 | |||
20 | The above copyright notice and this permission notice shall be included in all |
||
21 | copies or substantial portions of the Software. |
||
22 | |||
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||
24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||
25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
||
26 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
||
27 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
||
28 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE |
||
29 | OR OTHER DEALINGS IN THE SOFTWARE. |
||
30 | |||
31 | """ |
||
32 | import hashlib |
||
33 | import json |
||
34 | import tornado.log |
||
35 | |||
36 | from unmanic.libs.plugins import PluginsHandler |
||
37 | from unmanic.libs.uiserver import UnmanicDataQueues |
||
38 | from unmanic.libs.unplugins import PluginExecutor |
||
39 | from unmanic.webserver.api_v1.base_api_handler import BaseApiHandler |
||
40 | |||
41 | |||
42 | class ApiPluginsHandler(BaseApiHandler): |
||
43 | name = None |
||
44 | params = None |
||
45 | unmanic_data_queues = None |
||
46 | |||
47 | routes = [ |
||
48 | { |
||
49 | "supported_methods": ["GET"], |
||
50 | "call_method": "get_plugin_list", |
||
51 | "path_pattern": r"/api/v1/plugins/list", |
||
52 | }, |
||
53 | { |
||
54 | "supported_methods": ["POST"], |
||
55 | "call_method": "install_plugin_by_id", |
||
56 | "path_pattern": r"/api/v1/plugins/install", |
||
57 | }, |
||
58 | { |
||
59 | "supported_methods": ["GET"], |
||
60 | "call_method": "get_repo_list", |
||
61 | "path_pattern": r"/api/v1/plugins/repos/list", |
||
62 | }, |
||
63 | { |
||
64 | "supported_methods": ["POST"], |
||
65 | "call_method": "update_repo_list", |
||
66 | "path_pattern": r"/api/v1/plugins/repos/update", |
||
67 | }, |
||
68 | { |
||
69 | "supported_methods": ["GET"], |
||
70 | "call_method": "update_repos", |
||
71 | "path_pattern": r"/api/v1/plugins/repos/fetch", |
||
72 | }, |
||
73 | ] |
||
74 | |||
75 | def initialize(self, **kwargs): |
||
76 | self.name = 'plugins_api' |
||
77 | self.params = kwargs.get("params") |
||
78 | udq = UnmanicDataQueues() |
||
79 | self.unmanic_data_queues = udq.get_unmanic_data_queues() |
||
80 | |||
81 | def set_default_headers(self): |
||
82 | """Set the default response header to be JSON.""" |
||
83 | self.set_header("Content-Type", 'application/json; charset="utf-8"') |
||
84 | |||
85 | def get(self, path): |
||
86 | self.action_route() |
||
87 | |||
88 | def post(self, path): |
||
89 | self.action_route() |
||
90 | |||
91 | def prepare_filtered_plugins(self, request_dict): |
||
92 | """ |
||
93 | Returns a object of records filtered and sorted |
||
94 | according to the provided request. |
||
95 | |||
96 | :param request_dict: |
||
97 | :return: |
||
98 | """ |
||
99 | |||
100 | # Generate filters for query |
||
101 | start = request_dict.get('start') |
||
102 | length = request_dict.get('length') |
||
103 | |||
104 | search = request_dict.get('search') |
||
105 | search_value = search.get("value") |
||
106 | |||
107 | # Force sort order always by ID desc |
||
108 | order = [ |
||
109 | { |
||
110 | "column": 'name', |
||
111 | "dir": 'asc', |
||
112 | } |
||
113 | ] |
||
114 | |||
115 | # Fetch Plugins |
||
116 | plugins = PluginsHandler() |
||
117 | # Get total count |
||
118 | records_total_count = plugins.get_total_plugin_list_count() |
||
119 | # Get quantity after filters (without pagination) |
||
120 | records_filtered_count = plugins.get_plugin_list_filtered_and_sorted(order=order, start=0, length=0, |
||
121 | search_value=search_value).count() |
||
122 | # Get filtered/sorted results |
||
123 | plugin_results = plugins.get_plugin_list_filtered_and_sorted(order=order, start=start, length=length, |
||
124 | search_value=search_value) |
||
125 | |||
126 | # Build return data |
||
127 | return_data = { |
||
128 | "draw": request_dict.get('draw'), |
||
129 | "recordsTotal": records_total_count, |
||
130 | "recordsFiltered": records_filtered_count, |
||
131 | "successCount": 0, |
||
132 | "failedCount": 0, |
||
133 | "data": [] |
||
134 | } |
||
135 | |||
136 | # Iterate over plugins and append them to the plugin data |
||
137 | for plugin_result in plugin_results: |
||
138 | # Set plugin status |
||
139 | plugin_status = { |
||
140 | "enabled": plugin_result.get('enabled'), |
||
141 | "update_available": plugin_result.get('update_available'), |
||
142 | } |
||
143 | # Set params as required in template |
||
144 | item = { |
||
145 | 'id': plugin_result.get('id'), |
||
146 | 'plugin_id': plugin_result.get('plugin_id'), |
||
147 | 'icon': plugin_result.get('icon'), |
||
148 | 'name': plugin_result.get('name'), |
||
149 | 'description': plugin_result.get('description'), |
||
150 | 'tags': plugin_result.get('tags'), |
||
151 | 'author': plugin_result.get('author'), |
||
152 | 'version': plugin_result.get('version'), |
||
153 | 'status': plugin_status, |
||
154 | 'selected': False, |
||
155 | } |
||
156 | return_data["data"].append(item) |
||
157 | |||
158 | # Return results |
||
159 | return return_data |
||
160 | |||
161 | def update_repo_list(self, *args, **kwargs): |
||
162 | repos_list = self.get_argument('repos_list') |
||
163 | |||
164 | if repos_list: |
||
165 | repos_list = repos_list.splitlines() |
||
166 | |||
167 | try: |
||
168 | plugins = PluginsHandler() |
||
169 | plugins.set_plugin_repos(repos_list) |
||
170 | except Exception as e: |
||
171 | tornado.log.app_log.exception("Exception in updating repo list - {}".format(str(e)), exc_info=True) |
||
172 | |||
173 | self.get_repo_list() |
||
174 | |||
175 | def get_repo_list(self): |
||
176 | try: |
||
177 | plugins = PluginsHandler() |
||
178 | # Fetch the data again from the database |
||
179 | current_repos = plugins.get_plugin_repos() |
||
180 | |||
181 | # Remove the default plugin repo from the list |
||
182 | return_repos = [] |
||
183 | default_repo = plugins.get_default_repo() |
||
184 | for repo in current_repos: |
||
185 | if not repo.get("path").startswith(default_repo): |
||
186 | return_repos.append(repo) |
||
187 | |||
188 | # Return success |
||
189 | self.write(json.dumps({"success": True, "repos": return_repos})) |
||
190 | except Exception as e: |
||
191 | tornado.log.app_log.exception("Exception in fetching the current repo list - {}".format(str(e)), exc_info=True) |
||
192 | |||
193 | # Return failure |
||
194 | self.write(json.dumps({"success": False})) |
||
195 | |||
196 | def update_repos(self, *args, **kwargs): |
||
197 | plugins = PluginsHandler() |
||
198 | if plugins.update_plugin_repos(): |
||
199 | # Return success |
||
200 | self.write(json.dumps({"success": True})) |
||
201 | else: |
||
202 | # Return failure |
||
203 | self.write(json.dumps({"success": False})) |
||
204 | |||
205 | def get_plugin_list(self, *args, **kwargs): |
||
206 | plugins = PluginsHandler() |
||
207 | # Fetch a list of plugin data cached locally |
||
208 | plugin_list = plugins.get_installable_plugins_list() |
||
209 | self.write(json.dumps({"success": True, "plugins": plugin_list})) |
||
210 | |||
211 | def install_plugin_by_id(self, *args, **kwargs): |
||
212 | plugin_id = self.get_argument('plugin_id') |
||
213 | |||
214 | # Fetch a list of plugin data cached locally |
||
215 | plugins = PluginsHandler() |
||
216 | success = plugins.install_plugin_by_id(plugin_id) |
||
217 | |||
218 | if success: |
||
219 | # Return success |
||
220 | self.write(json.dumps({"success": True})) |
||
221 | else: |
||
222 | # Return failure |
||
223 | self.write(json.dumps({"success": False})) |
||
224 | |||
225 | def __get_plugin_changelog(self, plugin_id): |
||
226 | """ |
||
227 | Given a plugin ID , return a list of lines read from the plugin's changelog |
||
228 | |||
229 | :param plugin_id: |
||
230 | :return: |
||
231 | """ |
||
232 | # Fetch plugin changelog |
||
233 | plugin_executor = PluginExecutor() |
||
234 | return plugin_executor.get_plugin_changelog(plugin_id) |
||
235 | |||
236 | def __get_plugin_long_description(self, plugin_id): |
||
237 | """ |
||
238 | Given a plugin ID , return a list of lines read from the plugin's changelog |
||
239 | |||
240 | :param plugin_id: |
||
241 | :return: |
||
242 | """ |
||
243 | # Fetch plugin changelog |
||
244 | plugin_executor = PluginExecutor() |
||
245 | return plugin_executor.get_plugin_long_description(plugin_id) |