|long=A scanner to look for missing and unknown recording files. This is informative only, informing the user of the files but taking no action.

+

|long=A scanner to look for missing and unknown recording files. This will only delete files after multiple confirmations.

|category=Maintenance

|category=Maintenance

|file=find_orphans.py

|file=find_orphans.py

−

|S24=yes}}

+

|S24=yes|S25=yes|S26=yes|S27=yes|S28=yes|S29=yes|S30=yes|S31=yes}}

This script shows recordings with missing files, or files with missing recordings. It can handle multiple backends, and does not need to be run locally, however recordings stored on offline backends will be marked as orphaned.

This script shows recordings with missing files, or files with missing recordings. It can handle multiple backends, and does not need to be run locally, however recordings stored on offline backends will be marked as orphaned.

Line 45:

Line 45:

</pre>

</pre>

−

{{Python|find_orphans.py|

+

{{Python|find_orphans.py (for v31+)|

<pre>

<pre>

−

#!/usr/bin/env python

+

#!/usr/bin/python3

−

from MythTV import MythDB, MythBE, Recorded

+

from MythTV import MythDB, MythBE, Recorded, MythError

from socket import timeout

from socket import timeout

Line 61:

Line 61:

s /= 1000

s /= 1000

o += 1

o += 1

−

return str(round(s,1))+('B ','KB','MB','GB')[o]

+

return str(round(s,1))+('B ','KB','MB','GB','TB')[o]

class File( str ):

class File( str ):

Line 73:

Line 73:

def pprint(self):

def pprint(self):

name = '%s: %s' % (self.host, os.path.join(self.path, self))

name = '%s: %s' % (self.host, os.path.join(self.path, self))

−

print ' {0:<90}{1:>8}'.format(name, human_size(self.size))

+

print(' {0:<90}{1:>8}'.format(name, human_size(self.size)))

def delete(self):

def delete(self):

be = MythBE(self.host, db=DB)

be = MythBE(self.host, db=DB)

Line 84:

Line 84:

if self.subtitle:

if self.subtitle:

name += ' - '+self.subtitle

name += ' - '+self.subtitle

−

print ' {0:<70}{1:>28}'.format(name,self.basename)

+

print(' {0:<70}{1:>28}'.format(name,self.basename))

+

+

def printrecs(title, recs):

+

print(title)

+

for rec in sorted(recs, key=lambda x: x.title):

+

rec.pprint()

+

print('{0:>88}{1:>12}'.format('Count:',len(recs)))

+

+

def printfiles(title, files):

+

print(title)

+

for f in sorted(files, key=lambda x: x.path):

+

f.pprint()

+

size = sum([f.size for f in files])

+

print('{0:>88}{1:>12}'.format('Total:',human_size(size)))

+

+

def populate(host=None):

+

unfiltered = []

+

kwargs = {'livetv':True}

+

if host:

+

with DB as c:

+

c.execute("""SELECT count(1) FROM settings

+

WHERE hostname=%s AND value=%s""",

+

(host, 'BackendServerIP'))

+

if c.fetchone()[0] == 0:

+

raise Exception('Invalid hostname specified on command line.')

+

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') or f.endswith('.ts')):

A scanner to look for missing and unknown recording files. This will only delete files after multiple confirmations.

Supports

This script shows recordings with missing files, or files with missing recordings. It can handle multiple backends, and does not need to be run locally, however recordings stored on offline backends will be marked as orphaned.

Additionally, this allows listing of database backups, and the listing and deletion of zero byte recordings, orphaned snapshots, and other unknown files.