Ticket #6678: pyth.update6.patch

File pyth.update6.patch, 13.7 KB (added by Raymond Wagner <raymond@…>, 15 years ago)
  • mythtv/bindings/python/MythTV/MythTV.py

     
    1414import socket
    1515import code
    1616from datetime import datetime
     17from time import mktime
    1718
    1819from MythDB import *
    1920from MythLog import *
     
    9596                        try:
    9697                                length = int(data)
    9798                        except:
    98                                 return ''
     99                                return u''
    99100                        data = []
    100101                        while length > 0:
    101102                                chunk = self.socket.recv(length)
    102103                                length = length - len(chunk)
    103104                                data.append(chunk)
    104                         return ''.join(data)
     105                        return u''.join(data)
    105106
    106                 command = '%-8d%s' % (len(data), data)
     107                command = u'%-8d%s' % (len(data), data)
    107108                log.Msg(DEBUG, 'Sending command: %s', command)
    108109                self.socket.send(command)
    109110                return recv()
     
    120121                for i in range(num_progs):
    121122                        programs.append(Program(res[i * PROGRAM_FIELDS:(i * PROGRAM_FIELDS)
    122123                                + PROGRAM_FIELDS]))
    123                 return programs
     124                return tuple(programs)
    124125
    125126        def getScheduledRecordings(self):
    126127                """
     
    133134                for i in range(num_progs):
    134135                        programs.append(Program(res[i * PROGRAM_FIELDS:(i * PROGRAM_FIELDS)
    135136                                + PROGRAM_FIELDS]))
    136                 return programs
     137                return tuple(programs)
    137138
    138139        def getUpcomingRecordings(self):
    139140                """
     
    155156                        if p.recstatus == RECSTATUS['WillRecord']:
    156157                                programs.append(p)
    157158                programs.sort(sort_programs_by_starttime)
    158                 return programs
     159                return tuple(programs)
    159160
    160161        def getRecorderList(self):
    161162                """
    162163                Returns a list of recorders, or an empty list if none.
    163164                """
    164165                recorders = []
    165                 c = self.db.cursor()
     166                pc = self.db.cursor()
    166167                c.execute('SELECT cardid FROM capturecard')
    167168                row = c.fetchone()
    168169                while row is not None:
     
    220221                else:
    221222                        return False
    222223
     224        def getRecording(self, chanid, starttime):
     225                """
     226                Returns a Program object matching the channel id and start time
     227                """
     228                res = self.backendCommand('QUERY_RECORDING TIMESLOT %d %d' % (chanid, starttime)).split(BACKEND_SEP)
     229                if res[0] == 'ERROR':
     230                        return None
     231                else:
     232                        return Program(res[1:])
     233
     234        def getRecordings(self):
     235                """
     236                Returns a list of all Program objects which have already recorded
     237                """
     238                programs = []
     239                res = self.backendCommand('QUERY_RECORDINGS Play').split('[]:[]')
     240                num_progs = int(res.pop(0))
     241                log.Msg(DEBUG, '%s total recordings', num_progs)
     242                for i in range(num_progs):
     243                        programs.append(Program(res[i * PROGRAM_FIELDS:(i * PROGRAM_FIELDS)
     244                                + PROGRAM_FIELDS]))
     245                return tuple(programs)
     246
     247        def getCheckfile(self,program):
     248                """
     249                Returns location of recording in file system
     250                """
     251                res = self.backendCommand('QUERY_CHECKFILE[]:[]1[]:[]%s' % program.toString()).split(BACKEND_SEP)
     252                if res[0] == 0:
     253                        return None
     254                else:
     255                        return res[1]
     256
     257        def getFrontends(self):
     258                """
     259                Returns a list of Frontend objects for accessible frontends
     260                """
     261                cursor = self.db.db.cursor()
     262                cursor.execute("SELECT DISTINCT hostname FROM settings WHERE hostname IS NOT NULL and value='NetworkControlEnabled' and data=1")
     263                frontends = []
     264                for fehost in cursor.fetchall():
     265                        try:
     266                                frontend = self.getFrontend(fehost[0])
     267                                frontends.append(frontend)
     268                        except:
     269                                print "%s is not a valid frontend" % fehost[0]
     270                cursor.close()
     271                return frontends
     272
     273        def getFrontend(self,host):
     274                """
     275                Returns a Frontend object for the specified host
     276                """
     277                port = self.db.getSetting("NetworkControlPort",host)
     278                return Frontend(host,port)
     279
     280class Frontend:
     281        isConnected = False
     282        socket = None
     283        host = None
     284        port = None
     285
     286        def __init__(self, host, port):
     287                self.host = host
     288                self.port = int(port)
     289                self.connect()
     290                self.disconnect()
     291
     292        def __del__(self):
     293                if self.isConnected:
     294                        self.disconnect()
     295
     296        def __repr__(self):
     297                return "%s@%d" % (self.host, self.port)
     298
     299        def __str__(self):
     300                return "%s@%d" % (self.host, self.port)
     301
     302        def connect(self):
     303                self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     304                self.socket.settimeout(10)
     305                self.socket.connect((self.host, self.port))
     306                if self.recv()[:28] != "MythFrontend Network Control":
     307                        self.socket.close()
     308                        self.socket = None
     309                        raise Exception('FrontendConnect','Connected socket does not belong to a mythfrontend')
     310                self.isConnected = True
     311
     312        def disconnect(self):
     313                self.send("exit")
     314                self.socket.close()
     315                self.socket = None
     316                self.isConnected = False
     317
     318        def send(self,command):
     319                if not self.isConnected:
     320                        self.connect()
     321                self.socket.send("%s\n" % command)
     322
     323        def recv(self,curstr=""):
     324                def subrecv(self,curstr=""):
     325                        try:
     326                                curstr += self.socket.recv(100)
     327                        except:
     328                                return None
     329                        if curstr[-4:] != '\r\n# ':
     330                                curstr = subrecv(self,curstr)
     331                        return curstr
     332                return subrecv(self)[:-4]
     333
     334        def sendJump(self,jumppoint):
     335                """
     336                Sends jumppoint to frontend
     337                """
     338                self.send("jump %s" % jumppoint)
     339                if self.recv() == 'OK':
     340                        return 0
     341                else:
     342                        return 1
     343
     344        def getJump(self):
     345                """
     346                Returns a tuple containing available jumppoints
     347                """
     348                self.send("help jump")
     349                res = self.recv().split('\r\n')[3:-1]
     350                points = []
     351                for point in res:
     352                        spoint = point.split(' - ')
     353                        points.append((spoint[0].rstrip(),spoint[1]))
     354                return tuple(points)
     355
     356        def sendKey(self,key):
     357                """
     358                Sends keycode to connected frontend
     359                """
     360                self.send("key %s" % key)
     361                if self.recv() == 'OK':
     362                        return 0
     363                else:
     364                        return 1
     365
     366        def getKey(self):
     367                """
     368                Returns a tuple containing available special keys
     369                """
     370                self.send("help key")
     371                res = self.recv().split('\r\n')[4]
     372                keys = []
     373                for key in res.split(','):
     374                        keys.append(key.strip())
     375                return tuple(keys)
     376
     377        def sendQuery(self,query):
     378                """
     379                Returns query from connected frontend
     380                """
     381                self.send("query %s" % query)
     382                return self.recv()
     383
     384        def getQuery(self):
     385                """
     386                Returns a tuple containing available queries
     387                """
     388                self.send("help query")
     389                res = self.recv().split('\r\n')[:-1]
     390                queries = []
     391                tmpstr = ""
     392                for query in res:
     393                        tmpstr += query
     394                        squery = tmpstr.split(' - ')
     395                        if len(squery) == 2:
     396                                tmpstr = ""
     397                                queries.append((squery[0].rstrip().lstrip('query '),squery[1]))
     398                return tuple(queries)
     399
     400        def sendPlay(self,play):
     401                """
     402                Send playback command to connected frontend
     403                """
     404                self.send("play %s" % play)
     405                if self.recv() == 'OK':
     406                        return 0
     407                else:
     408                        return 1
     409
     410        def getPlay(self):
     411                """
     412                Returns a tuple containing available playback commands
     413                """
     414                self.send("help play")
     415                res = self.recv().split('\r\n')[:-1]
     416                plays = []
     417                tmpstr = ""
     418                for play in res:
     419                        tmpstr += play
     420                        splay = tmpstr.split(' - ')
     421                        if len(splay) == 2:
     422                                tmpstr = ""
     423                                plays.append((splay[0].rstrip().lstrip('play '),splay[1]))
     424                return tuple(plays)
     425                       
     426               
     427
    223428class Recorder:
    224429        """
    225430        Represents a MythTV capture card.
     
    265470                self.callsign = data[6] #chansign
    266471                self.channame = data[7]
    267472                self.filename = data[8] #pathname
    268                 self.fs_high = data[9]
    269                 self.fs_low = data[10]
     473                self.fs_high = int(data[9])
     474                self.fs_low = int(data[10])
    270475                self.starttime = datetime.fromtimestamp(int(data[11])) # startts
    271476                self.endtime = datetime.fromtimestamp(int(data[12])) #endts
    272477                self.duplicate = int(data[13])
     
    303508                self.video_props = data[44]
    304509                self.subtitle_type = data[45]
    305510                self.year = data[46]
     511               
     512                self.filesize = (self.fs_high + (self.fs_low<0))*2**32 + self.fs_low
    306513
     514        def toString(self):
     515                string =            self.title
     516                string += BACKEND_SEP + self.subtitle
     517                string += BACKEND_SEP + self.description
     518                string += BACKEND_SEP + self.category
     519                if self.chanid:
     520                        string += BACKEND_SEP + str(self.chanid)
     521                else:
     522                        string += BACKEND_SEP
     523                string += BACKEND_SEP + self.channum
     524                string += BACKEND_SEP + self.callsign
     525                string += BACKEND_SEP + self.channame
     526                string += BACKEND_SEP + self.filename
     527                string += BACKEND_SEP + str(self.fs_high)
     528                string += BACKEND_SEP + str(self.fs_low)
     529                string += BACKEND_SEP + str(int(mktime(self.starttime.timetuple())))
     530                string += BACKEND_SEP + str(int(mktime(self.endtime.timetuple())))
     531                string += BACKEND_SEP + str(self.duplicate)
     532                string += BACKEND_SEP + str(self.shareable)
     533                string += BACKEND_SEP + str(self.findid)
     534                string += BACKEND_SEP + self.hostname
     535                string += BACKEND_SEP + str(self.sourceid)
     536                string += BACKEND_SEP + str(self.cardid)
     537                string += BACKEND_SEP + str(self.inputid)
     538                string += BACKEND_SEP + str(self.recpriority)
     539                string += BACKEND_SEP + str(self.recstatus)
     540                string += BACKEND_SEP + str(self.recordid)
     541                string += BACKEND_SEP + self.rectype
     542                string += BACKEND_SEP + self.dupin
     543                string += BACKEND_SEP + self.dupmethod
     544                string += BACKEND_SEP + str(int(mktime(self.recstartts.timetuple())))
     545                string += BACKEND_SEP + str(int(mktime(self.recendts.timetuple())))
     546                string += BACKEND_SEP + str(self.repeat)
     547                string += BACKEND_SEP + self.programflags
     548                string += BACKEND_SEP + self.recgroup
     549                string += BACKEND_SEP + str(self.commfree)
     550                string += BACKEND_SEP + self.outputfilters
     551                string += BACKEND_SEP + self.seriesid
     552                string += BACKEND_SEP + self.programid
     553                string += BACKEND_SEP + self.lastmodified
     554                string += BACKEND_SEP + str(self.stars)
     555                string += BACKEND_SEP + self.airdate
     556                string += BACKEND_SEP + str(self.hasairdate)
     557                string += BACKEND_SEP + self.playgroup
     558                string += BACKEND_SEP + str(self.recpriority2)
     559                string += BACKEND_SEP + self.parentid
     560                string += BACKEND_SEP + self.storagegroup
     561                string += BACKEND_SEP + self.audio_props
     562                string += BACKEND_SEP + self.video_props
     563                string += BACKEND_SEP + self.subtitle_type
     564                string += BACKEND_SEP + self.year
     565
     566                return string
     567
    307568if __name__ == '__main__':
    308569        banner = '\'m\' is a MythTV instance.'
    309570        try:
  • mythtv/bindings/python/MythTV/MythDB.py

     
    160160                else:
    161161                        return None
    162162
     163        def setSetting(self, value, data, hostname=None):
     164                """
     165                Sets the value for the given MythTV setting.
     166                """
     167                log.Msg(DEBUG, 'Setting %s for host %s to %s', value, hostname, data)
     168                c = self.db.cursor()
     169                ws = None
     170                ss = None
     171
     172                if hostname is None:
     173                        ws = "WHERE value LIKE ('%s') AND hostname IS NULL" % (value)
     174                        ss = "(value,data) VALUES ('%s','%s')" % (value, data)
     175                else:
     176                        ws = "WHERE value LIKE ('%s') AND hostname LIKE ('%s%%')" % (value, hostname)
     177                        ss = "(value,data,hostname) VALUES ('%s','%s','%s')" % (value, data, hostname)
     178
     179                if c.execute("""UPDATE settings SET data %s LIMIT 1""" % ws) == 0:
     180                        c.execute("""INSERT INTO settings %s""" % ss)
     181                c.close()
     182
     183        def getCast(self, chanid, starttime, roles=None):
     184                """
     185                Returns cast members for a recording
     186                A string for 'roles' will return a tuple of members for that role
     187                A tuple of strings will return a touple containing all listed roles
     188                No 'roles' will return a dictionary of tuples
     189                """
     190                if roles is None:
     191                        c = self.db.cursor()
     192                        length = c.execute("SELECT name,role FROM people,credits WHERE people.person=credits.person AND chanid=%d AND starttime=%d ORDER BY role" % (chanid, starttime))
     193                        if length == 0:
     194                                return ()
     195                        crole = None
     196                        clist = []
     197                        dict = {}
     198                        for name,role in c.fetchall():
     199                                if crole is None:
     200                                        crole = role
     201                                if crole == role:
     202                                        clist.append(name)
     203                                else:
     204                                        dict[crole] = tuple(clist)
     205                                        clist = []
     206                                        clist.append(name)
     207                                        crole = role
     208                        dict[crole] = tuple(clist)
     209                        c.close()
     210                        return dict
     211                elif isinstance(roles,str):
     212                        c = self.db.cursor()
     213                        length = c.execute("SELECT name FROM people,credits WHERE people.person=credits.person AND chanid=%d AND starttime=%d AND role='%s'" % (chanid, starttime, roles))
     214                        if length == 0:
     215                                return ()
     216                        names = []
     217                        for name in c.fetchall():
     218                                names.append(name[0])
     219                        return tuple(names)
     220                elif isinstance(roles,tuple):
     221                        c = self.db.cursor()
     222                        length = c.execute("SELECT name FROM people,credits WHERE people.person=credits.person AND chanid=%d AND starttime=%d AND role IN %s" % (chanid, starttime, roles))
     223                        if length == 0:
     224                                return ()
     225                        names = []
     226                        for name in c.fetchall():
     227                                names.append(name[0])
     228                        return tuple(names)
     229
    163230        def cursor(self):
    164231                return self.db.cursor()
    165232
     233class Job:
     234        jobid = None
     235        chanid = None
     236        starttime = None
     237        host = None
     238        mythdb = None
     239        def __init__(self, *inp):
     240                if len(inp) == 1:
     241                        self.jobid = inp[0]
     242                        self.getProgram()
     243                elif len(inp) == 2:
     244                        self.chanid = inp[0]
     245                        self.starttime = inp[1]
     246                        self.getJobID()
     247                else:
     248                        print("improper input length")
     249                        return None
     250                self.getHost()
     251
     252        def getProgram(self):
     253                if self.mythdb is None:
     254                        self.mythdb = MythDB()
     255                c = self.mythdb.cursor()
     256                c.execute("SELECT chanid,starttime FROM jobqueue WHERE id=%d" % self.jobid)
     257                self.chanid, self.starttime = c.fetchone()
     258                c.close()
     259
     260        def getJobID(self):
     261                if self.mythdb is None:
     262                        self.mythdb = MythDB()
     263                if self.jobid is None:
     264                        c = self.mythdb.cursor()
     265                        c.execute("SELECT id FROM jobqueue WHERE chanid=%d AND starttime=%d" % (self.chanid, self.starttime))
     266                        self.jobid = c.fetchone()[0]
     267                        c.close()
     268                return self.jobid
     269
     270        def getHost(self):
     271                if self.mythdb is None:
     272                        self.mythdb = MythDB()
     273                if self.host is None:
     274                        c = self.mythdb.cursor()
     275                        c.execute("SELECT hostname FROM jobqueue WHERE id=%d" % self.jobid)
     276                        self.host = c.fetchone()[0]
     277                        c.close()
     278                return self.host
     279
     280        def setComment(self,comment):
     281                if self.mythdb is None:
     282                        self.mythdb = MythDB()
     283                c = self.mythdb.cursor()
     284                c.execute("UPDATE jobqueue SET comment='%s' WHERE id=%d" % (comment,self.jobid))
     285                c.close()
     286
     287        def setStatus(self,status):
     288                if self.mythdb is None:
     289                        self.mythdb = MythDB()
     290                c = self.mythdb.cursor()
     291                c.execute("UPDATE jobqueue SET status=%d WHERE id=%d" % (status,self.jobid))
     292                c.close()
     293
    166294if __name__ == '__main__':
    167295        banner = "'mdb' is a MythDB instance."
    168296        try: