-
Notifications
You must be signed in to change notification settings - Fork 0
/
mythnettv
executable file
·831 lines (720 loc) · 31.8 KB
/
mythnettv
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
#!/usr/bin/python
# This script requires that mplayer be installed
# Copyright (C) Michael Still (mikal@stillhq.com) 2006, 2007, 2008
# Copyright (C) Elkin Fricke (managementboy@gmail.com) 2011-2014
# Released under the terms of the GNU GPL v2
# Latest source is always at http://www.stillhq.com/mythtv/mythnettv/
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
import commands
import datetime
import feedparser
import os
import re
import shutil
import subprocess
import sys
import tempfile
import time
import traceback
import types
import database
import gflags
import program
import proxyhandler
import syndication
import mythnettvcore
import utility
import color
__author__ = 'Michael Still (mikal@stillhq.com), Elkin Fricke (managementboy@gmail.com)'
__version__ = 'Release 8'
# Define command line flags
FLAGS = gflags.FLAGS
gflags.DEFINE_string('datadir', '',
'The location of the data directory. Will change the '
'previous value')
gflags.DEFINE_string('defaultuploadrate', '',
'The default bittorrent upload rate. If set will '
'change the previous value')
gflags.DEFINE_boolean('prompt', True,
'Prompt for user input when required')
gflags.DEFINE_boolean('promptforannounce', True,
'Should the user be prompted about subscribing to the '
'announce video feed?')
gflags.DEFINE_string('downloadtime', '',
'The maximum time a torrent is allowed to run for.')
gflags.DEFINE_string('startuptime', '',
'The maximum time we wait for a torrent to start.')
def GetPossible(array, index):
"""GetPossible -- get a value from an array, handling its absence nicely"""
try:
return array[index]
except:
return None
def Usage(out):
out.write("""Unknown command line. Try one of:
(manual usage)
url <url> <title> : to download an RSS feed and load the shows
from it into the TODO list. The title is
as the show title in the MythTV user
interface
file <url> <title>: to do the same, but from a file, with a show
title like url above
download <num> : to download that number of shows from the
TODO list. We download some of the oldest
first, and then grab some of the newest as
well.
download <num> <title filter>
: the same as above, but filter to only
download shows with a title exactly
matching the specified filter
download <num> <title filter> <subtitle filter>
: the same as above, but with a regexp title
filter as well
download <num> <title filter> <subtitle filter> justone
: the same as above, but download just one
and then mark all other matches as read
cleartodo : permanently remove all items from the TODO
list
markread <num> : interactively mark some of the oldest <num>
shows as already downloaded and imported
markread <num> <title filter>
: the same as above, but filter to only mark
shows with a title exactly matching the
specified filter
markread <num> <title filter> <subtitle filter>
: the same as above, but with a regexp title
filter as well
markunread <num> <title filter> : interactively mark some of the
youngest <num> shows as not already downloaded
and imported filtered by actual title.
resetattempts : interactively reset the number of attempts
for matching programs to zero. This will
cause previously failed programs to be
retried
resetattempts <title filter>
: as above, but only for shows with this title
unfail : interactively scan through list of failed downloads
asking the user if they should be tried again
unfail <title filter>
: as above, but only for shows which match the title filter
(handy stuff)
todoremote : add a remote URL to the TODO list. This will
prompt for needed information about the
video, and set the date of the program to
now
todoremote <url> <title> <subtitle> <description>
: the same as above, but don't prompt for
anything
importremote : download and immediately import the named
URL. Will prompt for needed information
importremote <url> <title> <subtitle> <description>
: the same as above, but don't prompt for
anything
importtorrent <url> <title> <subtitle> <description>
: the same as above, but force the URL to be
treated as a torrent. This is useful when
MythNetTV doesn't automatically detect
that the URL is to a torrent file.
short version: imptor
importlocal <file>: import the named file, using the title,
subtitle and description from the command
line. The file will be left on disk.
importlocal <file>: import the named file. The file will be
left on disk. Will prompt for needed
information
importmanylocal <path> <regexp> <title>:
import all the files from path matching
regexp. title is use as the title for the
program, and the filename is used as the
subtitle
(subscription management)
subscribe <url> <title> <inetref*> <chanid*> <playbackgroup*>
: subscribe to a URL, and specify the show
title, inetref, chanid, playbackgroup
(*optional, but nice to have)
list : list subscriptions
unsubscribe <url> <title>
: unsubscribe from a feed, and remove feed
programs from TODO list
update : add new programs from subscribed URLs to the
TODO list
update <title> : as above, but just for this program
(things you can do to subscriptions)
archive <title> <path>
: archive all programs with this title to the
specified path. This is useful for shows you
download and import, but want to build a
non-MythTV archive of as well
category <title> <category>
: set the category for a given program. The
category is used for parental filtering within
MythTV.
group <title> <group>
: set the group for a given program. The
group is used as a recording group within
MythTV.
adddummychannel <chanid> <number> <callsign> <name> <icon>
: add a dummy channel to the mythbackend.
If the chanid is set in the subscription
mythnettv will map it to the imported
recording.
getchanid <callsign>
: returns the channel ID for a callsign.
us %callsign% to do a fuzzy match
http_proxy <url regexp> <proxy>
: you can choose to use a HTTP proxy for URL
requests matching a given regular expression.
Use this command to define such an entry. This
might be handy if some of the programs you
wish to subscribe to are only accessible over
a VPN.
http_proxy <url regexp> <proxy> <budget mb>
: the same a s above, but you can specify the
maximum number of megabytes to download via
the proxy in a given day. To see proxy usage
information, use the proxyusage command.
(reporting)
statistics : show some simple statistics about MythNetTV
short form: stats
log : dump the current internal log entries
nextdownload <num>
: if you executed download <num>, what would
be downloaded?
nextdownload <num> <title filter>
: as above, but only for the specified title
proxyusage : print a simple report on HTTP proxy usage over
the last seven days
(debugging)
videodir : show where MythNetTV thinks it should be
placing video files
explainvideodir : verbosely explain why that video directory was
selected. This can help debug when the wrong
video directory is being used, or no video
directory at all is found
(metadata)
tvrage <title> <ragetvtitle>
ttvdb <title>
: update all recordings that match the title
with the subtitle and description
found on TVRage/TTVDB.
Current subtitle must contain the season
and episode in a format like S##E##
or ##x##
sepfix <title> : fix the season and episode data by trying
to guess it from subtitle.
(other)
titlesubtitlefix <subtitle> <title>
: interactively remove a part of the subtitle
and replace the title with it. If you have
an rss feed that contains shows that contain
the actual title in the subtitle, this
tool will help you change those. Applies
to all titles where the subtitle contains
the string you provide. Updates metadata if
found.
autofixtitle <title>
: the automatic version of titlesubtitlefix.
Use if you are sure you know what you are
doing!
""")
out.write('\n\nAdditionally, you can use these global flags:%s\n' % FLAGS)
sys.exit(1)
def main(argv, out=color):
# Parse flags
try:
argv = FLAGS(argv)
except gflags.FlagsError, e:
out.write('%s\n' % e)
Usage(out)
db = database.MythNetTvDatabase()
# Update the data directory is set
if FLAGS.datadir:
db.WriteSetting('datadir', FLAGS.datadir)
print 'Updated the data directory to %s' % FLAGS.datadir
# Update the default upload rate for bittorrent if set
if FLAGS.defaultuploadrate:
db.WriteSetting('uploadrate', FLAGS.defaultuploadrate)
print ('Updated default bittorrent upload rate to %s'
% FLAGS.defaultuploadrate)
# Update the default max download time for bittorrent if set
if FLAGS.downloadtime:
db.WriteSetting('downloadtime', FLAGS.downloadtime)
print ('Updated default bittorrent download time to %s'
% FLAGS.downloadtime)
# Update the default max wait time for bittorrent if set
if FLAGS.startuptime:
db.WriteSetting('startuptime', FLAGS.startuptime)
print ('Updated default bittorrent start up time to %s'
% FLAGS.startuptime)
# Make sure the data directory exists
datadir = db.GetSettingWithDefault('datadir', FLAGS.datadir)
if not os.path.exists(datadir):
out.write('You need to create the configured data directory at "%s"\n'
% datadir)
sys.exit(1)
# Ask if we can subscribe the user to the announcement video feed
announce_prompted = db.GetSettingWithDefault('promptedforannounce',
not FLAGS.promptforannounce)
if not announce_prompted:
row = db.GetOneRow('select * from mythnettv_subscriptions where '
'title="MythNetTV announcements";')
if not row and FLAGS.promptforannounce:
out.write('You are not currently subscribed to the MythNetTV\n'
'announcements video feed. This feed is very low volume\n'
'and is used to announce important things like new releases\n'
'and major bug fixes.\n\n'
'Would you like to be subscribed? You will only be asked\n'
'this once.\n\n')
confirm = raw_input('Type yes to subscribe: ')
if confirm == 'yes':
mythnettvcore.Subscribe('http://www.stillhq.com/mythtv/mythnettv/'
'announce/feed.xml',
'MythNetTV announcements')
out.write('Subscribed to MythNetTV announcements\n')
db.WriteSetting('promptedforannounce', True)
# TODO(mikal): This command line processing is ghetto
if len(argv) == 1:
out.write('Invalid command line: %s\n' % ' '.join(argv))
Usage(out)
if argv[1] == 'url':
# Go and grab the XML file from the remote HTTP server, and then parse it
# as an RSS feed with enclosures. Populates a TODO list in
# mythnettv_programs
# Check to see if the correct number of args has been passed
if len(argv) == 4:
proxy = proxyhandler.HttpHandler(db)
xmlfile = proxy.Open(argv[2], out=out)
syndication.Sync(db, xmlfile, argv[3], out=out)
else:
out.write('Not enough arguments, please ensure you specify all values\n', RED)
elif argv[1] == 'file':
# Treat the local file as an RSS feed. Populates a TODO list in
# mythnettv_programs
xmlfile = open(argv[2])
syndication.Sync(db, xmlfile, argv[3])
elif argv[1] == 'download':
# Download the specified number of programs and import them into MythTV
filter = GetPossible(argv, 3)
subtitle_filter = GetPossible(argv, 4)
just_one = GetPossible(argv, 5) == 'justone'
success = False
previous = []
for guid in mythnettvcore.NextDownloads(argv[2], filter,
subtitle_filter,
out=out):
if not just_one:
mythnettvcore.DownloadAndImport(db, guid, out=out)
elif just_one and not success:
success = mythnettvcore.DownloadAndImport(db, guid, out=out)
if not success:
previous.append(guid)
else:
prog = program.MythNetTvProgram(db)
prog.Load(guid)
out.write('Skipping because we already have one\n')
out.write(' %s: %s\n' %(prog.GetTitle(), prog.GetSubtitle()))
out.write(' (%s)\n\n' % prog.GetDate())
prog.SetImported()
prog.Store()
# If some failed before we had one work, then we now need to mark them
# read if we're fetching just one
if just_one and previous:
for guid in previous:
prog = program.MythNetTvProgram(db)
prog.Load(guid)
out.write('Skipping because we already have one\n')
out.write(' %s: %s\n' %(prog.GetTitle(), prog.GetSubtitle()))
out.write(' (%s)\n\n' % prog.GetDate())
prog.SetImported()
prog.Store()
# And now make sure there aren't any stragglers
for guid in db.GetWaitingForImport():
prog = program.MythNetTvProgram(db)
prog.Load(guid)
try:
prog.Import(out=out)
except Exception, e:
out.write('Couldn\'t straggling %s, removing it from the queue\n'
' Error: %s\n\n'
% (guid, e))
prog.SetImported()
prog.Store()
elif argv[1] == 'todoremote':
# Add a remote URL to the TODO list. We have to prompt for a bunch of
# stuff because we don't have a "real" RSS feed
prog = program.MythNetTvProgram(db)
url = GetPossible(argv, 2)
title = GetPossible(argv, 3)
subtitle = GetPossible(argv, 4)
description = GetPossible(argv, 5)
prog.FromInteractive(url, title, subtitle, description)
elif argv[1] == 'importremote' or argv[1] == 'importtorrent' or argv[1] == 'imptor':
# Download a remote file and then import it as a program. We have to
# prompt for details here, because this didn't come from a "real" RSS feed
prog = program.MythNetTvProgram(db)
url = GetPossible(argv, 2)
title = GetPossible(argv, 3)
subtitle = GetPossible(argv, 4)
description = GetPossible(argv, 5)
# TODO(mikal)
# It is _possible_ that this show has already been created and
# that this is an attempt to restart a download. Check.
prog.FromInteractive(url, title, subtitle, description)
prog.Store()
if argv[1] == 'importtorrent':
prog.SetMime('application/x-bittorrent')
if prog.Download(db.GetSettingWithDefault('datadir',
FLAGS.datadir),
out=out) == True:
prog.Import(out=out)
elif argv[1] == 'importmanylocal':
# Import files matching regexp from path with the title
path = argv[2]
regexp = argv[3]
title = argv[4]
rxp = re.compile(regexp)
for ent in os.listdir(path):
if os.path.isfile('%s/%s' %(path, ent)):
out.write('\nConsidering %s\n' % ent)
m = rxp.match(ent)
if m:
prog = program.MythNetTvProgram(db)
prog.SetUrl(ent)
prog.FromInteractive('%s/%s' %(path, ent),
title,
ent,
'-')
prog.CopyLocalFile(db.GetSettingWithDefault('datadir',
FLAGS.datadir),
out=out)
prog.Import(out=out)
elif argv[1] == 'importlocal':
# Take a local file, copy it to the temporary directory, and then import
# it as if we had downloaded it
prog = program.MythNetTvProgram(db)
prog.SetUrl(argv[2])
url = GetPossible(argv, 2)
title = GetPossible(argv, 3)
subtitle = GetPossible(argv, 4)
description = GetPossible(argv, 5)
prog.FromInteractive(url, title, subtitle, description)
prog.CopyLocalFile(db.GetSettingWithDefault('datadir',
FLAGS.datadir),
out=out)
prog.Import(out=out)
elif argv[1] == 'subscribe':
# Subscribe to an RSS feed
if len(argv) > 4:
mythnettvcore.Subscribe(argv[2], argv[3], argv[4], argv[5], argv[6])
else:
mythnettvcore.Subscribe(argv[2], argv[3], None, None)
out.write('Subscribed to %s\n' % argv[3])
elif argv[1] == 'list':
# List subscribed RSS feeds
proxy = proxyhandler.HttpHandler(db)
for row in db.GetRows('select distinct(title) from '
'mythnettv_subscriptions order by title'):
out.write('%s\n' % row['title'])
for subrow in db.GetRows('select * from mythnettv_subscriptions where '
'title="%s";' % row['title']):
out.write(' - %s' % subrow['url'])
(proxy_host, budget) = proxy.LookupProxy(subrow['url'])
if proxy_host:
out.write(' (proxy: %s' % proxy_host)
if budget:
out.write(' budget %s)' % utility.DisplayFriendlySize(budget))
else:
out.write(')')
out.write('\n')
if subrow['inactive'] == 1:
out.write(' (inactive)\n')
subrow = db.GetOneRow('select * from mythnettv_archive '
'where title="%s";'
% row['title'])
if subrow:
out.write(' Archived to %s\n' % subrow['path'])
subrow = db.GetOneRow('select * from mythnettv_category '
'where title="%s";'
% row['title'])
if subrow:
out.write(' Category is %s\n' % subrow['category'])
subrow = db.GetOneRow('select * from mythnettv_group '
'where title="%s";'
% row['title'])
if subrow:
out.write(' Group is %s\n' % subrow['recgroup'])
out.write('\n')
elif argv[1] == 'unsubscribe':
# Remove a subscription to an RSS feed
if db.ExecuteSql('update mythnettv_subscriptions set inactive=1 '
'where url = "%s";'
% argv[2]) == 0:
print 'No subscriptions with this URL found!'
if db.ExecuteSql('update mythnettv_programs set inactive=1 '
'where title = "%s";'
% argv[3]) == 0:
print 'No subscriptions with this title found!'
elif argv[1] == 'update':
# Update the TODO list based on subscriptions
title = GetPossible(argv, 2)
mythnettvcore.Update(out, title)
elif argv[1] == 'archive':
db.WriteOneRow('mythnettv_archive', 'title', {'title': argv[2],
'path': argv[3]})
elif argv[1] == 'category':
db.WriteOneRow('mythnettv_category', 'title', {'title': argv[2],
'category': argv[3]})
elif argv[1] == 'group':
db.WriteOneRow('mythnettv_group', 'title', {'title': argv[2],
'recgroup': argv[3]})
elif argv[1] == 'http_proxy':
budget = GetPossible(argv, 4)
if budget:
budget = int(budget) * 1024 * 1024
out.write('Setting proxy budget to %d bytes\n' % budget)
db.WriteOneRow('mythnettv_proxies', 'url', {'url': argv[2],
'http_proxy': argv[3],
'daily_budget': budget})
elif argv[1] == 'statistics' or argv[1] == 'stats':
# Display some simple stats about the state of MythMYTHNETTV
row = db.GetOneRow('select count(guid) from mythnettv_programs where '
'download_finished is NULL and title is not NULL '
'and inactive is NULL;')
out.write('Programs still to download: %d\n'
% row['count(guid)'], BLUE)
for show in db.GetRows('select distinct(title) from mythnettv_programs '
'where title is not NULL and '
'inactive is NULL and '
'download_finished is NULL;'):
row = db.GetOneRow('select count(guid) from mythnettv_programs where '
'title = "%s" and inactive is NULL '
'and download_finished is NULL;'
% show['title'])
out.write(' %s: %d\n' %(show['title'], row['count(guid)']))
out.write('\n')
try:
row = db.GetOneRow('select sum(transfered) from mythnettv_programs;')
out.write('Data transferred: %s\n'
% (utility.DisplayFriendlySize(int(row['sum(transfered)']))))
except:
# TODO(mikal): I am sure there is a better way of doing this
dummy = 'blah'
elif argv[1] == 'log':
for logline in db.GetRows('select * from mythnettv_log order by '
'sequence asc;'):
out.write('%s %s\n' %(logline['timestamp'], logline['message']))
elif argv[1] == 'nextdownload':
filter = GetPossible(argv, 3)
subtitle_filter = GetPossible(argv, 4)
for guid in mythnettvcore.NextDownloads(argv[2], filter,
subtitle_filter,
out=out):
out.write('%s\n' % guid)
prog = program.MythNetTvProgram(db)
prog.Load(guid)
out.write(' %s: %s\n\n' %(prog.GetTitle(), prog.GetSubtitle()))
elif argv[1] == 'cleartodo':
out.write("""The command you are executing will permanently remove all
shows from the TODO list, as well as any record of shows which have
already been downloaded. Basically you\'ll be back at the start
again, although your preferences will remain set. Are you sure
you want to do this?\n\n""")
confirm = raw_input('Type yes to do this: ')
if confirm == 'yes':
db.ExecuteSql('delete from mythnettv_programs;')
out.write('Deleted\n')
elif argv[1] == 'markread':
filter = GetPossible(argv, 3)
subtitle_filter = GetPossible(argv, 4)
for guid in mythnettvcore.NextDownloads(argv[2], filter,
subtitle_filter):
prog = program.MythNetTvProgram(db)
prog.Load(guid)
out.write(' %s: %s\n' %(prog.GetTitle(), prog.GetSubtitle()))
out.write(' (%s)\n' % prog.GetDate())
out.write(' (%s)\n\n' % guid)
if FLAGS.prompt:
out.write('Are you sure you want to mark this show as downloaded?'
'\n\n')
confirm = raw_input('Type yes to do this: ')
else:
confirm = 'yes'
if confirm == 'yes':
prog.SetImported()
prog.Store()
out.write('Done\n')
out.write('\n')
elif argv[1] == 'markunread':
for row in db.GetRows('select guid from mythnettv_programs where '
'(download_finished=1 or imported=1 or '
'attempts is not null or failed=1 )'
'and title LIKE %s'
'order by date desc limit %d;'
% (db.FormatSqlValue('', argv[3]), int(argv[2]))):
prog = program.MythNetTvProgram(db)
prog.Load(row['guid'])
out.write(' %s: %s\n' %(prog.GetTitle(), prog.GetSubtitle()))
out.write(' (%s)\n\n' % prog.GetDate())
if FLAGS.prompt:
out.write('Are you sure you want to mark this show as not downloaded?'
'\n\n')
confirm = raw_input('Type yes to do this: ')
else:
confirm = 'yes'
if confirm == 'yes':
prog.SetNew()
prog.Store()
out.write('Done\n')
out.write('\n')
elif argv[1] == 'resetattempts':
filter = GetPossible(argv, 2)
if filter:
filter_sql = 'and title="%s"' % filter
else:
filter_sql = ''
for row in db.GetRows('select * from mythnettv_programs where '
'attempts > 0 and download_finished is null %s;'
% filter_sql):
prog = program.MythNetTvProgram(db)
prog.Load(row['guid'])
out.write(' %s: %s\n' %(prog.GetTitle(), prog.GetSubtitle()))
out.write(' (%s)\n\n' % prog.GetDate())
if FLAGS.prompt:
out.write('Are you sure you want to reset the attempt count for this '
'show?\n\n')
confirm = raw_input('Type yes to do this: ')
else:
confirm = 'yes'
if confirm == 'yes':
prog.SetAttempts(0)
prog.Store()
out.write('Done\n')
out.write('\n')
elif argv[1] == 'getchanid':
for row in db.GetRows('select callsign, chanid from channel where '
'callsign LIKE "%s";'
% argv[2]):
out.write(' %s: %s\n' %(row['callsign'], row['chanid']))
elif argv[1] == 'unfail':
filter = GetPossible(argv, 2)
if filter:
filter_sql = 'and title="%s"' % filter
else:
filter_sql = ''
for row in db.GetRows('select * from mythnettv_programs where '
'failed is not null and '
'download_finished is not null %s;'
% filter_sql):
prog = program.MythNetTvProgram(db)
prog.Load(row['guid'])
out.write(' %s: %s\n' %(prog.GetTitle(), prog.GetSubtitle()))
out.write(' (%s)\n\n' % prog.GetDate())
if FLAGS.prompt:
out.write('Are you sure you want to retry this failed download?\n\n')
confirm = raw_input('Type yes to do this: ')
else:
confirm = 'yes'
if confirm == 'yes':
prog.Unfail()
out.write('Done\n')
out.write('\n')
elif argv[1] == 'proxyusage':
proxy = proxyhandler.HttpHandler(db)
proxy.ReportRecentProxyUsage(out=out)
elif argv[1] == 'videodir':
try:
print 'Video directory is: %s' % utility.GetVideoDir()
except utility.FilenameException:
print 'No video directory found! Use explainvideodir to debug'
elif argv[1] == 'adddummychannel':
chanid = argv[2]
channum = argv[3]
callsign = argv[4]
channame = argv[5]
icon = argv[6]
if program.addChannel(icon, chanid, channum, callsign, channame):
out.write('Added dummy channel %s to mythbackend\n' % channame)
else:
out.write('Error: dummy channel %s was not added to mythbackend!/n Could be duplicate chanid or channel number\n' % channame)
elif argv[1] == 'explainvideodir':
utility.ExplainVideoDir(db)
elif argv[1] == 'tvrage':
showtitle = GetPossible(argv, 2)
prog = program.MythNetTvProgram(db)
prog.TVRage(showtitle)
elif argv[1] == 'ttvdb':
showtitle = GetPossible(argv, 2)
prog = program.MythNetTvProgram(db)
prog.TTVDB(showtitle)
elif argv[1] == 'titlefix':
oldtitle = GetPossible(argv, 2)
newtitle = GetPossible(argv, 3)
prog = program.MythNetTvProgram(db)
prog.titlefix(oldtitle, newtitle)
elif argv[1] == 'sefix':
title = GetPossible(argv, 2)
prog = program.MythNetTvProgram(db)
prog.sefix(title)
elif argv[1] == 'autofixtitle':
row = db.GetRows('SELECT subtitle FROM recorded where title LIKE "%s";' % argv[2])
p = re.compile(r'(.*)\ [0-9]of[0-9].*')
p2 = re.compile(r'(.*)\ ([0-9][0-9][0-9][0-9])(.*)')
if row:
for item in row:
try:
out.write('\n Current Subtitle: %s\n' % (item["subtitle"]))
m = p.match(item["subtitle"])
db.ExecuteSql('UPDATE recorded SET title = "%s", subtitle = replace(subtitle,"%s","") WHERE title LIKE "%s" AND subtitle LIKE "%s";'
% (m.group(1), m.group(1), argv[2], m.group(0)))
prog = program.MythNetTvProgram(db)
prog.TVRage(m.group(1))
prog.TTVDB(m.group(1))
except:
out.write(' No match could be found for XofY ... nothing changed\n')
pass
try:
m = p2.match(item["subtitle"])
db.ExecuteSql('UPDATE recorded SET title = "%s", subtitle = "%s", originalairdate = "%s-01-01" WHERE title LIKE "%s" AND subtitle LIKE "%s";'
% (m.group(1), m.group(3), m.group(2), argv[2], m.group(0)))
prog = program.MythNetTvProgram(db)
prog.TVRage(m.group(1))
prog.TTVDB(m.group(1))
except:
out.write(' No match could be found for YYYY ... nothing changed\n')
pass
else:
out.write('Sorry, no shows with the title %s available\n' % argv[2])
elif argv[1] == 'titlesubtitlefix':
row = db.GetOneRow('SELECT subtitle FROM recorded where title LIKE "%s";' % argv[2])
if row:
out.write('\n\nCurrent Subtitle: %s\n' % (row['subtitle']))
prompt = "New Title"
subtitle = program.Prompt(prompt)
db.ExecuteSql('UPDATE recorded SET title = "%s", subtitle = replace(subtitle,"%s","") WHERE title LIKE "%s" AND subtitle LIKE "%%%s%%";'
% (subtitle, subtitle, argv[2], subtitle))
prog = program.MythNetTvProgram(db)
prog.TVRage(subtitle)
prog.TTVDB(subtitle)
else:
out.write('Sorry, no shows with the title %s available\n' % argv[2])
elif argv[1] == 'aspectfix':
prog = program.MythNetTvProgram(db)
prog.allaspects(argv[2])
elif argv[1] == 'rescue':
prog = program.MythNetTvProgram(db)
for row in db.GetRows('SELECT title, subtitle, filesize, starttime, basename FROM recorded WHERE title LIKE "%s";' % (argv[2])):
row2 = db.GetOneRow('SELECT title, subtitle, size FROM mythnettv_programs WHERE starttime LIKE "%s" and size LIKE "%s";' % (
row['starttime'], row['filesize']))
title = re.sub('[0-9]of[0-9]\ .*|[0-9]x[0-9]\ .*','', row2['subtitle'])
subtitle = re.sub(title, '', row2['subtitle'])
try:
out.write('Title: %s\n' % title)
out.write('Subtitle: %s\n' % subtitle)
out.write('filename: %s\n' % row['basename'])
out.write('UPDATE recorded SET title = "%s", subtitle = "%s" WHERE starttime LIKE "%s" AND basename LIKE "%s";' % (title, subtitle, row['starttime'], row['basename']))
except:
pass
else:
Usage(out)
if __name__ == "__main__":
main(sys.argv)