kapsikkum-unmanic – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3  
4 """
5 unmanic.history.py
6  
7 Written by: Josh.5 <jsunnex@gmail.com>
8 Date: 23 Jun 2019, (10:42 AM)
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  
33 import os
34 import json
35 from operator import attrgetter
36  
37 from unmanic import config
38 from unmanic.libs import common, unlogger
39 from unmanic.libs.unmodels import CompletedTasks, CompletedTasksCommandLogs
40  
41 try:
42 from json.decoder import JSONDecodeError
43 except ImportError:
44 JSONDecodeError = ValueError
45  
46  
47 class History(object):
48 """
49 History
50  
51 Record statistical data for historical jobs
52 """
53  
54 def __init__(self):
55 self.name = 'History'
56 self.settings = config.Config()
57  
58 def _log(self, message, message2='', level="info"):
59 unmanic_logging = unlogger.UnmanicLogger.__call__()
60 logger = unmanic_logging.get_logger(self.name)
61 if logger:
62 message = common.format_message(message, message2)
63 getattr(logger, level)(message)
64 else:
65 print("Unmanic.{} - ERROR!!! Failed to find logger".format(self.name))
66  
67 def get_historic_task_list(self, limit=None):
68 """
69 Read all historic tasks entries
70  
71 :return:
72 """
73 try:
74 # Fetch a single row (get() will raise DoesNotExist exception if no results are found)
75 if limit:
76 historic_tasks = CompletedTasks.select().order_by(CompletedTasks.id.desc()).limit(limit)
77 else:
78 historic_tasks = CompletedTasks.select().order_by(CompletedTasks.id.desc())
79 except CompletedTasks.DoesNotExist:
80 # No historic entries exist yet
81 self._log("No historic tasks exist yet.", level="warning")
82 historic_tasks = []
83  
84 return historic_tasks.dicts()
85  
86 def get_total_historic_task_list_count(self):
87 query = CompletedTasks.select().order_by(CompletedTasks.id.desc())
88 return query.count()
89  
90 def get_historic_task_list_filtered_and_sorted(self, order=None, start=0, length=None, search_value=None, id_list=None,
91 task_success=None, after_time=None, before_time=None):
92 try:
93 query = (CompletedTasks.select())
94  
95 if id_list:
96 query = query.where(CompletedTasks.id.in_(id_list))
97  
98 if search_value:
99 query = query.where(CompletedTasks.task_label.contains(search_value))
100  
101 if task_success is not None:
102 query = query.where(CompletedTasks.task_success.in_([task_success]))
103  
104 if after_time is not None:
105 query = query.where(CompletedTasks.finish_time >= after_time)
106  
107 if before_time is not None:
108 query = query.where(CompletedTasks.finish_time <= before_time)
109  
110 # Get order by
111 if order:
112 if order.get("dir") == "asc":
113 order_by = attrgetter(order.get("column"))(CompletedTasks).asc()
114 else:
115 order_by = attrgetter(order.get("column"))(CompletedTasks).desc()
116  
117 query = query.order_by(order_by)
118  
119 if length:
120 query = query.limit(length).offset(start)
121  
122 except CompletedTasks.DoesNotExist:
123 # No historic entries exist yet
124 self._log("No historic tasks exist yet.", level="warning")
125 query = []
126  
127 return query.dicts()
128  
129 def get_current_path_of_historic_tasks_by_id(self, id_list=None):
130 """
131 Returns a list of CompletedTasks filtered by id_list and joined with the current absolute path of that file.
132 For failures this will be the the source path
133 For success, this will be the destination path
134  
135 :param id_list:
136 :return:
137 """
138 """
139 SELECT
140 t1.*,
141 t2.type,
142 t2.abspath
143 FROM completedtasks AS "t1"
144 WHERE t1.id IN ( %s)
145 """
146 query = (
147 CompletedTasks.select(CompletedTasks.id, CompletedTasks.task_label, CompletedTasks.task_success,
148 CompletedTasks.abspath)
149 )
150  
151 if id_list:
152 query = query.where(CompletedTasks.id.in_(id_list))
153  
154 return query.dicts()
155  
156 def get_historic_tasks_list_with_source_probe(self, order=None, start=0, length=None, search_value=None, id_list=None,
157 task_success=None, abspath=None):
158 """
159 Return a list of matching historic tasks with their source file's ffmpeg probe.
160  
161 :param order:
162 :param start:
163 :param length:
164 :param search_value:
165 :param id_list:
166 :param task_success:
167 :param abspath:
168 :return:
169 """
170 query = (
171 CompletedTasks.select(CompletedTasks.id, CompletedTasks.task_label, CompletedTasks.task_success,
172 CompletedTasks.abspath))
173  
174 if id_list:
175 query = query.where(CompletedTasks.id.in_(id_list))
176  
177 if search_value:
178 query = query.where(CompletedTasks.task_label.contains(search_value))
179  
180 if task_success is not None:
181 query = query.where(CompletedTasks.task_success.in_([task_success]))
182  
183 if abspath:
184 query = query.where(CompletedTasks.abspath.in_([abspath]))
185  
186 return query.dicts()
187  
188 def get_historic_task_data_dictionary(self, task_id):
189 """
190 Read all data for a task and return a dictionary of that data
191  
192 :return:
193 """
194 # Get historic task matching the id
195 try:
196 # Fetch the historic task (get() will raise DoesNotExist exception if no results are found)
197 historic_tasks = CompletedTasks.get_by_id(task_id)
198 except CompletedTasks.DoesNotExist:
199 self._log("Failed to retrieve historic task from database for id {}.".format(task_id), level="exception")
200 return False
201 # Get all saved data for this task and create dictionary of task data
202 historic_task = historic_tasks.model_to_dict()
203 # Return task data dictionary
204 return historic_task
205  
206 def delete_historic_tasks_recursively(self, id_list=None):
207 """
208 Deletes a given list of historic tasks based on their IDs
209  
210 :param id_list:
211 :return:
212 """
213 # Prevent running if no list of IDs was given
214 if not id_list:
215 return False
216  
217 try:
218 query = (CompletedTasks.select())
219  
220 if id_list:
221 query = query.where(CompletedTasks.id.in_(id_list))
222  
223 for historic_task_id in query:
224 try:
225 historic_task_id.delete_instance(recursive=True)
226 except Exception as e:
227 # Catch delete exceptions
228 self._log("An error occurred while deleting historic task ID: {}.".format(historic_task_id), str(e),
229 level="exception")
230 return False
231  
232 return True
233  
234 except CompletedTasks.DoesNotExist:
235 # No historic entries exist yet
236 self._log("No historic tasks exist yet.", level="warning")
237  
238 def save_task_history(self, task_data):
239 """
240 Record a task's data and state to the database.
241  
242 :param task_data:
243 :return:
244 """
245 try:
246 # Create the new historical task entry
247 new_historic_task = self.create_historic_task_entry(task_data)
248 # Create an entry of the data from the source ffprobe
249 self.create_historic_task_ffmpeg_log_entry(new_historic_task, task_data.get('log', ''))
250 except Exception as error:
251 self._log("Failed to save historic task entry to database.", str(error), level="exception")
252 return False
253 return True
254  
255 @staticmethod
256 def create_historic_task_ffmpeg_log_entry(historic_task, log):
257 """
258 Create an entry of the stdout log from the ffmpeg command
259  
260 :param historic_task:
261 :param log:
262 :return:
263 """
264 CompletedTasksCommandLogs.create(
265 completedtask_id=historic_task,
266 dump=log
267 )
268  
269 def create_historic_task_entry(self, task_data):
270 """
271 Create a historic task entry
272  
273 Required task_data params:
274 - task_label
275 - task_success
276 - start_time
277 - finish_time
278 - processed_by_worker
279  
280 :param task_data:
281 :return:
282 """
283 if not task_data:
284 self._log('Task data param empty', json.dumps(task_data), level="debug")
285 raise Exception('Task data param empty. This should not happen - Something has gone really wrong.')
286  
287 new_historic_task = CompletedTasks.create(task_label=task_data['task_label'],
288 abspath=task_data['abspath'],
289 task_success=task_data['task_success'],
290 start_time=task_data['start_time'],
291 finish_time=task_data['finish_time'],
292 processed_by_worker=task_data['processed_by_worker'])
293 return new_historic_task