Example #1
0
    def fromPowerRule(cls,
                      title='unnamed (Power Search)',
                      where='',
                      args=None,
                      join='',
                      db=None,
                      type=RECTYPE.kAllRecord,
                      searchtype=RECSEARCHTYPE.kPowerSearch,
                      wait=False):

        if type not in (RECTYPE.kAllRecord, RECTYPE.kFindDailyRecord,
                        RECTYPE.kFindWeeklyRecord, RECTYPE.kFindOneRecord):
            raise MythDBError("Invalid 'type' set for power recording rule.")

        rec = cls(None, db=db)
        if args is not None:
            where = rec._db.literal(where, args)

        now = datetime.now()
        rec.starttime = now.time()
        rec.endtime = now.time()
        rec.startdate = now.date()
        rec.enddate = now.date()

        rec.title = title
        rec.description = where
        rec.subtitle = join
        rec.type = type
        rec.search = searchtype
        return rec.create(wait=wait)
Example #2
0
    def fromGuide(cls, guide, type=RECTYPE.kAllRecord, wait=False):
        if datetime.now() > guide.endtime:
            raise MythError('Cannot create recording rule for past recording.')
        rec = cls(None, db=guide._db)
        for key in ('chanid','title','subtitle','description', 'category',
                    'seriesid','programid'):
            rec[key] = guide[key]

        rec.startdate = guide.starttime.date()
        rec.starttime = guide.starttime-datetime.combine(rec.startdate, time())
        rec.enddate = guide.endtime.date()
        rec.endtime = guide.endtime-datetime.combine(rec.enddate, time())

        rec.station = Channel(guide.chanid, db=guide._db).callsign
        rec.type = type
        return rec.create(wait=wait)
Example #3
0
    def fromGuide(cls, guide, type=RECTYPE.kAllRecord, wait=False):
        if datetime.now() > guide.endtime:
            raise MythError('Cannot create recording rule for past recording.')
        rec = cls(None, db=guide._db)
        for key in ('chanid','title','subtitle','description', 'category',
                    'seriesid','programid'):
            rec[key] = guide[key]

        rec.startdate = guide.starttime.date()
        rec.starttime = guide.starttime-datetime.combine(rec.startdate, time())
        rec.enddate = guide.endtime.date()
        rec.endtime = guide.endtime-datetime.combine(rec.enddate, time())

        rec.station = Channel(guide.chanid, db=guide._db).callsign
        rec.type = type
        return rec.create(wait=wait)
Example #4
0
    def fromProgram(cls, program, type=RECTYPE.kAllRecord, wait=False):
        if datetime.now() > program.endtime:
            raise MythError('Cannot create recording rule for past recording.')
        rec = cls(None, db=program._db)
        for key in ('chanid','title','subtitle','description','category',
                    'seriesid','programid'):
            rec[key] = program[key]
        rec.station = program.callsign

        rec.startdate = program.starttime.date()
        rec.starttime = program.starttime-datetime.combine(rec.startdate, time())
        rec.enddate = program.endtime.date()
        rec.endtime = program.endtime-datetime.combine(rec.enddate, time())

        if program.recordid:
            rec.parentid = program.recordid
            if program.recstatus == RECTYPE.kNotRecording:
                rec.type = RECTYPE.kOverrideRecord
            else:
                rec.type = RECTYPE.kDontRecord
        else:
            rec.type = type
        return rec.create(wait=wait)
Example #5
0
    def fromProgram(cls, program, type=RECTYPE.kAllRecord, wait=False):
        if datetime.now() > program.endtime:
            raise MythError('Cannot create recording rule for past recording.')
        rec = cls(None, db=program._db)
        for key in ('chanid','title','subtitle','description','category',
                    'seriesid','programid'):
            rec[key] = program[key]
        rec.station = program.callsign

        rec.startdate = program.starttime.date()
        rec.starttime = program.starttime-datetime.combine(rec.startdate, time())
        rec.enddate = program.endtime.date()
        rec.endtime = program.endtime-datetime.combine(rec.enddate, time())

        if program.recordid:
            rec.parentid = program.recordid
            if program.recstatus == RECTYPE.kNotRecording:
                rec.type = RECTYPE.kOverrideRecord
            else:
                rec.type = RECTYPE.kDontRecord
        else:
            rec.type = type
        return rec.create(wait=wait)
Example #6
0
    def fromPowerRule(cls, title='unnamed (Power Search)', where='', args=None, 
                           join='', db=None, type=RECTYPE.kAllRecord, 
                           searchtype=RECSEARCHTYPE.kPowerSearch, wait=False):

        if type not in (RECTYPE.kAllRecord,           RECTYPE.kFindDailyRecord,
                        RECTYPE.kFindWeeklyRecord,    RECTYPE.kFindOneRecord):
            raise MythDBError("Invalid 'type' set for power recording rule.")

        rec = cls(None, db=db)
        if args is not None:
            where = rec._db.literal(where, args)

        now = datetime.now()
        rec.starttime = now.time()
        rec.endtime = now.time()
        rec.startdate = now.date()
        rec.enddate = now.date()

        rec.title = title
        rec.description = where
        rec.subtitle = join
        rec.type = type
        rec.search = searchtype
        return rec.create(wait=wait)
Example #7
0
class Video( CMPVideo, VideoSchema, DBDataWrite ):
    """Video(id=None, db=None, raw=None) -> Video object"""
    _table = 'videometadata'
    _defaults = {'subtitle':u'',             'director':u'Unknown',
                 'rating':u'NR',             'inetref':u'00000000',
                 'year':1895,                'userrating':0.0,
                 'length':0,                 'showlevel':1,
                 'coverfile':u'No Cover',    'host':u'',
                 'homepage':u'',             'insertdate': datetime.now(),
                 'watched':False,            'category':0,
                 'browse':True,              'hash':u'',
                 'season':0,                 'episode':0,
                 'releasedate':date(1,1,1),  'childid':-1}
    _cm_toid, _cm_toname = DictInvertCI.createPair({0:'none'})

    @classmethod
    def _setClassDefs(cls, db=None):
        db = DBCache(db)
        super(Video, cls)._setClassDefs(db)
        cls._fill_cm(db)

    @classmethod
    def _fill_cm(cls, db=None):
        db = DBCache(db)
        with db.cursor() as cursor:
            cursor.execute("""SELECT * FROM videocategory""")
            for row in cursor:
                cls._cm_toname[row[0]] = row[1]

    def _cat_toname(self):
        if self.category is not None:
            try:
                self.category = self._cm_toname[int(self.category)]
            except ValueError:
                # already a named category
                pass
            except KeyError:
                self._fill_cm(self._db)
                if int(self.category) in self._cm_toname:
                    self.category = self._cm_toname[int(self.category)]
                else:
                    raise MythDBError('Video defined with unknown category id')
        else:
            self.category = 'none'

    def _cat_toid(self):
        if self.category is not None:
            try:
                if self.category.lower() not in self._cm_toid:
                    self._fill_cm(self._db)
                if self.category.lower() not in self._cm_toid:
                    with self._db.cursor(self._log) as cursor:
                        cursor.execute("""INSERT INTO videocategory
                                          SET category=%s""",
                                      self.category)
                        self._cm_toid[self.category] = cursor.lastrowid
                self.category = self._cm_toid[self.category]
            except AttributeError:
                # already an integer category
                pass
        else:
            self.category = 0

    def _pull(self):
        DBDataWrite._pull(self)
        self._fill_cm()
        self._cat_toname()

    def _push(self):
        self._cat_toid()
        DBDataWrite._push(self)
        self._cat_toname()
        self.cast.commit()
        self.genre.commit()
        self.country.commit()

    def __repr__(self):
        if self._wheredat is None:
            return u"<Uninitialized Video at %s>" % hex(id(self))
        res = self.title
        if self.season and self.episode:
            res += u' - %dx%02d' % (self.season, self.episode)
        if self.subtitle:
            res += u' - '+self.subtitle
        return u"<Video '%s' at %s>" % (res, hex(id(self)))

    def _postinit(self):
        self._fill_cm()
        self._cat_toname()
        self.cast = self._Cast(self._wheredat, self._db)
        self.genre = self._Genre(self._wheredat, self._db)
        self.country = self._Country(self._wheredat, self._db)
        self.markup = self._Markup((self.filename,), self._db)

    def create(self, data=None):
        """Video.create(data=None) -> Video object"""
        if (self.host is not None) and (self.host != ''):
            # check for pre-existing entry
            if self.hash == '':
                self.hash = self.getHash()
            with self._db as cursor:
                if cursor.execute("""SELECT intid FROM videometadata
                                     WHERE hash=%s""", self.hash) > 0:
                    id = cursor.fetchone()[0]
                    self._evalwheredat([id])
                    self._pull()
                    self._postinit()
                    return self

        # create new entry
        self._import(data)
        self._cat_toid()
        return DBDataWrite._create_autoincrement(self)

    class _Cast( DBDataCRef ):
        _table = ['videometadatacast','videocast']
        _ref = ['idvideo']
        _cref = ['idcast','intid']

    class _Genre( DBDataCRef ):
        _table = ['videometadatagenre','videogenre']
        _ref = ['idvideo']
        _cref = ['idgenre','intid']

    class _Country( DBDataCRef ):
        _table = ['videometadatacountry','videocountry']
        _ref = ['idvideo']
        _cref = ['idcountry','intid']

    class _Markup( DBDataRef, MARKUP ):
        _table = 'filemarkup'
        _ref = ['filename',]

    def delete(self):
        """Video.delete() -> None"""
        if (self._where is None) or \
                (self._wheredat is None):
            return
        self.cast.clean()
        self.genre.clean()
        self.country.clean()
        DBDataWrite.delete(self)

    banner               = Artwork('banner')
    coverfile = coverart = Artwork('coverfile')
    fanart               = Artwork('fanart')
    screenshot           = Artwork('screenshot')
    trailer              = Artwork('trailer')

    def open(self, mode='r', nooverwrite=False):
        return ftopen((self.host, 'Videos', self.filename),
                    mode, False, nooverwrite, self._db)

    def getHash(self):
        """Video.getHash() -> file hash"""
        if self.host is None:
            return None
        be = FileOps(db=self._db)
        hash = be.getHash(self.filename, 'Videos', self.host)
        return hash

    def parseFilename(self):
        filename = self.filename
        filename = filename[:filename.rindex('.')]
        for old in ('%20','_','.'):
            filename = filename.replace(old, ' ')

        sep = '(?:\s?(?:-|/)?\s?)?'
        regex1 = re.compile(
            sep.join(['^(.*[^s0-9])',
                      '(?:s|(?:Season))?',
                      '(\d{1,4})',
                      '(?:[ex/]|Episode)',
                      '(\d{1,3})',
                      '(.*)$']), re.I)

        regex2 = re.compile('(%s(?:Season%s\d*%s)*%s)$' \
                            % (sep, sep, sep, sep), re.I)

        match1 = regex1.search(filename)
        if match1:
            title = match1.group(1)
            season = int(match1.group(2))
            episode = int(match1.group(3))
            subtitle = match1.group(4)

            match2 = regex2.search(title)
            if match2:
                title = title[:match2.start()]
                title = title.rsplit('/',1)[-1]
        else:
            season = None
            episode = None
            subtitle = None
            title = filename.rsplit('/',1)[-1]
            for left,right in (('(',')'), ('[',']'), ('{','}')):
                while left in title:
                    lin = title.index(left)
                    rin = title.index(right,lin)
                    title = title[:lin]+title[rin+1:]
            title = title

        return (title, season, episode, subtitle)

    def importMetadata(self, metadata, overwrite=False):
        """Imports data from a VideoMetadata object."""
        def _allow_change(self, tag, overwrite):
            if overwrite: return True
            if self[tag] is None: return True
            if self[tag] == '': return True
            if tag in self._defaults:
                if self[tag] == self._defaults[tag]:
                    return True
            return False

        # only operate on existing entries
        if self._wheredat is None:
            return

        # pull direct tags
        for tag in ('title', 'subtitle', 'tagline', 'season', 'episode',
                    'inetref', 'homepage', 'trailer', 'userrating', 'year',
                    'releasedate'):
            if metadata[tag] and _allow_change(self, tag, overwrite):
                self[tag] = metadata[tag]

        # pull tags needing renaming
        for tagf,tagt in (('description','plot'), ('runtime','length')):
            if metadata[tagf] and _allow_change(self, tagt, overwrite):
                self[tagt] = metadata[tagf]

        # pull director
        try:
            if _allow_change(self, 'director', overwrite):
                self.director = [person.name for person in metadata.people \
                                            if person.job=='Director'].pop(0)
        except IndexError: pass

        # pull actors
        for actor in [person for person in metadata.people \
                                  if person.job=='Actor']:
            self.cast.add(unicode(actor.name))

        # pull genres
        for category in metadata.categories:
            self.genre.add(unicode(category))

        # pull images (SG content only)
        if bool(self.host):
            for image in metadata.images:
                if not hasattr(self, image.type):
                    continue
                current = getattr(self, image.type)
                if current and (current != 'No Cover') and not overwrite:
                    continue
                setattr(self, image.type, image.filename)
                getattr(self, image.type).downloadFrom(image.url)

        self.processed = True
        self.update()

    def exportMetadata(self):
        """Exports data to a VideoMetadata object."""
        # only work on entries from the database
        if self._wheredat is None:
            return
        metadata = VideoMetadata()

        # pull direct tags
        for tag in ('title', 'subtitle', 'tagline', 'season', 'episode',
                    'inetref', 'homepage', 'trailer', 'userrating', 'year',
                    'releasedate'):
            if self[tag]:
                metadata[tag] = self[tag]

        # pull translated tags
        for tagf, tagt in (('plot', 'description'), ('length', 'runtime')):
            if self[tagf]:
                metadata[tagt] = self[tagf]

        # pull director
        if self.director:
            metadata.people.append(OrdDict((('name',self.director), ('job','Director'))))

        # pull actors
        for actor in self.cast:
            metadata.people.append(OrdDict((('name',actor.cast), ('job','Actor'))))

        # pull genres
        for genre in self.genre:
            metadata.categories.append(genre.genre)

        # pull countries
        for country in self.country:
            metadata.countries.append(country.country)

        # pull images
#        for arttype in ['coverart', 'fanart', 'banner', 'screenshot']:
#            art = getattr(self, arttype)
#            if art:
#                metadata.images.append(OrdDict((('type',arttype), ('filename',art))))

        return metadata

    def __getstate__(self):
        data = DBDataWrite.__getstate__(self)
        data['cast'] = self.cast._picklelist()
        data['genre'] = self.genre._picklelist()
        data['markup'] = self.markup._picklelist()
        data['country'] = self.country._picklelist()
        return data

    def __setstate__(self, state):
        DBDataWrite.__setstate__(self, state)
        if self._wheredat is not None:
            self.cast._populate(data=state['cast'])
            self.genre._populate(data=state['genre'])
            self.markup._populate(data=state['markup'])
            self.country._populate(data=state['country'])

    @classmethod
    def fromFilename(cls, filename, db=None):
        vid = cls(db=db)
        vid.filename = filename
        vid.title, vid.season, vid.episode, vid.subtitle = \
                        vid.parseFilename()
        return vid

    def _playOnFe(self, fe):
        return fe.send('play','file myth://Videos@%s/%s' % 
                    (self.host, self.filename))

    #### LEGACY ####
    # of course this will likely all get scrapped for 0.26...
    def openBanner(self, mode='r', nooverwrite=False):
        return self.banner.open(mode)
    def openCoverart(self, mode='r', nooverwrite=False):
        return self.coverfile.open(mode)
    def openFanart(self, mode='r', nooverwrite=False):
        return self.fanart.open(mode)
    def openScreenshot(self, mode='r', nooverwrite=False):
        return self.screenshot.open(mode)
    def openTrailer(self, mode='r', nooverwrite=False):
        return self.trailer.open(mode)
Example #8
0
class Job( DBDataWrite, JOBTYPE, JOBCMD, JOBFLAG, JOBSTATUS ):
    """
    Job(id=None, db=None) -> Job object
    """
    _table = 'jobqueue'
    _logmodule = 'Python Jobqueue'
    _defaults = {'id':None,     'inserttime':datetime.now(),
                 'hostname':'', 'status':JOBSTATUS.QUEUED,
                 'comment':'',  'schedruntime':datetime.now()}

    def __str__(self):
        if self._wheredat is None:
            return u"<Uninitialized Job at %s>" % hex(id(self))
        return u"<Job '%s' at %s>" % (self.id, hex(id(self)))

    def __repr__(self):
        return str(self).encode('utf-8')

    def setComment(self,comment):
        """Job.setComment(comment) -> None, updates comment"""
        self.comment = comment
        self.update()

    def setStatus(self,status):
        """Job.setStatus(Status) -> None, updates status"""
        self.status = status
        self.update()

    @classmethod
    def fromRecorded(cls, rec, type, status=None, schedruntime=None,
                               hostname=None, args=None, flags=None):
        job = cls(db=rec._db)
        job.type = type
        job.chanid = rec.chanid
        job.starttime = rec.starttime
        if status:
            job.status = status
        if schedruntime:
            job.schedruntime = schedruntime
        if hostname:
            job.hostname = hostname
        if args:
            job.args = args
        if flags:
            job.flags = flags
        job.create()

    @classmethod
    def fromProgram(cls, prog, type, status=None, schedruntime=None,
                                hostname=None, args=None, flags=None):
        if prog.rectype != prog.rsRecorded:
            raise MythError('Invalid recording type for Job.')
        job = cls(db=prog._db)
        job.type = type
        job.chanid = prog.chanid
        job.starttime = prog.recstartts
        if status:
            job.status = status
        if schedruntime:
            job.schedruntime = schedruntime
        if hostname:
            job.hostname = hostname
        if args:
            job.args = args
        if flags:
            job.flags = flags
        job.create()