Beispiel #1
0
    def _process_source(self, source, method_name, file_path):
        remove_file(file_path)

        path = source.path.strip()
        source_type = source.source_type
        archive_type = source.archive_type

        if source_type == Source.TYPE_ADDON:
            addon_id = path
            addon, data = merge_info(addon_id, self.integrations, merging=True)

            if method_name not in data:
                raise Error('{} could not be found for {}'.format(
                    method_name, addon_id))

            template_tags = {
                '$ID': addon_id,
                '$FILE': file_path,
                '$IP': xbmc.getIPAddress(),
            }

            path = data[method_name]
            for tag in template_tags:
                path = path.replace(tag, template_tags[tag])

            path = path.strip()
            if path.lower().startswith('plugin'):
                self._call_addon_method(path)
                return

            if path.lower().startswith('http'):
                source_type = Source.TYPE_URL
            else:
                source_type = Source.TYPE_FILE

            archive_extensions = {
                '.gz': Source.ARCHIVE_GZIP,
                '.xz': Source.ARCHIVE_XZ,
            }

            name, ext = os.path.splitext(path.lower())
            archive_type = archive_extensions.get(ext, Source.ARCHIVE_NONE)

        if source_type == Source.TYPE_URL and path.lower().startswith('http'):
            log.debug('Downloading: {} > {}'.format(path, file_path))
            Session().chunked_dl(path, file_path)
        elif not xbmcvfs.exists(path):
            raise Error(_(_.LOCAL_PATH_MISSING, path=path))
        else:
            log.debug('Copying local file: {} > {}'.format(path, file_path))
            xbmcvfs.copy(path, file_path)

        if archive_type == Source.ARCHIVE_GZIP:
            gzip_extract(file_path)
        elif archive_type == Source.ARCHIVE_XZ:
            xz_extract(file_path)
Beispiel #2
0
def race(slug, **kwargs):
    races = api.races()
    if slug not in races:
        raise Error(_.RACE_NOT_FOUND)

    race = races[slug]
    folder = plugin.Folder(race['title'], no_items_label=_.NO_STREAMS)

    for stream in race['streams']:
        if not stream['slug']:
            continue

        item = plugin.Item(
            label = stream['label'],
            path  = plugin.url_for(play, slug=stream['slug']),
            playable = True,
        )

        if stream['live']:
            item.label = _(_.LIVE_LABEL, title=stream['label'])

            item.context.append((_.PLAY_FROM_LIVE, "PlayMedia({})".format(
                plugin.url_for(play, slug=stream['slug'], play_type=PLAY_FROM_LIVE, _is_live=True)
            )))

            item.context.append((_.PLAY_FROM_START, "PlayMedia({})".format(
                plugin.url_for(play, slug=stream['slug'], play_type=PLAY_FROM_START, _is_live=True)
            )))

            item.path = plugin.url_for(play, slug=stream['slug'], play_type=settings.getEnum('live_play_type', PLAY_FROM_TYPES, PLAY_FROM_ASK), _is_live=True)

        folder.add_items([item])

    return folder
def merge_info(addon_id, merging=False):
    addon = get_addon(addon_id, required=True, install=False)
    addon_path = xbmc.translatePath(addon.getAddonInfo('path'))
    merge_path = os.path.join(addon_path, MERGE_SETTING_FILE)

    data = {}
    if os.path.exists(merge_path):
        try:
            with codecs.open(merge_path, 'r', encoding='utf8') as f:
                data = json.load(f)
                data['type'] = TYPE_IPTV_MERGE
        except Exception as e:
            log.exception(e)
            log.debug('failed to parse merge file: {}'.format(merge_path))
            return addon, {}

    elif addon.getSetting('iptv.enabled'):
        data = {
            'type': TYPE_IPTV_MANAGER,
            'playlist': addon.getSetting('iptv.channels_uri'),
            'epg': addon.getSetting('iptv.epg_uri'),
        }

    elif addon_id.lower() in INTEGRATIONS:
        data = INTEGRATIONS[addon_id.lower()]
        data['type'] = TYPE_INTEGRATION

    elif merging:
        raise Error('No integration found for this source')

    min_version = data.get('min_version')
    max_version = data.get('max_version')
    current_version = LooseVersion(addon.getAddonInfo('version'))

    if min_version and current_version < LooseVersion(min_version):
        if merging:
            raise Error('Min version {} required'.format(min_version))
        else:
            data = {}

    if max_version and current_version > LooseVersion(max_version):
        if merging:
            raise Error('Max version {} exceeded'.format(max_version))
        else:
            data = {}

    return addon, data
Beispiel #4
0
def install_xbian():
    password = gui.input(_.XBIAN_PASSWORD, default='raspberry')
    sudo_cmd = 'echo "{}" | sudo -S su -c "{{}}"'.format(password)

    try:
        install_debian(sudo_cmd, 'xbian')
    except Exception as e:
        log.exception(e)
        raise Error(_.XBIAN_ERROR)
Beispiel #5
0
def merge_info(addon_id, integrations=None, merging=False):
    addon = get_addon(addon_id, required=True, install=False)
    addon_path = xbmc.translatePath(addon.getAddonInfo('path'))
    merge_path = os.path.join(addon_path, MERGE_SETTING_FILE)

    if os.path.exists(merge_path):
        try:
            with codecs.open(merge_path, 'r', encoding='utf8') as f:
                data = json.load(f)
        except Exception as e:
            log.exception(e)
            log.debug('failed to parse merge file: {}'.format(merge_path))
            return addon, {}
    else:
        if integrations is None:
            integrations = get_integrations()

        data = integrations.get(addon_id) or {}

        if merging:
            if not integrations:
                raise Error('Failed to download integrations')

            elif not data:
                raise Error('No integration found for this source')

    min_version = data.get('min_version')
    max_version = data.get('max_version')
    current_version = LooseVersion(addon.getAddonInfo('version'))

    if min_version and current_version < LooseVersion(min_version):
        if merging:
            raise Error('Min version {} required'.format(min_version))
        else:
            data = {}

    if max_version and current_version > LooseVersion(max_version):
        if merging:
            raise Error('Max version {} exceeded'.format(max_version))
        else:
            data = {}

    return addon, data
    def select_path(self, creating=False):
        try:
            default = self.TYPES.index(self.source_type)
        except:
            default = -1

        index = gui.select(_.SELECT_SOURCE_TYPE,
                           [self.TYPE_LABELS[x] for x in self.TYPES],
                           preselect=default)
        if index < 0:
            return False

        orig_source_type = self.source_type
        self.source_type = self.TYPES[index]

        if self.source_type == self.TYPE_ADDON:
            addons = self.get_addon_sources()
            if not addons:
                raise Error(_.NO_SOURCE_ADDONS)

            options = []
            default = -1
            addons.sort(key=lambda x: x[0].getAddonInfo('name').lower())

            for idx, row in enumerate(addons):
                options.append(
                    plugin.Item(label=row[0].getAddonInfo('name'),
                                art={'thumb': row[0].getAddonInfo('icon')}))
                if orig_source_type == self.TYPE_ADDON and row[0].getAddonInfo(
                        'id') == self.path:
                    default = idx

            index = gui.select(_.SELECT_SOURCE_ADDON,
                               options,
                               preselect=default,
                               useDetails=True)
            if index < 0:
                return False

            addon, data = addons[index]
            self.path = addon.getAddonInfo('id')
        elif self.source_type == self.TYPE_URL:
            self.path = gui.input(_.ENTER_SOURCE_URL,
                                  default=self.path if orig_source_type
                                  == self.TYPE_URL else '').strip()
        elif self.source_type == self.TYPE_FILE:
            self.path = xbmcgui.Dialog().browseSingle(
                1,
                _.SELECT_SOURCE_FILE,
                '',
                '',
                defaultt=self.path
                if orig_source_type == self.TYPE_FILE else '')
        elif self.source_type == self.TYPE_CUSTOM:
            self.path = gui.input('Custom Name',
                                  default=self.path if orig_source_type
                                  == self.TYPE_CUSTOM else '').strip()

        if not self.path:
            return False

        self.save()

        if self.source_type == self.TYPE_ADDON:
            if creating:
                if self.__class__ == Playlist and METHOD_EPG in data:
                    epg = EPG(source_type=EPG.TYPE_ADDON, path=self.path)
                    try:
                        epg.save()
                    except:
                        pass

                elif self.__class__ == EPG and METHOD_PLAYLIST in data:
                    playlist = Playlist(source_type=Playlist.TYPE_ADDON,
                                        path=self.path)
                    try:
                        playlist.save()
                    except:
                        pass

            for key in data.get('settings', {}):
                value = data['settings'][key].replace('$ID', self.path)
                log.debug('Set setting {}={} for addon {}'.format(
                    key, value, self.path))
                addon.setSetting(key, value)

            if 'configure' in data:
                path = data['configure'].replace('$ID', self.path)
                run_plugin(path, wait=True)

        return True
 def save(self, *args, **kwargs):
     try:
         super(Source, self).save(*args, **kwargs)
     except peewee.IntegrityError as e:
         raise Error(_.SOURCE_EXISTS)
    def _process_playlist(self, playlist, file_path):
        channel = None
        to_create = set()
        slugs = set()
        added_count = 0

        Channel.delete().where(Channel.playlist == playlist).execute()

        if playlist.use_start_chno:
            chnos = {'tv': playlist.start_chno, 'radio': playlist.start_chno}

        if not self._is_troll:
            for troll in TROLLS:
                if troll.lower() in playlist.path.lower():
                    self._is_troll = True
                    break

        valid_file = False
        default_attribs = {}

        with codecs.open(file_path, 'r', encoding='utf8',
                         errors='replace') as infile:
            for line in infile:
                line = line.strip()

                if not line:
                    continue

                if not self._is_troll:
                    for troll in TROLLS:
                        if troll.lower() in line.lower():
                            self._is_troll = True
                            break

                if not valid_file and '#EXTM3U' not in line:
                    raise Error(
                        'Invalid playlist - Does not start with #EXTM3U')

                if '#EXTM3U' in line:
                    valid_file = True

                    #if not playlist.ignore_playlist_epg:
                    attribs = {}
                    for key, value in re.findall('([\w-]+)="([^"]*)"', line):
                        attribs[key] = value.strip()

                    xml_urls = attribs.get('x-tvg-url', '').split(',')
                    xml_urls.extend(attribs.get('url-tvg', '').split(','))

                    for url in xml_urls:
                        url = url.strip()
                        if url:
                            self._playlist_epgs.append(url)

                    if 'tvg-shift' in attribs:
                        default_attribs['tvg-shift'] = attribs['tvg-shift']
                    if 'catchup-correction' in attribs:
                        default_attribs['catchup-correction'] = attribs[
                            'catchup-correction']

                if line.startswith('#EXTINF'):
                    channel = Channel.from_playlist(line)
                    for key in default_attribs:
                        if key not in channel.attribs:
                            channel.attribs[key] = default_attribs[key]

                elif not channel:
                    continue

                if line.startswith('#EXTGRP'):
                    value = line.split(':', 1)[1].strip()
                    if value:
                        channel.groups.extend(value.split(';'))

                elif line.startswith('#KODIPROP') or line.startswith(
                        '#EXTVLCOPT'):
                    value = line.split(':', 1)[1].strip()
                    if value and '=' in value:
                        key, value = value.split('=', 1)
                        channel.properties[key] = value

                elif line.startswith('#EXT-X-PLAYLIST-TYPE'):
                    value = line.split(':', 1)[1].strip()
                    if value and value.upper() == 'VOD':
                        channel.is_live = False

                elif not line.startswith('#'):
                    channel.url = line
                    if not channel.url:
                        channel = None
                        continue

                    channel.playlist = playlist

                    if playlist.skip_playlist_groups:
                        channel.groups = []

                    if playlist.group_name:
                        channel.groups.extend(playlist.group_name.split(';'))

                    if playlist.skip_playlist_chno:
                        channel.chno = None

                    if playlist.use_start_chno:
                        if channel.radio:
                            if channel.chno is None:
                                channel.chno = chnos['radio']

                            chnos['radio'] = channel.chno + 1
                        else:
                            if channel.chno is None:
                                channel.chno = chnos['tv']

                            chnos['tv'] = channel.chno + 1

                    if self._is_troll:
                        channel.url = TROLL_URL
                        channel.name = TROLL_NAME

                    channel.groups = [x for x in channel.groups if x.strip()]
                    channel.visible = playlist.default_visible
                    channel.slug = slug = '{}.{}'.format(
                        playlist.id,
                        hash_6(channel.epg_id or channel.url.lower().strip()))
                    channel.order = added_count + 1

                    count = 1
                    while channel.slug in slugs:
                        channel.slug = '{}.{}'.format(slug, count)
                        count += 1

                    slugs.add(channel.slug)
                    to_create.add(channel)

                    if Channel.bulk_create_lazy(to_create):
                        to_create.clear()

                    channel = None
                    added_count += 1

        if not valid_file:
            raise Error('Invalid playlist - Does not start with #EXTM3U')

        Channel.bulk_create_lazy(to_create, force=True)
        to_create.clear()
        slugs.clear()

        return added_count
    def _process_source(self, source, method_name, file_path):
        remove_file(file_path)

        path = source.path.strip()
        source_type = source.source_type
        archive_type = source.archive_type
        self._is_troll = False

        if source_type == Source.TYPE_ADDON:
            addon_id = path
            addon, data = merge_info(addon_id, merging=True)

            if method_name not in data:
                raise Error('{} could not be found for {}'.format(
                    method_name, addon_id))

            path = data[method_name]

            if data['type'] == TYPE_IPTV_MANAGER:
                iptv_manager.process_path(path, file_path)
                return

            template_tags = {
                '$ID': addon_id,
                '$FILE': file_path,
                '$IP': xbmc.getIPAddress(),
            }

            for tag in template_tags:
                path = path.replace(tag, template_tags[tag])

            path = path.strip()
            if path.lower().startswith('plugin://'):
                self._call_addon_method(path)
                return

            if path.lower().startswith('http://') or path.lower().startswith(
                    'https://'):
                source_type = Source.TYPE_URL
            else:
                source_type = Source.TYPE_FILE

        if source_type == Source.TYPE_URL and (
                path.lower().startswith('http://')
                or path.lower().startswith('https://')):
            if 'drive.google.com' in path.lower():
                log.debug('Gdrive Downloading: {} > {}'.format(
                    path, file_path))
                path = gdrivedl(path, file_path)
            else:
                log.debug('Downloading: {} > {}'.format(path, file_path))
                resp = Session().chunked_dl(path, file_path)

                for troll in TROLLS:
                    if troll.lower() in resp.url.lower():
                        self._is_troll = True
                        break

        elif not xbmcvfs.exists(path):
            raise Error(_(_.LOCAL_PATH_MISSING, path=path))
        else:
            _safe_copy(path, file_path)

        if archive_type == Source.ARCHIVE_AUTO:
            archive_type = Source.auto_archive_type(path)

        if archive_type == Source.ARCHIVE_GZIP:
            gzip_extract(file_path)
        elif archive_type == Source.ARCHIVE_XZ:
            xz_extract(file_path)