Find orphans.py
From MythTV Official Wiki
Note: The correct title of this article is find_orphans.py. It appears incorrectly here due to technical restrictions.
| Version: 0.24
|
This script MythTV Python bindings from MythTV 0.24 or higher.
|
| Author | Raymond Wagner |
| Description | A scanner to look for missing and unknown recording files. This is informative only, informing the user of the files but taking no action. |
| Supports |
This script is a "safe" alternative to the old Myth.find_orphans.pl script. It is informative only, showing any missing videos, or unknown files. It can handle multiple backends, and does not need to be run locally, however recordings stored on offline backends will be marked as orphaned.
>./find_orphans.py
Recordings with missing files
Undercovers - Devices 4642_20101006201300.mpg
Orphaned video files
mythbe:/srv/mounts/twotb_1/video/2054_20080225110000.mpg 2.5GB
Total: 2.5GB
Orphaned snapshots
myth0:/srv/mounts/myth0_1/video/4122_20101013113500.mpg.png 2.6KB
mythbe:/srv/mounts/twotb_1/video/2029_20100409024900.mpg.png 84.9KB
mythbe:/srv/mounts/twotb_1/video/2047_20100807180500.mpg.png 92.9KB
mythbe:/srv/mounts/twotb_1/video/2059_20100630090000.mpg.png 87.0KB
Total: 267.4KB
Database backups
mythbe:/mnt/mythtv/store/backups/mythconverg--20101007134000.sql 17.3MB
mythbe:/mnt/mythtv/store/backups/mythconverg-1254-20100902174922.sql.gz 13.1MB
mythbe:/mnt/mythtv/store/backups/mythconverg-1263-20100913163154.sql 62.1MB
mythbe:/mnt/mythtv/store/backups/mythconverg-1263-20100913163216.sql.gz 13.0MB
mythbe:/mnt/mythtv/store/backups/mythconverg-1263-20101007134659.sql.gz 15.9MB
mythbe:/mnt/mythtv/store/backups/mythconverg-1264-20101008023651.sql.gz 16.5MB
Total: 137.9MB
Other files
mythbe:/srv/mounts/twotb_1/video/4121_20100312215900.mpg.tmp 398.6MB
mythbe:/srv/mounts/twotb_1/video/4191_20090928200000.mpg.tmp 2.4GB
mythbe:/srv/mounts/twotb_1/video/4191_20091005195900.mpg.tmp 2.6GB
mythbe:/srv/mounts/twotb_1/video/4642_20101006201300.mpg.1 4.9GB
Total: 10.2GB
#!/usr/bin/env python
from MythTV import MythDB, MythBE
from socket import timeout
import os
import sys
class File( str ):
def __new__(self, host, group, path, name, size):
return str.__new__(self, name)
def __init__(self, host, group, path, name, size):
self.host = host
self.group = group
self.path = path
self.size = int(size)
def human_size(s):
s = float(s)
o = 0
while s > 1000:
s /= 1000
o += 1
return str(round(s,1))+('B ','KB','MB','GB')[o]
def prettyprint(f):
print (' %s:%s' % (f.host, os.path.join(f.path, f))).ljust(80),\
human_size(f.size).rjust(8)
def main(host=None):
db = MythDB()
be = MythBE()
unfiltered = []
kwargs = {}
if host:
hosts = [host]
kwargs['hostname'] = host
else:
with db as c:
c.execute("""SELECT hostname FROM settings
WHERE value='BackendServerIP'""")
hosts = [r[0] for r in c.fetchall()]
for host in hosts:
for sg in db.getStorageGroup():
if sg.groupname in ('Videos','Banners','Coverart',\
'Fanart','Screenshots','Trailers'):
continue
try:
dirs,files,sizes = be.getSGList(host, sg.groupname, sg.dirname)
for f,s in zip(files,sizes):
newfile = File(host, sg.groupname, sg.dirname, f, s)
if newfile not in unfiltered:
unfiltered.append(newfile)
except:
pass
recs = list(db.searchRecorded(**kwargs))
zerorecs = []
orphvids = []
for rec in list(recs):
if rec.basename in unfiltered:
recs.remove(rec)
i = unfiltered.index(rec.basename)
f = unfiltered.pop(i)
if f.size < 1024:
zerorecs.append(rec)
name = rec.basename.rsplit('.',1)[0]
for f in list(unfiltered):
if name in f:
unfiltered.remove(f)
for f in list(unfiltered):
if not (f.endswith('.mpg') or f.endswith('.nuv')):
continue
orphvids.append(f)
unfiltered.remove(f)
orphimgs = []
for f in list(unfiltered):
if not f.endswith('.png'):
continue
orphimgs.append(f)
unfiltered.remove(f)
dbbackup = []
for f in list(unfiltered):
if 'sql' not in f:
continue
dbbackup.append(f)
unfiltered.remove(f)
if len(recs):
print "Recordings with missing files"
for rec in recs:
if rec.subtitle:
print (' %s - %s' % (rec.title, rec.subtitle)).ljust(60),
else:
print (' %s' % rec.title).ljust(60),
print rec.basename
if len(zerorecs):
print "\nZero byte recordings"
for rec in zerorecs:
if rec.subtitle:
print (' %s - %s' % (rec.title, rec.subtitle)).ljust(40),
else:
print (' %s' % rec.title).ljust(40),
print rec.basename
if len(orphvids):
print "\nOrphaned video files"
for f in sorted(orphvids, key=lambda x: x.path):
# os.unlink(os.path.join(f.path,f))
prettyprint(f)
size = sum([f.size for f in orphvids])
print 'Total:'.rjust(80),human_size(size).rjust(8)
if len(orphimgs):
print "\nOrphaned snapshots"
for f in sorted(orphimgs, key=lambda x: x.path):
prettyprint(f)
size = sum([f.size for f in orphimgs])
print 'Total:'.rjust(80),human_size(size).rjust(8)
if len(dbbackup):
print "\nDatabase backups"
for f in sorted(dbbackup, key=lambda x: x.path):
prettyprint(f)
size = sum([f.size for f in dbbackup])
print 'Total:'.rjust(80),human_size(size).rjust(8)
if len(unfiltered):
print "\nOther files"
for f in sorted(unfiltered, key=lambda x: x.path):
prettyprint(f)
size = sum([f.size for f in unfiltered])
print 'Total:'.rjust(80),human_size(size).rjust(8)
if __name__ == '__main__':
if len(sys.argv) == 2:
main(sys.argv[1])
else:
main()