-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathdefault.py
816 lines (740 loc) · 31.9 KB
/
default.py
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
#!/usr/bin/python
# -*- coding: utf-8 -*-
# script.video.cleaner
# Written by black_eagle and BatterPudding
#
# Version 27b/7 - Batter Pudding Fix added
# Version 27b/9 - Batter Pudding tweaks the debug logging
# Version 28b/1 - New GUI, several code fixes
# Version 28b/2 - Fix the WINDOWS KODI temp path
# Version 28b/3 - Tidy up temp path code, remove some unused code
# Version 29b/1 - Add ability to rename paths inside the db
# Version 29b/2 - Fix incorrectly altered SQL
# Version 30b/1 - UI improvements - only allow one instance
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
import datetime
import json as jsoninterface
import sqlite3
import xml.etree.ElementTree as ET
import mysql.connector
import xbmc
import xbmcaddon
import xbmcgui
import xbmcvfs
# database versions to scan for
MIN_VIDEODB_VERSION = 35
MAX_VIDEODB_VERSION = 116 # i.e. Leia, aka Kodi 18
ACTION_PREVIOUS_MENU = 10
ACTION_SELECT_ITEM = 7
ACTION_NAV_BACK = 92
ACTION_MOUSE_LEFT_CLICK = 100
flag = 0
WINDOW = xbmcgui.Window(10000)
class MyClass(xbmcgui.WindowXMLDialog):
def __init__( self, *args, **kwargs ): pass
def onInit( self ):
self.container = self.getControl(6)
self.container2 = self.getControl(8)
self.container3 = self.getControl(10)
self.listitems = []
self.excludesitems = []
self.addonsettings = []
# List paths from sources.xml
if not specificpath and not replacepath:
self.display_list = display_list
for i in range(len(self.display_list)):
self.listitems.append('[COLOR yellow]'+ self.display_list[i] + '[/COLOR]')
if no_sources:
self.listitems.append('[COLOR red][B]No sources are in use[/B][/COLOR]')
self.listitems.append('[COLOR red][B]All streaming paths will be removed[/B][/COLOR]')
if excluding:
self.listitems.append('')
self.listitems.append('[COLOR red][B]Paths from excludes.xml will be kept[/B][/COLOR]')
if replacepath:
self.listitems.append('[COLOR yellow]Replacing a path[/COLOR]')
self.listitems.append('[COLOR yellow]in your database[/COLOR]')
self.listitems.append('[COLOR yellow]Confirm details below[/COLOR]')
if specificpath:
self.listitems.append('[COLOR yellow]Removing a path[/COLOR]')
self.listitems.append('[COLOR yellow]in your database[/COLOR]')
self.listitems.append('[COLOR yellow]Confirm details below[/COLOR]')
self.container.addItems(self.listitems)
# List paths in excludes.xml (if it exists)
self.excludes_list = excludes_list
if excluding:
for i in range(len(self.excludes_list)):
self.excludesitems.append('[COLOR yellow]' + self.excludes_list[i]+ '[/COLOR]')
else:
self.excludesitems.append("Not Present")
self.container2.addItems(self.excludesitems)
# List the relevant addon settings
if is_pvr and (not specificpath and not replacepath):
self.addonsettings.append('Keep PVR information')
if bookmarks and (not specificpath and not replacepath):
self.addonsettings.append('Keep bookmark information')
if autoclean:
self.addonsettings.append('Auto call Clean Library')
if promptdelete:
self.addonsettings.append('Show summary window (This window !!)')
if autobackup == 'true' and not is_mysql:
self.addonsettings.append('Auto backing up local database')
if no_sources or specificpath or replacepath:
self.addonsettings.append('[COLOR red]Not[/COLOR] using info from sources.xml')
if specificpath:
self.addonsettings.append('[COLOR red]Cleaning a specific path[/COLOR]')
if replacepath:
self.addonsettings.append('[COLOR red]Replacing a path[/COLOR]')
if enable_logging:
self.addonsettings.append('Writing a logfile to Kodi TEMP directory')
if debugging:
debug_string = 'Debugging [COLOR red]enabled[/COLOR]'
else:
debug_string = 'Debugging [COLOR green]disabled[/COLOR]'
self.addonsettings.append(debug_string)
self.addonsettings.append('') #blank line
# Display the name of the database we are connected to
self.addonsettings.append('Database is - [COLOR green][B]%s[/B][/COLOR]' % our_dbname)
cursor.execute(our_select)
data_list = cursor.fetchall()
data_list_size = len(data_list)
if replacepath:
self.addonsettings.append('[COLOR red][B]There are %d paths to be changed[/B][/COLOR]' % data_list_size)
else:
self.addonsettings.append('[COLOR red][B]There are %d entries to be removed[/B][/COLOR]' % data_list_size)
self.container3.addItems(self.addonsettings)
# Show warning about backup if using MySQL
if is_mysql:
self.getControl(20).setLabel('WARNING - MySQL database [COLOR red][B]not[/B][/COLOR] backed up automatically, please do this [B]manually[/B]')
if specificpath:
self.getControl(20).setLabel('WARNING - Removing specific path [COLOR yellow]%s[/COLOR] ' % specific_path_to_remove)
if replacepath:
self.getControl(20).setLabel('WARNING - Renaming specific path from [COLOR yellow]%s[/COLOR] ' % old_path)
self.getControl(21).setLabel('TO [COLOR yellow]%s[/COLOR] ' % new_path)
def onAction(self, action):
global flag
dbglog('Got an action %s' % action.getId())
if ( action == ACTION_PREVIOUS_MENU ) or ( action == ACTION_NAV_BACK ):
self.close()
if (action == ACTION_SELECT_ITEM) or ( action == ACTION_MOUSE_LEFT_CLICK ):
try:
btn = self.getFocus()
btn_id = btn.getId()
except:
btn_id = None
if btn_id == 1:
dbglog('you pressed abort')
flag = 0
self.close()
elif btn_id == 2:
dbglog('you pressed clean')
flag = 1
self.close()
# Set some variables ###
addon = xbmcaddon.Addon()
addonname = addon.getAddonInfo('name')
addonversion = addon.getAddonInfo('version')
addonpath = addon.getAddonInfo('path').decode('utf-8')
advanced_file = xbmc.translatePath('special://profile/advancedsettings.xml').decode('utf-8')
sources_file = xbmc.translatePath('special://profile/sources.xml').decode('utf-8')
excludes_file = xbmc.translatePath('special://profile/addon_data/script.database.cleaner/excludes.xml').decode('utf-8')
db_path = xbmc.translatePath('special://database').decode('utf-8')
userdata_path = xbmc.translatePath('special://userdata').decode('utf-8')
bp_logfile_path = xbmc.translatePath('special://temp/bp-debuglog.log').decode('utf-8')
type_of_log =''
is_pvr = addon.getSetting('pvr')
autoclean = addon.getSetting('autoclean')
bookmarks = addon.getSetting('bookmark')
promptdelete = addon.getSetting('promptdelete')
source_file_path = addon.getSetting('sourcefilepath')
debugging = addon.getSetting('debugging')
no_sources = addon.getSetting('usesources')
autobackup = addon.getSetting('autobackup')
specificpath = addon.getSetting('specificpath')
backup_filename = addon.getSetting('backupname')
forcedbname = addon.getSetting('overridedb')
replacepath = addon.getSetting('replacepath')
enable_logging = addon.getSetting('logtolog')
if enable_logging == 'true':
enable_logging = True
type_of_log = addon.getSetting('typeoflog')
else:
enable_logging = False
if replacepath == 'true':
replacepath = True
else:
replacepath = False
old_path = addon.getSetting('oldpath')
new_path = addon.getSetting('newpath')
if forcedbname == 'true':
forcedbname = True
else:
forcedbname = False
forcedname = addon.getSetting('forceddbname')
if specificpath == 'true':
specificpath = True
else:
specificpath = False
specific_path_to_remove = addon.getSetting('spcpathstr')
display_list = []
excludes_list = []
renamepath_list = []
excluding = False
found = False
is_mysql = False
remote_file = False
cleaning = False
path_name = ''
the_path = ''
success = 0
our_source_list = ''
if debugging == 'true':
debugging = True
else:
debugging = False
def log(txt):
if isinstance(txt, str):
txt = txt.decode('utf-8')
message = u'%s: %s' % (addonname, txt)
xbmc.log(msg=message.encode('utf-8'), level=xbmc.LOGDEBUG)
def dbglog(txt):
if debugging:
log(txt)
def exit_on_error():
WINDOW.setProperty('database-cleaner-running', 'false')
exit(1)
def cleaner_log_file(our_select, cleaning):
cleaner_log = xbmc.translatePath('special://temp/database-cleaner.log').decode('utf-8')
old_cleaner_log = xbmc.translatePath('special://temp/database-cleaner.old.log').decode('utf-8')
old_log_contents =''
do_progress = False
if not enable_logging:
return
if type_of_log == '0':
dbglog('Writing to new log file')
if cleaning:
if xbmcvfs.exists(cleaner_log):
dbglog('database-cleaner.log exists - renaming to old.log')
xbmcvfs.delete(old_cleaner_log)
xbmcvfs.copy(cleaner_log, old_cleaner_log)
xbmcvfs.delete(cleaner_log)
else:
xbmcvfs.delete(cleaner_log)
else:
dbglog('Appending to existing log file')
if cleaning:
if xbmcvfs.exists(cleaner_log):
dbglog('database-cleaner.log exists - backing up to old.log')
xbmcvfs.delete(old_cleaner_log)
xbmcvfs.copy(cleaner_log, old_cleaner_log)
old_log= xbmcvfs.File(cleaner_log)
old_log_contents=old_log.read()
old_log.close()
now = datetime.datetime.now()
logfile=xbmcvfs.File(cleaner_log, 'w')
if old_log_contents:
logfile.write(old_log_contents)
date_long_format = xbmc.getRegion('datelong')
time_format = xbmc.getRegion('time')
date_long_format = date_long_format + ' '+time_format
logfile_header = 'Video Database Cleaner V' + addonversion+ ' - Running at ' +now.strftime(date_long_format) + '\n\n'
logfile.write(logfile_header)
cursor.execute(our_select)
counting = 0
my_data = cursor.fetchall()
listsize = len(my_data)
dbglog("Listsize is %d" % listsize)
logfile.write('There are %d paths in the database that meet your criteria\n\n' % listsize)
if listsize > 600:
do_progress = True
dialog = xbmcgui.DialogProgressBG()
dbglog('Creating progress dialog for logfile')
dialog.create('Getting required data. Please wait')
dialog.update(1)
if not cleaning and not replacepath:
logfile.write('The following file paths would be removed from your database')
logfile.write('\n\n')
elif cleaning and not replacepath:
logfile.write('The following paths were removed from the database')
logfile.write('\n\n')
elif not cleaning and replacepath:
logfile.write('The following paths will be changed in your database')
logfile.write('\n\n')
else:
logfile.write('The following paths were changed in your database')
logfile.write('\n\n')
if not specificpath and not replacepath:
for strPath in my_data:
counting +=1
mystring = u''.join(strPath) + '\n'
outdata = mystring.encode('utf-8')
if do_progress:
dialog.update(percent = int((counting / float(listsize)) * 100))
if cleaning:
dbglog('Removing %s' % strPath)
logfile.write(outdata)
elif specificpath and not replacepath:
dbglog('Removing specific path %s' % specific_path_to_remove)
for strPath in my_data:
counting +=1
mystring = u''.join(strPath) + '\n'
outdata = mystring.encode('utf-8')
if do_progress:
dialog.update(percent = int((counting / float(listsize)) * 100))
if cleaning:
dbglog('Removing unwanted path %s' % strPath)
logfile.write(outdata)
else:
for strPath in my_data:
counting +=1
mystring = u''.join(strPath) + '\n'
outdata = mystring.encode('utf-8')
if do_progress:
dialog.update(percent = int((counting / float(listsize)) * 100))
if cleaning:
dbglog('Changing path %s' % strPath)
logfile.write(outdata)
our_data = cursor
if counting == 0: # nothing to remove
logfile.write('No paths have been found to remove\n')
if do_progress:
dialog.close()
logfile.write('\n\n')
logfile.close()
#### Start Here !! ####
dbglog('script version %s started' % addonversion)
#if WINDOW.getProperty('database-cleaner-running') == 'true':
#log('Video Database Cleaner already running')
#exit(0)
#else:
#WINDOW.setProperty('database-cleaner-running', 'true')
xbmcgui.Dialog().notification(addonname, 'Starting Up', xbmcgui.NOTIFICATION_INFO, 2000)
xbmc.sleep(2000)
if xbmcvfs.exists(advanced_file):
dbglog('Found advancedsettings.xml')
found = True
if found:
msg = advanced_file.encode('utf-8')
dbglog('looking in advancedsettings for videodatabase info')
try:
advancedsettings = ET.parse(advanced_file)
except ET.ParseError:
dbglog('Error parsing advancedsettings.xml file')
xbmcgui.Dialog().ok(addonname, 'Error parsing advancedsettings.xml file[CR] Possibly a mal-formed comment or missing closing tag - script aborted')
exit_on_error()
root = advancedsettings.getroot()
try:
for videodb in root.findall('videodatabase'):
try:
our_host = videodb.find('host').text
except:
log('Unable to find MySQL host address')
try:
our_username = videodb.find('user').text
except:
log('Unable to determine MySQL username')
try:
our_password = videodb.find('pass').text
except:
log('Unable to determine MySQL password')
try:
our_port = videodb.find('port').text
except:
log('Unable to find MySQL port')
try:
our_dbname = videodb.find('name').text
except:
our_dbname = 'MyVideos'
dbglog('MySQL details - %s, %s, %s, %s' % (our_host, our_port, our_username, our_dbname))
is_mysql = True
except Exception as e:
e =str(e)
dbglog ('Error parsing advancedsettings file - %s' % e)
is_mysql = False
if not is_mysql:
our_dbname = 'MyVideos'
for num in range(MAX_VIDEODB_VERSION, MIN_VIDEODB_VERSION, -1):
testname = our_dbname + str(num)
our_test = db_path + testname + '.db'
dbglog('Checking for local database %s' % testname)
if xbmcvfs.exists(our_test):
break
if num != MIN_VIDEODB_VERSION:
our_dbname = testname
if our_dbname == 'MyVideos':
dbglog('No video database found - assuming MySQL database')
dbglog('Database name is %s' % our_dbname)
if is_pvr == 'true':
is_pvr = True
else:
is_pvr = False
if autoclean == 'true':
autoclean = True
else:
autoclean = False
if bookmarks == 'true':
bookmarks = True
else:
bookmarks = False
if promptdelete == 'true':
promptdelete = True
else:
promptdelete = False
if no_sources == 'true':
no_sources = False
else:
no_sources = True
dbglog('Settings for file cleaning are as follows')
if is_pvr:
dbglog('keeping PVR files')
if bookmarks:
dbglog('Keeping bookmarks')
if autoclean:
dbglog('autocleaning afterwards')
if promptdelete:
dbglog('Prompting before deletion')
if no_sources:
dbglog('Not using sources.xml')
if source_file_path != '':
sources_file = source_file_path
remote_file = True
dbglog('Remote sources.xml file path identified')
if xbmcvfs.exists(sources_file) and not remote_file:
try:
source_file = sources_file
tree = ET.parse(source_file)
root = tree.getroot()
dbglog('Got local sources.xml file')
except:
dbglog('Error parsing local sources.xml file')
xbmcgui.Dialog().ok(addonname, 'Error parsing local sources.xml file - script aborted')
exit_on_error()
elif xbmcvfs.exists(sources_file):
try:
f = xbmcvfs.File(sources_file)
source_file = f.read()
f.close()
root = ET.fromstring(source_file)
dbglog('Got remote sources.xml')
except:
dbglog('Error parsing remote sources.xml')
xbmcgui.Dialog().ok(addonname, 'Error parsing remote sources.xml file - script aborted')
exit_on_error()
else:
xbmcgui.Dialog().notification(addonname,
'Warning - no sources.xml file found - defaulting to cleaning streaming paths only',xbmcgui.NOTIFICATION_INFO,3000)
dbglog('No local sources.xml, no remote sources file set in settings')
xbmc.sleep(3000)
no_sources = True
my_command = ''
first_time = True
if forcedbname:
log('Forcing video db version to %s' % forcedname)
# Open database connection
if is_mysql and not forcedbname:
if our_dbname == '': # no db name in advancedsettings
our_dbname = 'MyVideos'
for num in range(MAX_VIDEODB_VERSION, MIN_VIDEODB_VERSION, -1):
testname = our_dbname + str(num)
try:
dbglog('Attempting MySQL connection to %s' % testname)
db = mysql.connector.connect(user=our_username,
database=testname, password=our_password,
host=our_host)
if db.is_connected():
our_dbname = testname
dbglog('Connected to MySQL database %s' % our_dbname)
break
except:
pass
else: # already got db name from ad settings
for num in range(MAX_VIDEODB_VERSION, MIN_VIDEODB_VERSION, -1):
testname = our_dbname + str(num)
try:
dbglog('Attempting MySQL connection to %s' % testname)
db = mysql.connector.connect(user=our_username, database=testname, password=our_password, host=our_host, port=our_port)
if db.is_connected():
our_dbname = testname
dbglog('Connected to MySQL database %s' % our_dbname)
break
except:
pass
if not db.is_connected():
xbmcgui.Dialog().ok(addonname, "Couldn't connect to MySQL database", s)
log("Error - couldn't connect to MySQL database - %s " % s)
exit_on_error()
elif is_mysql and forcedbname:
try:
db = mysql.connector.connect(user=our_username, database=forcedname, password=our_password, host=our_host, port=our_port)
if db.is_connected():
our_dbname = forcedname
dbglog('Connected to forced MySQL database %s' % forcedname)
except:
log('Error connecting to forced database - %s' % forcedname)
exit_on_error()
elif not is_mysql and not forcedbname:
try:
my_db_connector = db_path + our_dbname + '.db'
db = sqlite3.connect(my_db_connector)
except Exception,e:
s = str(e)
xbmcgui.Dialog().ok(addonname, 'Error connecting to SQLite database', s)
log('Error connecting to SQLite database - %s' % s)
exit_on_error()
else:
testpath = db_path + forcedname + '.db'
if not xbmcvfs.exists(testpath):
log('Forced version of database does not exist')
xbmcgui.Dialog().ok(addonname,'Error - Forced version of database ( %s ) not found. Script will now exit' % forcedname)
exit_on_error()
try:
my_db_connector = db_path + forcedname + '.db'
db = sqlite3.connect(my_db_connector)
dbglog('Connected to forced video database')
except:
xbmcgui.Dialog().ok(addonname,'Error - Unable to connect to forced database %s. Script will now exit' % forcedname)
log('Unable to connect to forced database s%' % forcedname)
exit_on_error()
cursor = db.cursor()
if xbmcvfs.exists(excludes_file):
excludes_list =[]
excluding = True
exclude_command = ''
try:
tree = ET.parse(excludes_file)
er = tree.getroot()
for excludes in er.findall('exclude'):
to_exclude = excludes.text
excludes_list.append(to_exclude)
dbglog('Excluding plugin path - %s' % to_exclude)
exclude_command = exclude_command + " AND strPath NOT LIKE '" + to_exclude + "%'"
log('Parsed excludes.xml')
except:
log('Error parsing excludes.xml')
xbmcgui.Dialog().ok(addonname, 'Error parsing excludes.xml file - script aborted')
exit_on_error()
if not no_sources:
# start reading sources.xml and build SQL statements to exclude these sources from any cleaning
try:
display_list =[]
for video in root.findall('video'):
dbglog('Contents of sources.xml file')
for sources in video.findall('source'):
for path_name in sources.findall('name'):
the_path_name = path_name.text
for paths in sources.findall('path'):
the_path = paths.text.replace("'","''")
display_list.append(the_path)
dbglog('%s - %s' % (the_path_name, the_path))
if first_time:
first_time = False
my_command = "strPath NOT LIKE '" + the_path + "%'"
our_source_list = 'Keeping files in ' + the_path
else:
my_command = my_command + " AND strPath NOT LIKE '" + the_path + "%'"
our_source_list = our_source_list + ', ' + the_path
if path_name == '':
no_sources = True
dbglog('******* WARNING *******')
dbglog('local sources.xml specified in settings')
dbglog('But no sources found in sources.xml file')
dbglog('Defaulting to alternate method for cleaning')
except:
log('Error parsing sources.xml file')
xbmcgui.Dialog().ok(addonname, 'Error parsing sources.xml file - script aborted')
exit_on_error()
if is_pvr:
my_command = my_command + " AND strPath NOT LIKE 'pvr://%'"
our_source_list = our_source_list + 'Keeping PVR info '
if excluding:
my_command = my_command + exclude_command
our_source_list = our_source_list + 'Keeping items from excludes.xml '
if bookmarks:
my_command = my_command + ' AND idFile NOT IN (SELECT idFile FROM bookmark)'
our_source_list = our_source_list + 'Keeping bookmarked files '
# construct the full SQL query
sql = \
"""DELETE FROM files WHERE idPath IN(SELECT idPath FROM path where (""" + my_command + """));"""
if no_sources:
my_command = ''
our_source_list = 'NO SOURCES FOUND - REMOVING rtmp(e), plugin and http info '
dbglog('Not using sources.xml')
if is_pvr:
my_command = my_command + "strPath NOT LIKE 'pvr://%'"
our_source_list = our_source_list + 'Keeping PVR info '
if bookmarks:
if my_command:
my_command = my_command + ' AND idFile NOT IN (SELECT idFile FROM bookmark)'
else:
my_command = my_command + ' idFile NOT IN (SELECT idFile FROM bookmark)'
our_source_list = our_source_list + 'Keeping bookmarked files '
if excluding:
if my_command:
my_command = my_command + exclude_command
else:
my_command = my_command + exclude_command.replace('AND','',1)
our_source_list = our_source_list + 'Keeping items from excludes.xml '
# Build SQL query
if not no_sources: # this is SQL for no sources
sql = """DELETE FROM files WHERE idPath IN ( SELECT idPath FROM path WHERE ((""" + my_command + """)));"""
# sql2="""DELETE FROM path WHERE idPath IN (SELECT * FROM( SELECT idPath FROM path WHERE ((strPath LIKE 'rtmp://%' OR strPath Like 'rtmpe:%' OR strPath LIKE 'plugin:%' OR strPath LIKE 'http://%') AND (""" + my_command +"""))) as pathsub);"""
else:
sql = """DELETE FROM files WHERE idPath IN (SELECT idPath FROM path WHERE ((strPath LIKE 'rtmp://%' OR strPath LIKE 'rtmpe:%' OR strPath LIKE 'plugin:%' OR strPath LIKE 'http://%' OR strPath LIKE 'https://%') AND (""" + my_command + """)));"""
# sql2= """DELETE FROM path WHERE idPath IN (SELECT * FROM( SELECT idPath FROM path WHERE (strPath LIKE 'rtmp://%' OR strPath Like 'rtmpe:%' OR strPath LIKE 'plugin:%' OR strPath LIKE 'http://%') as pathsub);"""
if my_command == "":
sql=sql.replace('((strPath','(strPath').replace(' AND ()))',')')
dbglog('SQL command is %s' % sql)
if not specificpath and not replacepath:
dbglog (our_source_list)
our_select = sql.replace('DELETE FROM files','SELECT strPath FROM path',1)
if bookmarks: # have to delete from paths table rather than files as there is a conflicting trigger on the files table
our_select = sql.replace('DELETE FROM files', 'SELECT strPath FROM path WHERE idPath in (SELECT idPath FROM files', 1)
our_select = our_select.replace('bookmark)', 'bookmark))',1)
sql = sql.replace('DELETE FROM files','DELETE FROM path',1)
dbglog('Select Command is %s' % our_select)
elif not replacepath and specificpath: # cleaning a specific path
if specific_path_to_remove != '':
sql = """delete from path where idPath in(select * from (SELECT idPath FROM path WHERE (strPath LIKE '""" + specific_path_to_remove +"""%')) as temptable)"""
our_select = "SELECT strPath FROM path WHERE idPath IN (SELECT idPath FROM path WHERE (strPath LIKE'" + specific_path_to_remove + "%'))"
dbglog('Select Command is %s' % our_select)
else:
xbmcgui.Dialog().ok(addonname,'Error - Specific path selected but no path defined. Script aborted')
dbglog("Error - Specific path selected with no path defined")
exit_on_error()
else: # must be replacing a path at this point
if old_path != '' and new_path != '':
our_select = "SELECT strPath from path WHERE strPath Like '" + old_path + "%'"
else:
xbmcgui.Dialog().ok(addonname,'Error - Replace path selected but one or more paths are not defined. Script aborted')
dbglog('Error - Missing path for replacement')
exit_on_error()
xbmc.sleep(500)
if promptdelete:
cleaner_log_file(our_select, False)
mydisplay = MyClass('cleaner-window.xml', addonpath, 'Default', '1080i')
mydisplay.doModal()
del mydisplay
if flag == 1:
i = True
else:
i = False
else:
i = True
if i:
if autobackup == 'true' and not is_mysql:
backup_path = xbmc.translatePath('special://database/backups/'
).decode('utf-8')
if not xbmcvfs.exists(backup_path):
dbglog('Creating backup path %s' % backup_path)
xbmcvfs.mkdir(backup_path)
now = datetime.datetime.now()
if forcedbname:
our_dbname = forcedname
current_db = db_path + our_dbname + '.db'
if backup_filename == '':
backup_filename = our_dbname
backup_db = backup_path + backup_filename + '_' \
+ now.strftime('%Y-%m-%d_%H%M') + '.db'
backup_filename = backup_filename + '_' \
+ now.strftime('%Y-%m-%d_%H%M')
success = xbmcvfs.copy(current_db, backup_db)
if success == 1:
success = 'successful'
else:
success = 'failed'
dbglog('auto backup database %s.db to %s.db - result was %s'
% (our_dbname, backup_filename, success))
cleaner_log_file(our_select, True)
if not replacepath:
try:
# Execute the SQL command
dbglog('Executing SQL command - %s' % sql)
cursor.execute(sql)
# cursor.execute(sql2)
# Commit the changes in the database
db.commit()
except Exception as e:
# Rollback in case there is any error
db.rollback()
dbglog('Error in db commit. Transaction rolled back')
dbglog('******************************************************************************')
dbglog('** SQL ERROR ** SQL ERROR ** SQL ERROR ** SQL ERROR ** SQL ERROR **')
dbglog('** %s ' % e)
dbglog('******************************************************************************')
else:
dbglog('Changing Paths - generating SQL statements')
our_select = "SELECT strPath from path WHERE strPath Like '" + old_path + "%'"
cursor.execute(our_select)
tempcount=0
listsize = len(cursor.fetchall())
dialog = xbmcgui.DialogProgressBG()
dbglog('Creating progress dialog')
dialog.create('Replacing paths in database. Please wait')
dialog.update(1)
dbglog('Cursor size is %d' % listsize)
cursor.execute(our_select)
renamepath_list = []
for strPath in cursor: # build a list of paths to change
renamepath_list.append( ''.join(strPath))
for i in range(len(renamepath_list)):
tempcount += 1
our_old_path = renamepath_list[i]
our_new_path = our_old_path.replace(old_path, new_path,1)
sql = 'UPDATE path SET strPath ="' + our_new_path + '" WHERE strPath LIKE "' +our_old_path + '"'
dialog.update(percent = int((tempcount / float(listsize)) * 100))
dbglog('Percentage done %d' % int((tempcount / float(listsize)) * 100))
dbglog('SQL - %s' % sql)
try:
cursor.execute(sql)
db.commit()
except Exception as e:
e = str(e)
db.rollback()
dbglog('Error in db commit %s. Transaction rolled back' % e)
# disconnect from server
# xbmc.executebuiltin( "Dialog.Close(busydialog)" )
xbmc.sleep(1000)
dbglog('Closing progress dialog')
dialog.close()
db.close()
dbglog("Database connection closed")
# Make sure replacing or changing a path is a one-shot deal
if replacepath or specificpath:
addon.setSetting('specificpath', 'false')
addon.setSetting('replacepath', 'false')
if autoclean:
xbmcgui.Dialog().notification(addonname,
'Running cleanup', xbmcgui.NOTIFICATION_INFO,
2000)
xbmc.sleep(2000)
json_query = \
xbmc.executeJSONRPC('{ "jsonrpc": "2.0", "method": "VideoLibrary.Clean","id": 1 }'
)
json_query = unicode(json_query, 'utf-8', errors='ignore')
json_query = jsoninterface.loads(json_query)
if json_query.has_key('result'):
dbglog('Clean library sucessfully called')
else:
xbmcgui.Dialog().ok(addonname,
'Script finished. You should run clean library for best results'
)
dbglog('Script finished')
else:
xbmcgui.Dialog().notification(addonname, 'Script aborted - No changes made', xbmcgui.NOTIFICATION_INFO, 3000)
dbglog('script aborted by user - no changes made')
WINDOW.setProperty('database-cleaner-running', 'false')
exit(1)
WINDOW.setProperty('database-cleaner-running', 'false')