Problems deleteing records for files missing ~ find_orphans.py v31

Have a MythTV related problem? Ask for help from other MythTV users here.

Moderator: Forum Moderators

Post Reply
User avatar
keepitsimpleengineer
Junior
Posts: 37
Joined: Fri Oct 03, 2014 9:53 pm
Location: Central California, U.S.A.
Contact:
United States of America

Problems deleteing records for files missing ~ find_orphans.py v31

Post by keepitsimpleengineer » Tue Oct 20, 2020 6:47 pm

Ran the 'find_orphans.py' for v31 https://www.mythtv.org/wiki/Find_orphans.py

Found 1400+. the residue from major hardware failure :(

New drive for recordings :)
but when I run find_orphans.py and try "1. Delete orphaned recording entries" I get this error:

Code: Select all

Traceback (most recent call last):
  File "/usr/bin/find_orphans.py", line 230, in <module>
    main()
  File "/usr/bin/find_orphans.py", line 214, in main
    opt[1](opt[2])
  File "/usr/bin/find_orphans.py", line 129, in delete_recs
    rec.delete(True, True)
  File "/usr/lib/python3.8/site-packages/MythTV/dataheap.py", line 377, in delete
    return self.getProgram().delete(force, rerecord)
  File "/usr/lib/python3.8/site-packages/MythTV/mythproto.py", line 972, in delete
    res = int(be.deleteRecording(self, force=force))
  File "/usr/lib/python3.8/site-packages/MythTV/mythproto.py", line 668, in deleteRecording
    [command,program.toString()]))
  File "/usr/lib/python3.8/site-packages/MythTV/mythproto.py", line 962, in toString
    return BACKEND_SEP.join(self._deprocess())
  File "/usr/lib/python3.8/site-packages/MythTV/altdict.py", line 178, in _deprocess
    data[i] = self._inv_trans[self._field_type[i]](v)
  File "/usr/lib/python3.8/site-packages/MythTV/altdict.py", line 113, in <lambda>
    lambda x: str(int(x.timestamp())),
  File "/usr/lib/python3.8/site-packages/MythTV/utility/dt.py", line 481, in timestamp
    return ((utc_naive - utc_epoch).total_seconds())
TypeError: can't subtract offset-naive and offset-aware datetimes
Checked for database errors did not help.

:o Help..!

User avatar
bill6502
Developer
Posts: 1814
Joined: Fri Feb 07, 2014 5:28 pm
United States of America

Re: Problems deleteing records for files missing ~ find_orphans.py v31

Post by bill6502 » Tue Oct 20, 2020 9:05 pm

I believe it was fixed last July.[d8ecd8fe7c]

User avatar
keepitsimpleengineer
Junior
Posts: 37
Joined: Fri Oct 03, 2014 9:53 pm
Location: Central California, U.S.A.
Contact:
United States of America

Re: Problems deleteing records for files missing ~ find_orphans.py v31

Post by keepitsimpleengineer » Wed Oct 21, 2020 9:45 pm

bill6502 wrote:
Tue Oct 20, 2020 9:05 pm
I believe it was fixed last July.[d8ecd8fe7c]
I down loaded the script the same day I ran it so perhaps the fix didn't make it to https://www.mythtv.org/wiki/Find_orphans.py

How could one find out... .. ? :?:

User avatar
keepitsimpleengineer
Junior
Posts: 37
Joined: Fri Oct 03, 2014 9:53 pm
Location: Central California, U.S.A.
Contact:
United States of America

Re: Problems deleteing records for files missing ~ find_orphans.py v31

Post by keepitsimpleengineer » Wed Oct 21, 2020 11:34 pm

keepitsimpleengineer wrote:
Wed Oct 21, 2020 9:45 pm
bill6502 wrote:
Tue Oct 20, 2020 9:05 pm
I believe it was fixed last July.[d8ecd8fe7c]
I down loaded the script the same day I ran it so perhaps the fix didn't make it to https://www.mythtv.org/wiki/Find_orphans.py

How could one find out... .. ? :?:
The code in [d8ecd8fe7c] is different from the code in https://github.com/MythTV/mythtv/issues

So where to pursue this now..?

User avatar
bill6502
Developer
Posts: 1814
Joined: Fri Feb 07, 2014 5:28 pm
United States of America

Re: Problems deleteing records for files missing ~ find_orphans.py v31

Post by bill6502 » Thu Oct 22, 2020 12:41 am

I updated the commit to the v31 version (I used master.) Not sure which issue you're referring to.
The fix is in bindings, not find_orphans.py.

User avatar
keepitsimpleengineer
Junior
Posts: 37
Joined: Fri Oct 03, 2014 9:53 pm
Location: Central California, U.S.A.
Contact:
United States of America

Re: Problems deleteing records for files missing ~ find_orphans.py v31

Post by keepitsimpleengineer » Fri Oct 23, 2020 6:08 pm

I re-ran find_orphans.py and logged the output deleted several thousand lines of record names.

Code: Select all

[ljohnson@KISE-055 ~]$ cat /usr/bin/find_orphans.py | tee -a find_orphans_test.txt
#!/usr/bin/python3

from MythTV import MythDB, MythBE, Recorded, MythError
from socket import timeout

import os
import sys

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','TB')[o]

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 pprint(self):
        name = '%s: %s' % (self.host, os.path.join(self.path, self))
        print('  {0:<90}{1:>8}'.format(name, human_size(self.size)))
    def delete(self):
        be = MythBE(self.host, db=DB)
        be.deleteFile(self, self.group)

class MyRecorded( Recorded ):
    _table = 'recorded'
    def pprint(self):
        name = '{0.hostname}: {0.title}'.format(self)
        if self.subtitle:
            name += ' - '+self.subtitle
        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, 'BackendServerAddr'))
            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='BackendServerAddr'""")
            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')):
            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)

    return (recs, zerorecs, orphvids, orphimgs, dbbackup, unfiltered)

def delete_recs(recs):
    printrecs('The following recordings will be deleted', recs)
    print('Are you sure you want to continue?')
    try:
        res = input('> ')
        while True:
            if res == 'yes':
                for rec in recs:
                    rec.delete(True, True)
                break
            elif res == 'no':
                break
            else:
                res = input("'yes' or 'no' > ")
    except MythError:
        name = '{0.hostname}: {0.title}'.format(rec)
        if rec.subtitle:
            name += ' - '+rec.subtitle
        print("Warning: Failed to delete '" + name + "'")
    except KeyboardInterrupt:
        pass
    except EOFError:
        sys.exit(0)

def delete_files(files):
    printfiles('The following files will be deleted', files)
    print('Are you sure you want to continue?')
    try:
        res = input('> ')
        while True:
            if res == 'yes':
                for f in files:
                    f.delete()
                break
            elif res == 'no':
                break
            else:
                res = input("'yes' or 'no' > ")
    except KeyboardInterrupt:
        pass
    except EOFError:
        sys.exit(0)

def main(host=None):
   while True:
        recs, zerorecs, orphvids, orphimgs, dbbackup, unfiltered = populate(host)

        if len(recs):
            printrecs("Recordings with missing files", recs)
        if len(zerorecs):
            printrecs("Zero byte recordings", zerorecs)
        if len(orphvids):
            printfiles("Orphaned video files", orphvids)
        if len(orphimgs):
            printfiles("Orphaned snapshots", orphimgs)
        if len(dbbackup):
            printfiles("Database backups", dbbackup)
        if len(unfiltered):
            printfiles("Other files", unfiltered)

        opts = []
        if len(recs):
            opts.append(['Delete orphaned recording entries', delete_recs, recs])
        if len(zerorecs):
            opts.append(['Delete zero byte recordings', delete_recs, zerorecs])
        if len(orphvids):
            opts.append(['Delete orphaned video files', delete_files, orphvids])
        if len(orphimgs):
            opts.append(['Delete orphaned snapshots', delete_files, orphimgs])
        if len(unfiltered):
            opts.append(['Delete other files', delete_files, unfiltered])
        opts.append(['Refresh list', None, None])
        print('Please select from the following')
        for i, opt in enumerate(opts):
            print(' {0}. {1}'.format(i+1, opt[0]))

        try:
            inner = True
            res = input('> ')
            while inner:
                try:
                    res = int(res)
                except:
                    res = input('input number. ctrl-c to exit > ')
                    continue
                if (res <= 0) or (res > len(opts)):
                    res = input('input number within range > ')
                    continue
                break
            opt = opts[res-1]
            if opt[1] is None:
                continue
            else:
                opt[1](opt[2])

        except KeyboardInterrupt:
            break
        except EOFError:
            sys.exit(0)

DB = MythDB()
BE = MythBE(db=DB)
DB.searchRecorded.handler = MyRecorded
DB.searchRecorded.dbclass = MyRecorded

if __name__ == '__main__':
    if len(sys.argv) == 2:
        main(sys.argv[1])
    else:
        main()
#!/usr/bin/python3

from MythTV import MythDB, MythBE, Recorded, MythError
from socket import timeout

import os
import sys

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','TB')[o]

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 pprint(self):
        name = '%s: %s' % (self.host, os.path.join(self.path, self))
        print('  {0:<90}{1:>8}'.format(name, human_size(self.size)))
    def delete(self):
        be = MythBE(self.host, db=DB)
        be.deleteFile(self, self.group)

class MyRecorded( Recorded ):
    _table = 'recorded'
    def pprint(self):
        name = '{0.hostname}: {0.title}'.format(self)
        if self.subtitle:
            name += ' - '+self.subtitle
        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, 'BackendServerAddr'))
            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='BackendServerAddr'""")
            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')):
            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)

    return (recs, zerorecs, orphvids, orphimgs, dbbackup, unfiltered)

def delete_recs(recs):
    printrecs('The following recordings will be deleted', recs)
    print('Are you sure you want to continue?')
    try:
        res = input('> ')
        while True:
            if res == 'yes':
                for rec in recs:
                    rec.delete(True, True)
                break
            elif res == 'no':
                break
            else:
                res = input("'yes' or 'no' > ")
    except MythError:
        name = '{0.hostname}: {0.title}'.format(rec)
        if rec.subtitle:
            name += ' - '+rec.subtitle
        print("Warning: Failed to delete '" + name + "'")
    except KeyboardInterrupt:
        pass
    except EOFError:
        sys.exit(0)

def delete_files(files):
    printfiles('The following files will be deleted', files)
    print('Are you sure you want to continue?')
    try:
        res = input('> ')
        while True:
            if res == 'yes':
                for f in files:
                    f.delete()
                break
            elif res == 'no':
                break
            else:
                res = input("'yes' or 'no' > ")
    except KeyboardInterrupt:
        pass
    except EOFError:
        sys.exit(0)

def main(host=None):
   while True:
        recs, zerorecs, orphvids, orphimgs, dbbackup, unfiltered = populate(host)

        if len(recs):
            printrecs("Recordings with missing files", recs)
        if len(zerorecs):
            printrecs("Zero byte recordings", zerorecs)
        if len(orphvids):
            printfiles("Orphaned video files", orphvids)
        if len(orphimgs):
            printfiles("Orphaned snapshots", orphimgs)
        if len(dbbackup):
            printfiles("Database backups", dbbackup)
        if len(unfiltered):
            printfiles("Other files", unfiltered)

        opts = []
        if len(recs):
            opts.append(['Delete orphaned recording entries', delete_recs, recs])
        if len(zerorecs):
            opts.append(['Delete zero byte recordings', delete_recs, zerorecs])
        if len(orphvids):
            opts.append(['Delete orphaned video files', delete_files, orphvids])
        if len(orphimgs):
            opts.append(['Delete orphaned snapshots', delete_files, orphimgs])
        if len(unfiltered):
            opts.append(['Delete other files', delete_files, unfiltered])
        opts.append(['Refresh list', None, None])
        print('Please select from the following')
        for i, opt in enumerate(opts):
            print(' {0}. {1}'.format(i+1, opt[0]))

        try:
            inner = True
            res = input('> ')
            while inner:
                try:
                    res = int(res)
                except:
                    res = input('input number. ctrl-c to exit > ')
                    continue
                if (res <= 0) or (res > len(opts)):
                    res = input('input number within range > ')
                    continue
                break
            opt = opts[res-1]
            if opt[1] is None:
                continue
            else:
                opt[1](opt[2])

        except KeyboardInterrupt:
            break
        except EOFError:
            sys.exit(0)

DB = MythDB()
BE = MythBE(db=DB)
DB.searchRecorded.handler = MyRecorded
DB.searchRecorded.dbclass = MyRecorded

if __name__ == '__main__':
    if len(sys.argv) == 2:
        main(sys.argv[1])
    else:
        main()
[ljohnson@KISE-055 ~]$ /usr/bin/find_orphans.py | tee -a find_orphans_test.txt
Recordings with missing files
  KISE-055: 60 Minutes                                                        1131_20190107020000.ts
  KISE-055: A Year in Space                                                   1061_20171117220000.ts
......
  KISE-055: Young Sheldon - A Broom Closet and Satan's Monopoly Board         1131_20191004020000.ts
  KISE-055: Young Sheldon - Hobbitses, Physicses and a Ball With Zip          1131_20191018020000.ts
                                                                                  Count:        1468
Orphaned video files
  kise-055: /pvr/default/10301_20200608230000.ts                                               6.6GB
  kise-055: /pvr/default/10301_20200804011700.ts                                               1.2GB
  kise-055: /pvr/default/10603_20200608223000.ts                                             476.4MB
  kise-055: /pvr/default/11301_20200609000000.ts                                               3.4GB
  kise-055: /pvr/default/11301_20200609003000.ts                                               3.3GB
  kise-055: /pvr/default/1131_20190819230000.ts                                                2.3GB
  kise-055: /pvr/default/1131_20200220150000.ts                                                7.6GB
  kise-055: /pvs/livetv/1401_20190818232750.ts                                                 0.0B 
                                                                                  Total:      24.9GB
Orphaned snapshots
  kise-055: /pvr/default/10301_20200608230000.ts.png                                           2.0MB
  kise-055: /pvr/default/10603_20200608223000.ts.png                                         210.5KB
  kise-055: /pvr/default/11301_20200609000000.ts.png                                           1.2MB
  kise-055: /pvr/default/11301_20200609003000.ts.png                                         274.3KB
                                                                                  Total:       3.7MB
Database backups
  kise-055: /pvr/db_bu/mythconverg-1361-20200910050502.sql.gz                                150.1MB
  kise-055: /pvr/db_bu/mythconverg-1361-20200911050502.sql.gz                                151.4MB
  kise-055: /pvr/db_bu/mythconverg-1361-20200914050502.sql.gz                                150.2MB
  kise-055: /pvr/db_bu/mythconverg-20200913050501.sql                                          0.0B 
                                                                                  Total:     451.7MB
Other files
  kise-055: /pvr/default/test                                                                  0.0B 
                                                                                  Total:       0.0B 
Please select from the following
 1. Delete orphaned recording entries
 2. Delete orphaned video files
 3. Delete orphaned snapshots
 4. Delete other files
 5. Refresh list
> The following recordings will be deleted
  KISE-055: 60 Minutes                                                        1131_20190107020000.ts
  KISE-055: A Year in Space                                                   1061_20171117220000.ts
............
  KISE-055: Young Sheldon - A Broom Closet and Satan's Monopoly Board         1131_20191004020000.ts
  KISE-055: Young Sheldon - Hobbitses, Physicses and a Ball With Zip          1131_20191018020000.ts
                                                                                  Count:        1468
Are you sure you want to continue?
> yes
Traceback (most recent call last):
  File "/usr/bin/find_orphans.py", line 230, in <module>
    main()
  File "/usr/bin/find_orphans.py", line 214, in main
    opt[1](opt[2])
  File "/usr/bin/find_orphans.py", line 129, in delete_recs
    rec.delete(True, True)
  File "/usr/lib/python3.8/site-packages/MythTV/dataheap.py", line 377, in delete
    return self.getProgram().delete(force, rerecord)
  File "/usr/lib/python3.8/site-packages/MythTV/mythproto.py", line 972, in delete
    res = int(be.deleteRecording(self, force=force))
  File "/usr/lib/python3.8/site-packages/MythTV/mythproto.py", line 668, in deleteRecording
    [command,program.toString()]))
  File "/usr/lib/python3.8/site-packages/MythTV/mythproto.py", line 962, in toString
    return BACKEND_SEP.join(self._deprocess())
  File "/usr/lib/python3.8/site-packages/MythTV/altdict.py", line 178, in _deprocess
    data[i] = self._inv_trans[self._field_type[i]](v)
  File "/usr/lib/python3.8/site-packages/MythTV/altdict.py", line 113, in <lambda>
    lambda x: str(int(x.timestamp())),
  File "/usr/lib/python3.8/site-packages/MythTV/utility/dt.py", line 481, in timestamp
    return ((utc_naive - utc_epoch).total_seconds())
TypeError: can't subtract offset-naive and offset-aware datetimes
 
I don't know python and could use some help from someone.
Full output @ https://pastebin.com/FEXgLzXz

User avatar
paulh
Developer
Posts: 585
Joined: Thu Feb 06, 2014 6:09 pm
Great Britain

Re: Problems deleteing records for files missing ~ find_orphans.py v31

Post by paulh » Fri Oct 23, 2020 6:29 pm

The find_orphans.py script uses the MythTV python bindings that are installed alongside the rest of MythTV.

If Bill is correct then the file that is broken is dt.py that you will find wherever your distro installs the python bindings. For me it's located here :-
/usr/local/lib/python3.8/dist-packages/MythTV/utility/dt.py

The commit is a little confusing because it contains a formatting change but the line you should be looking for is

Code: Select all

utc_naive = utc_naive.replace(tzinfo=None)
if that is missing from dt.py then you don't have the fix.

What full version of MythTV have you installed? That will tell us if it's new enough to have the fix Bill mentioned.

User avatar
keepitsimpleengineer
Junior
Posts: 37
Joined: Fri Oct 03, 2014 9:53 pm
Location: Central California, U.S.A.
Contact:
United States of America

Re: Problems deleteing records for files missing ~ find_orphans.py v31

Post by keepitsimpleengineer » Fri Oct 23, 2020 9:35 pm

paulh wrote:
Fri Oct 23, 2020 6:29 pm
If Bill is correct then the file that is broken is dt.py that you will find wherever your distro installs the python bindings. For me it's located here :-
/usr/local/lib/python3.8/dist-packages/MythTV/utility/dt.py

The commit is a little confusing because it contains a formatting change but the line you should be looking for is

Code: Select all

utc_naive = utc_naive.replace(tzinfo=None)
if that is missing from dt.py then you don't have the fix.

What full version of MythTV have you installed? That will tell us if it's new enough to have the fix Bill mentioned.
Version (from the frontend installed on the same computer with the backend): tag: v31.0 (v31.0-9579662cdcb)

I'm guessing this was around 03-23-2020

Code: Select all

[KISE-055 ~]# less /usr/lib/python3.8/site-packages/MythTV/utility/dt.py | grep 'utc_naive'
         utc_naive = self.replace(tzinfo=None) - self.utcoffset()
         return ((utc_naive - utc_epoch).total_seconds())
The line is missing from my backend. Getting a getting a current version will likely solve to problem.

Thanks for the help 👍

User avatar
paulh
Developer
Posts: 585
Joined: Thu Feb 06, 2014 6:09 pm
Great Britain

Re: Problems deleteing records for files missing ~ find_orphans.py v31

Post by paulh » Fri Oct 23, 2020 10:25 pm

Yes that version is to old to have the fix.

For now you could just get the updated dt.py file from
https://github.com/MythTV/mythtv/blob/f ... lity/dt.py
and replace the old version with the new one.

Post Reply