1 | |
---|
2 | import os |
---|
3 | import json |
---|
4 | import codecs |
---|
5 | import shutil |
---|
6 | import xmlrpclib as n4dclient |
---|
7 | import ssl |
---|
8 | import zipfile |
---|
9 | |
---|
10 | |
---|
11 | class BellSchedulerManager(object): |
---|
12 | |
---|
13 | def __init__(self): |
---|
14 | |
---|
15 | self.config_dir=os.path.expanduser("/etc/bellScheduler/") |
---|
16 | self.config_file=self.config_dir+"bell_list" |
---|
17 | self.cron_dir="/etc/scheduler/tasks.d/" |
---|
18 | self.cron_file=os.path.join(self.cron_dir,"BellScheduler") |
---|
19 | |
---|
20 | self.images_folder="/usr/local/share/bellScheduler/images" |
---|
21 | self.sounds_folder="/usr/local/share/bellScheduler/sounds" |
---|
22 | self.media_files_folder="/usr/local/share/bellScheduler/" |
---|
23 | |
---|
24 | |
---|
25 | server='localhost' |
---|
26 | context=ssl._create_unverified_context() |
---|
27 | self.n4d = n4dclient.ServerProxy("https://"+server+":9779",context=context,allow_none=True) |
---|
28 | |
---|
29 | self._get_n4d_key() |
---|
30 | |
---|
31 | |
---|
32 | #def __init__ |
---|
33 | |
---|
34 | |
---|
35 | def _get_n4d_key(self): |
---|
36 | |
---|
37 | self.n4dkey='' |
---|
38 | with open('/etc/n4d/key') as file_data: |
---|
39 | self.n4dkey = file_data.readlines()[0].strip() |
---|
40 | |
---|
41 | #def _get_n4d_key |
---|
42 | |
---|
43 | def _create_conf(self): |
---|
44 | |
---|
45 | if not os.path.exists(self.config_dir): |
---|
46 | os.makedirs(self.config_dir) |
---|
47 | |
---|
48 | if not os.path.exists(self.images_folder): |
---|
49 | os.makedirs(self.images_folder) |
---|
50 | |
---|
51 | if not os.path.exists(self.sounds_folder): |
---|
52 | os.makedirs(self.sounds_folder) |
---|
53 | |
---|
54 | var={} |
---|
55 | with codecs.open(self.config_file,'w',encoding="utf-8") as f: |
---|
56 | json.dump(var,f,ensure_ascii=False) |
---|
57 | f.close() |
---|
58 | |
---|
59 | return {"status":True,"msg":"Configuration file created successfuly"} |
---|
60 | |
---|
61 | #def create_conf |
---|
62 | |
---|
63 | |
---|
64 | def read_conf(self): |
---|
65 | |
---|
66 | if not os.path.exists(self.config_file): |
---|
67 | self._create_conf() |
---|
68 | |
---|
69 | f=open(self.config_file) |
---|
70 | |
---|
71 | try: |
---|
72 | self.bells_config=json.load(f) |
---|
73 | except Exception as e: |
---|
74 | |
---|
75 | self.bells_config={} |
---|
76 | return {"status":False,"msg":"Unabled to read configuration file :" +str(e),"code":25,"data":self.bells_config} |
---|
77 | |
---|
78 | |
---|
79 | f.close() |
---|
80 | |
---|
81 | return {"status":True,"msg":"Configuration file readed successfuly","code":26,"data":self.bells_config} |
---|
82 | |
---|
83 | #def read_conf |
---|
84 | |
---|
85 | def _get_tasks_from_cron(self): |
---|
86 | |
---|
87 | cron_tasks={} |
---|
88 | tmp_tasks={} |
---|
89 | tasks=self.n4d.get_local_tasks(self.n4dkey,'SchedulerServer') |
---|
90 | |
---|
91 | if tasks["status"]: |
---|
92 | |
---|
93 | for item in tasks["data"]: |
---|
94 | if item=="BellScheduler": |
---|
95 | tmp_tasks=tasks["data"][item] |
---|
96 | |
---|
97 | if len(tmp_tasks)>0: |
---|
98 | for item in tmp_tasks: |
---|
99 | key=str(tmp_tasks[item]["BellId"]) |
---|
100 | cron_tasks[key]={} |
---|
101 | cron_tasks[key]["CronId"]=item |
---|
102 | |
---|
103 | return cron_tasks |
---|
104 | |
---|
105 | #def _get_tasks_from_cron |
---|
106 | |
---|
107 | |
---|
108 | def sync_with_cron(self): |
---|
109 | |
---|
110 | bell_tasks=self.read_conf()["data"] |
---|
111 | keys_cron=self._get_tasks_from_cron().keys() |
---|
112 | changes=0 |
---|
113 | |
---|
114 | if len(keys_cron)>0: |
---|
115 | for item in bell_tasks: |
---|
116 | if item in keys_cron: |
---|
117 | if bell_tasks[item]["active"]: |
---|
118 | pass |
---|
119 | else: |
---|
120 | changes+=1 |
---|
121 | bell_tasks[item]["active"]=True |
---|
122 | else: |
---|
123 | if bell_tasks[item]["active"]: |
---|
124 | changes+=1 |
---|
125 | bell_tasks[item]["active"]=False |
---|
126 | else: |
---|
127 | pass |
---|
128 | else: |
---|
129 | for item in bell_tasks: |
---|
130 | if bell_tasks[item]["active"]: |
---|
131 | changes+=1 |
---|
132 | bell_tasks[item]["active"]=False |
---|
133 | |
---|
134 | if changes>0: |
---|
135 | self._write_conf(bell_tasks) |
---|
136 | |
---|
137 | return {"status":True,"msg":"Sync with cron sucessfully","data":bell_tasks} |
---|
138 | |
---|
139 | #def sync_with_cron |
---|
140 | |
---|
141 | def _write_conf(self,info): |
---|
142 | |
---|
143 | self.bells_config=info |
---|
144 | |
---|
145 | with codecs.open(self.config_file,'w',encoding="utf-8") as f: |
---|
146 | json.dump(info,f,ensure_ascii=False) |
---|
147 | f.close() |
---|
148 | |
---|
149 | return {"status":True,"msg":"Bell list saved successfuly"} |
---|
150 | |
---|
151 | |
---|
152 | #def _write_conf |
---|
153 | |
---|
154 | def save_changes(self,info,last_change,action): |
---|
155 | |
---|
156 | turn_on=False |
---|
157 | if action !="remove": |
---|
158 | if info[last_change]["active"]: |
---|
159 | turn_on=True |
---|
160 | tasks_for_cron=self._format_to_cron(info,last_change,action) |
---|
161 | result=self.n4d.write_tasks(self.n4dkey,'SchedulerServer','local',tasks_for_cron) |
---|
162 | |
---|
163 | else: |
---|
164 | result=self._delete_from_cron(last_change) |
---|
165 | else: |
---|
166 | result=self._delete_from_cron(last_change) |
---|
167 | |
---|
168 | |
---|
169 | if result['status']: |
---|
170 | return self._write_conf(info) |
---|
171 | else: |
---|
172 | if action=="edit": |
---|
173 | return {"status":False,"action":action,"msg":result['data'],"code":19} |
---|
174 | elif action=="add": |
---|
175 | return {"status":False,"action":action,"msg":result['data'],"code":20} |
---|
176 | elif action=="remove": |
---|
177 | return {"status":False,"action":action,"msg":result['data'],"code":21} |
---|
178 | elif action=="active": |
---|
179 | if turn_on: |
---|
180 | return {"status":False,"action":action,"msg":result['data'],"code":22} |
---|
181 | else: |
---|
182 | return {"status":False,"action":action,"msg":result['data'],"code":23} |
---|
183 | |
---|
184 | #def save_changes |
---|
185 | |
---|
186 | def _get_cron_id(self,last_change): |
---|
187 | |
---|
188 | cron_tasks=self._get_tasks_from_cron() |
---|
189 | if len(cron_tasks)>0: |
---|
190 | if last_change in cron_tasks.keys(): |
---|
191 | return {"status":True, "id":cron_tasks[last_change]} |
---|
192 | |
---|
193 | return {"status":False,"id":{"CronId":0}} |
---|
194 | |
---|
195 | # def _get_cron_id |
---|
196 | |
---|
197 | def _delete_from_cron(self,last_change): |
---|
198 | |
---|
199 | id_to_remove=self._get_cron_id(last_change) |
---|
200 | cron_id=id_to_remove["id"]["CronId"] |
---|
201 | delete={"status":True,"data":"0"} |
---|
202 | |
---|
203 | if id_to_remove["status"]: |
---|
204 | delete=self.n4d.remove_task(self.n4dkey,'SchedulerServer','local','BellScheduler',cron_id,'cmd') |
---|
205 | |
---|
206 | return delete |
---|
207 | |
---|
208 | #def _delete_from_cron |
---|
209 | |
---|
210 | def _format_to_cron(self,info,item,action): |
---|
211 | |
---|
212 | info_to_cron={} |
---|
213 | |
---|
214 | |
---|
215 | if action=="edit" or action=="active": |
---|
216 | cron_tasks=self._get_tasks_from_cron() |
---|
217 | try: |
---|
218 | key=cron_tasks[item]["CronId"] |
---|
219 | except: |
---|
220 | key="0" |
---|
221 | else: |
---|
222 | key="0" |
---|
223 | |
---|
224 | info_to_cron["BellScheduler"]={} |
---|
225 | info_to_cron["BellScheduler"][key]={} |
---|
226 | info_to_cron["BellScheduler"][key]["name"]=info[item]["name"] |
---|
227 | info_to_cron["BellScheduler"][key]["dom"]="*" |
---|
228 | info_to_cron["BellScheduler"][key]["mon"]="*" |
---|
229 | info_to_cron["BellScheduler"][key]["h"]=str(info[item]["hour"]) |
---|
230 | info_to_cron["BellScheduler"][key]["m"]=str(info[item]["minute"]) |
---|
231 | info_to_cron["BellScheduler"][key]["protected"]=True |
---|
232 | |
---|
233 | weekdays=info[item]["weekdays"] |
---|
234 | days="" |
---|
235 | if weekdays["0"]: |
---|
236 | days=days+"1," |
---|
237 | if weekdays["1"]: |
---|
238 | days=days+"2," |
---|
239 | if weekdays["2"]: |
---|
240 | days=days+"3," |
---|
241 | if weekdays["3"]: |
---|
242 | days=days+"4," |
---|
243 | if weekdays["4"]: |
---|
244 | days=days+"5," |
---|
245 | |
---|
246 | if days!="": |
---|
247 | days=days[:-1] |
---|
248 | |
---|
249 | else: |
---|
250 | days='*' |
---|
251 | |
---|
252 | info_to_cron["BellScheduler"][key]["dow"]=days |
---|
253 | info_to_cron["BellScheduler"][key]["BellId"]=item |
---|
254 | |
---|
255 | |
---|
256 | sound_option=info[item]["sound"]["option"] |
---|
257 | sound_path=info[item]["sound"]["path"] |
---|
258 | duration=info[item]["play"]["duration"] |
---|
259 | |
---|
260 | |
---|
261 | if duration>0: |
---|
262 | fade_out=int(duration)-2 |
---|
263 | fade_effects='-af aformat=channel_layouts=mono -af afade=in:st=1:d=3,afade=out:st='+str(fade_out)+":d=2" |
---|
264 | cmd="ffplay -nodisp -autoexit -t "+str(duration) |
---|
265 | else: |
---|
266 | fade_effects='-af aformat=channel_layouts=mono ' |
---|
267 | cmd="ffplay -nodisp -autoexit " |
---|
268 | |
---|
269 | if sound_option !="url": |
---|
270 | if sound_option =="file": |
---|
271 | cmd=cmd+" '"+sound_path+"' "+fade_effects |
---|
272 | else: |
---|
273 | random_file="$(find"+ " '"+sound_path+"' -type f -print0 | xargs -0 file -i | awk -F ':' '{ if ($2 ~ /audio/ || $2 ~ /video/ ) print $1 }'| shuf -n 1)" |
---|
274 | cmd=cmd+' "'+ random_file + '" '+fade_effects |
---|
275 | #cmd=cmd+" $(find"+ " '"+sound_path+"' -type f | shuf -n 1) "+fade_effects |
---|
276 | else: |
---|
277 | cmd=cmd+ " $(youtube-dl -g "+sound_path+ " | sed -n 2p) "+fade_effects |
---|
278 | |
---|
279 | info_to_cron["BellScheduler"][key]["cmd"]=cmd |
---|
280 | |
---|
281 | return info_to_cron |
---|
282 | |
---|
283 | #def _format_to_cron |
---|
284 | |
---|
285 | def copy_media_files(self,image,sound): |
---|
286 | |
---|
287 | |
---|
288 | if image!="": |
---|
289 | image_file=os.path.basename(image) |
---|
290 | image_dest=os.path.join(self.images_folder,image_file) |
---|
291 | |
---|
292 | if sound!="": |
---|
293 | sound_file=os.path.basename(sound) |
---|
294 | sound_dest=os.path.join(self.sounds_folder,sound_file) |
---|
295 | |
---|
296 | try: |
---|
297 | if image!="": |
---|
298 | if not os.path.exists(image_dest): |
---|
299 | shutil.copy2(image,image_dest) |
---|
300 | |
---|
301 | if sound!="": |
---|
302 | if not os.path.exists(sound_dest): |
---|
303 | shutil.copy2(sound,sound_dest) |
---|
304 | |
---|
305 | result={"status":True,"msg":"Files copied successfully"} |
---|
306 | except Exception as e: |
---|
307 | result={"status":False,"msg":str(e),"code":24} |
---|
308 | |
---|
309 | return result |
---|
310 | |
---|
311 | #def copy_media_files |
---|
312 | |
---|
313 | def export_bells_conf(self,dest_file,user,arg=None): |
---|
314 | |
---|
315 | tmp_export=tempfile.mkdtemp("_bell_export") |
---|
316 | |
---|
317 | try: |
---|
318 | shutil.copy2(self.config_file,os.path.join(tmp_export,os.path.basename(self.config_file))) |
---|
319 | if os.path.exists(self.cron_file): |
---|
320 | shutil.copy2(self.cron_file,os.path.join(tmp_export,os.path.basename(self.cron_file))) |
---|
321 | if os.path.exists(self.media_files_folder): |
---|
322 | shutil.copytree(self.media_files_folder,os.path.join(tmp_export,"media")) |
---|
323 | |
---|
324 | shutil.make_archive(dest_file, 'zip', tmp_export) |
---|
325 | if arg!=True: |
---|
326 | shutil.rmtree(tmp_export) |
---|
327 | |
---|
328 | cmd='chown -R '+user+':'+user +" " + dest_file+'.zip' |
---|
329 | os.system(cmd) |
---|
330 | result={"status":True,"msg":"Bells exported successfullly","code":11} |
---|
331 | |
---|
332 | except Exception as e: |
---|
333 | result={"status":False,"msg":str(e),"code":12} |
---|
334 | |
---|
335 | return result |
---|
336 | |
---|
337 | #def export_bells_conf |
---|
338 | |
---|
339 | def import_bells_conf(self,orig_file,user,backup): |
---|
340 | |
---|
341 | backup_file=["",""] |
---|
342 | unzip_tmp=tempfile.mkdtemp("_import_bells") |
---|
343 | result={"status":True} |
---|
344 | |
---|
345 | if backup: |
---|
346 | backup_file=tempfile.mkstemp("_bells_backup") |
---|
347 | result=self.export_bells_conf(backup_file[1],user,True) |
---|
348 | |
---|
349 | try: |
---|
350 | if result['status']: |
---|
351 | tmp_zip=zipfile.ZipFile(orig_file) |
---|
352 | tmp_zip.extractall(unzip_tmp) |
---|
353 | tmp_zip.close |
---|
354 | |
---|
355 | config_file=os.path.join(unzip_tmp,os.path.basename(self.config_file)) |
---|
356 | if os.path.exists(config_file): |
---|
357 | try: |
---|
358 | f=open(config_file) |
---|
359 | read=json.load(f) |
---|
360 | shutil.copy2(config_file,self.config_dir) |
---|
361 | f.close() |
---|
362 | except Exception as e: |
---|
363 | result={"status":False,"msg":str(e),"code":9,"data":backup_file[1]} |
---|
364 | return result |
---|
365 | |
---|
366 | cron_file=os.path.join(unzip_tmp,os.path.basename(self.cron_file)) |
---|
367 | if os.path.exists(cron_file): |
---|
368 | try: |
---|
369 | f=open(cron_file) |
---|
370 | read=json.load(f) |
---|
371 | shutil.copy2(cron_file,self.cron_dir) |
---|
372 | f.close() |
---|
373 | except Exception as e: |
---|
374 | result={"status":False,"msg":str(e),"code":9,"data":backup_file[1]} |
---|
375 | return result |
---|
376 | |
---|
377 | if os.path.exists(self.images_folder): |
---|
378 | shutil.rmtree(self.images_folder) |
---|
379 | shutil.copytree(os.path.join(unzip_tmp,"media/images"),self.images_folder) |
---|
380 | |
---|
381 | if os.path.exists(self.sounds_folder): |
---|
382 | shutil.rmtree(self.sounds_folder) |
---|
383 | shutil.copytree(os.path.join(unzip_tmp,"media/sounds"),self.sounds_folder) |
---|
384 | |
---|
385 | |
---|
386 | result={"status":True,"msg":"Bells imported successfullly","code":10,"data":backup_file[1]} |
---|
387 | |
---|
388 | except Exception as e: |
---|
389 | result={"status":False,"msg":str(e),"code":9,"data":backup_file[1]} |
---|
390 | |
---|
391 | |
---|
392 | return result |
---|
393 | |
---|
394 | #def import_bells_conf |
---|