Esempio n. 1
0
    def __init__(self):
        super(VideoListPopular, self).__init__()

        self.get_style_context().add_class('video_list_popular')

        entries = search_youtube_by_keyword(popular=True, max_results=3,
                                            parent_control=self.ParentalControl,
                                            start_index=randint(1, 20))

        if entries:
            parsed_entries = parse_youtube_entries(entries)
            x_pos = 0

            for i, e in enumerate(parsed_entries):
                img = Gtk.Image()

                button = Button()
                if e['big_thumb']:
                    thumbnail = '{}/video_{}.jpg'.format(tmp_dir, time())
                    download_url(e['big_thumb'], thumbnail)
                    img.set_from_file(thumbnail)
                button.add(img)
                button.connect('clicked', self._play, e['video_url'])
                self._grid.attach(button, x_pos, 0, 1, 1)

                x_pos += 1
Esempio n. 2
0
    def download_online_badges(self):
        profile = load_profile()
        if "kanoworld_id" in profile:
            user_id = profile["kanoworld_id"]
        else:
            return False, "Profile not registered!"

        success, text, data = request_wrapper("get", "/users/{}".format(user_id), session=self.session)

        if not success:
            return False, text

        if "user" not in data:
            return False, "Corrupt response (the 'user' key not found)"

        if "profile" not in data["user"]:
            return False, "Corrupt response (the 'user.profile' key not found)"

        if "badges" not in data["user"]["profile"]:
            msg = "Corrupt response (the 'user.profile.badges' key not found)"
            return False, msg

        online_badges_data = {}

        ensure_dir(online_badges_dir)

        badges = data["user"]["profile"]["badges"]
        for badge in badges:
            if "assigned" not in badge or not badge["assigned"]:
                continue

            if "image_url" not in badge:
                return False, "Couldn't find an image for the badge"

            image_loc = os.path.join(online_badges_dir, "{}.png".format(badge["id"]))
            download_url(badge["image_url"], image_loc)

            online_badges_data[badge["id"]] = {
                "achieved": True,
                "bg_color": badge["bg_color"].replace("#", ""),
                "desc_locked": badge["desc_locked"],
                "desc_unlocked": badge["desc_unlocked"],
                "title": badge["title"],
            }

        try:
            may_write = True
            txt = None
            f = open(online_badges_file, "w")
        except IOError as e:
            may_write = False
            txt = "Error opening badges file {}".format(str(e))
        else:
            with f:
                f.write(json.dumps(online_badges_data))
            if "SUDO_USER" in os.environ:
                chown_path(online_badges_dir)
                chown_path(online_badges_file)

        return may_write, txt
Esempio n. 3
0
    def __init__(self):
        super(VideoListPopular, self).__init__()

        self.get_style_context().add_class('video_list_popular')

        entries = search_youtube_by_keyword(
            popular=True,
            max_results=3,
            parent_control=self.ParentalControl,
            start_index=randint(1, 20))

        if entries:
            parsed_entries = parse_youtube_entries(entries)
            x_pos = 0

            for i, e in enumerate(parsed_entries):
                img = Gtk.Image()

                button = Button()
                if e['big_thumb']:
                    thumbnail = '{}/video_{}.jpg'.format(tmp_dir, time())
                    download_url(e['big_thumb'], thumbnail)
                    img.set_from_file(thumbnail)
                button.add(img)
                button.connect('clicked', self._play, e['video_url'])
                self._grid.attach(button, x_pos, 0, 1, 1)

                x_pos += 1
Esempio n. 4
0
def download_app(app_id_or_slug):
    data = query_for_app(app_id_or_slug)

    # download the icon
    icon_file_type = data['icon_url'].split(".")[-1]
    icon_path = '/tmp/{}.{}'.format(app_id_or_slug, icon_file_type)
    rv, err = download_url(data['icon_url'], icon_path)
    if not rv:
        msg = "Unable to download the application ({})".format(err)
        raise AppDownloadError(msg)

    # Check if the app isn't rpi2 only
    if not is_model_2_b() and 'rpi2_only' in data and data['rpi2_only']:
        msg = "{} won't be downloaded ".format(data['title']) + \
              "becuase it's Raspberry Pi 2 only"
        raise AppDownloadError(msg)

    # Cleanup the JSON file
    data['icon'] = data['slug']
    del data['icon_url']
    del data['likes']
    del data['comments_count']
    data['time_installed'] = int(time.time())
    data['categories'] = map(lambda c: c.lower(), data['categories'])
    data['removable'] = True

    # write out the data
    data_path = '/tmp/{}.app'.format(app_id_or_slug)
    with open(data_path, 'w') as f:
        f.write(json.dumps(data))

    return [data_path, icon_path]
Esempio n. 5
0
    def restore_content(self, file_path):
        success, text, data = request_wrapper("get", "/sync/backup", session=self.session)
        if not success:
            return False, text

        try:
            file_url = data["user_backup"]["file_url"]
        except Exception:
            file_url = None

        if not file_url:
            return False, "backup file not found"

        return download_url(file_url, file_path)
    def restore_content(self, file_path):
        success, text, data = request_wrapper('get', '/sync/backup',
                                              session=self.session)
        if not success:
            return False, text

        try:
            file_url = data['user_backup']['file_url']
        except Exception:
            file_url = None

        if not file_url:
            return False, 'backup file not found'

        return download_url(file_url, file_path)
Esempio n. 7
0
    def restore_content(self, file_path):
        success, text, data = request_wrapper('get',
                                              '/sync/backup',
                                              session=self.session)
        if not success:
            return False, text

        try:
            file_url = data['user_backup']['file_url']
        except Exception:
            file_url = None

        if not file_url:
            return False, "backup file not found"

        return download_url(file_url, file_path)
Esempio n. 8
0
def download_app(app_id_or_slug):
    data = query_for_app(app_id_or_slug)

    # download the icon
    icon_file_type = data['icon_url'].split(".")[-1]
    icon_path = '/tmp/{}.{}'.format(app_id_or_slug, icon_file_type)
    rv, err = download_url(data['icon_url'], icon_path)
    if not rv:
        msg = _("Unable to download the application ({})").format(err)
        raise AppDownloadError(msg)

    # Check if the app is going to run well on the hardware
    if 'min_performance_score' in data and \
       has_min_performance(data['min_performance_score']):

        msg = _(
            "{} won't be downloaded "
            "because the hardware is not performant enough"
        ).format(data['title'])
        raise AppDownloadError(msg)

    # Cleanup the JSON file
    data['icon'] = data['slug']
    del data['icon_url']
    del data['likes']
    del data['comments_count']
    data['time_installed'] = int(time.time())
    data['categories'] = map(lambda c: c.lower(), data['categories'])
    data['removable'] = True

    # FIXME: This should all be done in the API
    if 'priority' not in data:
        data['priority'] = get_prio(data['slug'])

    if data['slug'] == 'powerup':
        data['title'] = 'Make Light'

    # write out the data
    data_path = '/tmp/{}.app'.format(app_id_or_slug)
    with open(data_path, 'w') as f:
        f.write(json.dumps(data))

    return [data_path, icon_path]
Esempio n. 9
0
    def _process_notification(self, entry):
        """ Cherry picks information from a Kano World notification
            based on its type and returns it in a dict.

            :param entry: A notification entry from the World API
            :returns: A dict that can be passed to the notification widget
        """

        notification_dir = os.path.join(media_dir, 'images', 'notification',
                                        '280x170')

        FEATURED_SHARE_IMG = os.path.join(notification_dir, 'featured.png')
        PONG_SHARE_IMG = os.path.join(notification_dir, 'share-pong.png')
        MUSIC_SHARE_IMG = os.path.join(notification_dir, 'share-music.png')
        LIGHT_SHARE_IMG = os.path.join(notification_dir, 'share-light.png')
        ART_SHARE_IMG = os.path.join(notification_dir, 'share-art.png')
        SNAKE_SHARE_IMG = os.path.join(notification_dir, 'snake-art.png')
        MINECRAFT_SHARE_IMG = os.path.join(notification_dir,
                                           'share-minecraft.png')
        FOLLOWER_IMG = os.path.join(notification_dir, 'follower.png')
        COMMENT_IMG = os.path.join(notification_dir, 'comment.png')
        LIKE_IMG = os.path.join(notification_dir, 'like.png')
        GENERIC_ALERT_IMG = os.path.join(notification_dir, 'notification.png')

        n = {
            'id':
            entry['id'],
            'title':
            'Kano World',
            'byline':
            '',
            'image':
            GENERIC_ALERT_IMG,
            'command':
            'kano-world-launcher /notifications/open/{}'.format(entry['id'])
        }

        # Some notifications may have images
        # If so, we need to download them and resize
        if 'image_url' in entry and entry['image_url']:
            filename = os.path.basename(entry['image_url'])

            img_path = "{}/notifications/{}".format(profile_dir, filename)
            ensure_dir(os.path.dirname(img_path))

            rv, e = download_url(entry['image_url'], img_path)
            if rv:
                # Resize image to 280x170
                # FIXME: We import GdkPixbuf locally to make sure not to
                # bugger up anything else, but we should move it up to the top.
                from gi.repository import GdkPixbuf

                pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                    img_path, 280, 170)
                pixbuf.savev(img_path, 'png', [None], [None])

                n['image'] = img_path
            else:
                msg = "Notifications image failed to download ({}).".format(e)
                logger.error(msg)

        # Certain notifications may come with a command as well.
        # If so, override the default one.
        cmd = self._get_dict_value(entry, ['meta', 'cmd'])
        if cmd:
            n['command'] = cmd

        # Customise settings for known types
        if entry['category'] == 'follows':
            n['title'] = 'New follower!'
            n['byline'] = entry['title']
            n['image'] = FOLLOWER_IMG

        elif entry['category'] in ['share-items', 'shares']:
            n['title'] = 'New share!'
            n['byline'] = entry['title']

            if entry['type'] == 'make-minecraft':
                n['image'] = MINECRAFT_SHARE_IMG
            elif entry['type'] == 'make-pong':
                n['image'] = PONG_SHARE_IMG
            elif entry['type'] == 'make-music':
                n['image'] = MUSIC_SHARE_IMG
            elif entry['type'] == 'make-light':
                n['image'] = LIGHT_SHARE_IMG
            elif entry['type'] == 'kano-draw':
                n['image'] = ART_SHARE_IMG
            elif entry['type'] == 'featured':
                n['title'] = 'Staff picked!'
                n['image'] = FEATURED_SHARE_IMG

        elif entry['category'] == 'comments':
            n['title'] = 'New comment!'
            n['byline'] = entry['title']
            n['image'] = COMMENT_IMG

        elif entry['category'] == 'likes':
            n['title'] = 'New like!'
            n['byline'] = entry['title']
            n['image'] = LIKE_IMG
        else:
            return None

        return n
Esempio n. 10
0
    def download_online_badges(self):
        profile = load_profile()
        if 'kanoworld_id' in profile:
            user_id = profile['kanoworld_id']
        else:
            return False, 'Profile not registered!'

        success, text, data = request_wrapper('get',
                                              '/users/{}'.format(user_id),
                                              session=self.session)

        if not success:
            return False, text

        if 'user' not in data:
            return False, _("Corrupt response (the 'user' key not found)")

        if 'profile' not in data['user']:
            return False, _(
                "Corrupt response (the 'user.profile' key not found)")

        if 'badges' not in data['user']['profile']:
            return False, _(
                "Corrupt response (the 'user.profile.badges' key not found)")

        online_badges_data = {}

        ensure_dir(online_badges_dir)

        badges = data['user']['profile']['badges']
        for badge in badges:
            if 'assigned' not in badge or not badge['assigned']:
                continue

            if 'image_url' not in badge:
                return False, _("Couldn't find an image for the badge")

            image_loc = os.path.join(online_badges_dir,
                                     "{}.png".format(badge['id']))
            download_url(badge['image_url'], image_loc)

            online_badges_data[badge['id']] = {
                'achieved': True,
                'bg_color': badge['bg_color'].replace("#", ""),
                'desc_locked': badge['desc_locked'],
                'desc_unlocked': badge['desc_unlocked'],
                'title': badge['title']
            }

        try:
            may_write = True
            txt = None
            f = open(online_badges_file, 'w')
        except IOError as e:
            may_write = False
            txt = 'Error opening badges file {}'.format(str(e))
        else:
            with f:
                f.write(json.dumps(online_badges_data))
            if 'SUDO_USER' in os.environ:
                chown_path(online_badges_dir)
                chown_path(online_badges_file)

        return may_write, txt
Esempio n. 11
0
    def _process_notification(self, entry):
        """ Cherry picks information from a Kano World notification
            based on its type and returns it in a dict.

            :param entry: A notification entry from the World API
            :returns: A dict that can be passed to the notification widget
        """

        notification_dir = os.path.join(
            media_dir, 'images', 'notification', '280x170'
        )

        FEATURED_SHARE_IMG = os.path.join(notification_dir, 'featured.png')
        PONG_SHARE_IMG = os.path.join(notification_dir, 'share-pong.png')
        MUSIC_SHARE_IMG = os.path.join(notification_dir, 'share-music.png')
        LIGHT_SHARE_IMG = os.path.join(notification_dir, 'share-light.png')
        ART_SHARE_IMG = os.path.join(notification_dir, 'share-art.png')
        SNAKE_SHARE_IMG = os.path.join(notification_dir, 'snake-art.png')
        MINECRAFT_SHARE_IMG = os.path.join(notification_dir,
                                           'share-minecraft.png')
        FOLLOWER_IMG = os.path.join(notification_dir, 'follower.png')
        COMMENT_IMG = os.path.join(notification_dir, 'comment.png')
        LIKE_IMG = os.path.join(notification_dir, 'like.png')
        GENERIC_ALERT_IMG = os.path.join(notification_dir, 'notification.png')

        n = {
            'id': entry['id'],
            'title': 'Kano World',
            'byline': '',
            'image': GENERIC_ALERT_IMG,
            'command': 'kano-world-launcher /notifications/open/{}'.format(
                       entry['id'])
        }

        # Some notifications may have images
        # If so, we need to download them and resize
        if 'image_url' in entry and entry['image_url']:
            filename = os.path.basename(entry['image_url'])

            img_path = "{}/notifications/{}".format(profile_dir, filename)
            ensure_dir(os.path.dirname(img_path))

            rv, e = download_url(entry['image_url'], img_path)
            if rv:
                # Resize image to 280x170
                # FIXME: We import GdkPixbuf locally to make sure not to
                # bugger up anything else, but we should move it up to the top.
                from gi.repository import GdkPixbuf

                pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                    img_path, 280, 170)
                pixbuf.savev(img_path, 'png', [None], [None])

                n['image'] = img_path
            else:
                msg = "Notifications image failed to download ({}).".format(e)
                logger.error(msg)

        # Certain notifications may come with a command as well.
        # If so, override the default one.
        cmd = self._get_dict_value(entry, ['meta', 'cmd'])
        if cmd:
            n['command'] = cmd

        # Customise settings for known types
        if entry['category'] == 'follows':
            n['title'] = 'New follower!'
            n['byline'] = entry['title']
            n['image'] = FOLLOWER_IMG

        elif entry['category'] in ['share-items', 'shares']:
            n['title'] = 'New share!'
            n['byline'] = entry['title']

            if entry['type'] == 'make-minecraft':
                n['image'] = MINECRAFT_SHARE_IMG
            elif entry['type'] == 'make-pong':
                n['image'] = PONG_SHARE_IMG
            elif entry['type'] == 'make-music':
                n['image'] = MUSIC_SHARE_IMG
            elif entry['type'] == 'make-light':
                n['image'] = LIGHT_SHARE_IMG
            elif entry['type'] == 'kano-draw':
                n['image'] = ART_SHARE_IMG
            elif entry['type'] == 'featured':
                n['title'] = 'Staff picked!'
                n['image'] = FEATURED_SHARE_IMG

        elif entry['category'] == 'comments':
            n['title'] = 'New comment!'
            n['byline'] = entry['title']
            n['image'] = COMMENT_IMG

        elif entry['category'] == 'likes':
            n['title'] = 'New like!'
            n['byline'] = entry['title']
            n['image'] = LIKE_IMG
        else:
            return None

        return n
Esempio n. 12
0
    def download_online_badges(self):
        profile = load_profile()
        if 'kanoworld_id' in profile:
            user_id = profile['kanoworld_id']
        else:
            return False, 'Profile not registered!'

        success, text, data = request_wrapper(
            'get', '/users/{}'.format(user_id),
            session=self.session
        )

        if not success:
            return False, text

        if 'user' not in data:
            return False, _("Corrupt response (the 'user' key not found)")

        if 'profile' not in data['user']:
            return False, _("Corrupt response (the 'user.profile' key not found)")

        if 'badges' not in data['user']['profile']:
            return False, _("Corrupt response (the 'user.profile.badges' key not found)")

        online_badges_data = {}

        ensure_dir(online_badges_dir)

        badges = data['user']['profile']['badges']
        for badge in badges:
            if 'assigned' not in badge or not badge['assigned']:
                continue

            if 'image_url' not in badge:
                return False, _("Couldn't find an image for the badge")

            image_loc = os.path.join(online_badges_dir,
                                     "{}.png".format(badge['id']))
            download_url(badge['image_url'], image_loc)

            online_badges_data[badge['id']] = {
                'achieved': True,
                'bg_color': badge['bg_color'].replace("#", ""),
                'desc_locked': badge['desc_locked'],
                'desc_unlocked': badge['desc_unlocked'],
                'title': badge['title']
            }

        try:
            may_write = True
            txt = None
            f = open(online_badges_file, 'w')
        except IOError as e:
            may_write = False
            txt = 'Error opening badges file {}'.format(str(e))
        else:
            with f:
                f.write(json.dumps(online_badges_data))
            if 'SUDO_USER' in os.environ:
                chown_path(online_badges_dir)
                chown_path(online_badges_file)

        return may_write, txt
Esempio n. 13
0
def download_share(entry):
    app = entry['app']
    title = entry['title']
    description = entry['description']
    attachment_url = entry['attachment_url']
    cover_url = entry['cover_url']
    resource_url = entry['resource_url']

    data = {
        'title': title,
        'description': description
    }

    app_profiles = read_json(app_profiles_file)

    if app not in app_profiles:
        logger.error("Cannot download share, app not found in app-profiles")
        return

    app_profile = app_profiles[app]

    folder = os.path.join(get_home(), app_profile['dir'], 'webload')
    ensure_dir(folder)

    title_slugified = slugify(title)

    # Download attachment
    attachment_ext = attachment_url.split('.')[-1]
    attachment_name = '{}.{}'.format(title_slugified, attachment_ext)
    attachment_path = os.path.join(folder, attachment_name)

    success, text = download_url(attachment_url, attachment_path)
    if not success:
        msg = "Error with downloading share file: {}".format(text)
        logger.error(msg)
        return False, msg

    # Download screenshot
    if cover_url:
        cover_ext = cover_url.split('.')[-1]
        cover_name = '{}.{}'.format(title_slugified, cover_ext)
        cover_path = os.path.join(folder, cover_name)

        success, text = download_url(cover_url, cover_path)
        if not success:
            msg = "Error with downloading cover file: {}".format(text)
            logger.error(msg)
            return False, msg

    # Download resource file
    if resource_url:
        resource_ext = resource_url.split('.')[-1]
        # Make sure we don't remove the tar from gz
        if 'tar.gz' in resource_url:
            resource_ext = 'tar.' + resource_ext
        resource_name = '{}.{}'.format(title_slugified, resource_ext)
        resource_path = os.path.join(folder, resource_name)

        success, text = download_url(resource_url, resource_path)
        if not success:
            msg = "Error with downloading resource file: {}".format(text)
            logger.error(msg)
            return False, msg

    # JSON file
    json_name = '{}.{}'.format(title_slugified, 'json')
    json_path = os.path.join(folder, json_name)
    write_json(json_path, data)
    return True, [title, attachment_path, app, attachment_name, folder]
Esempio n. 14
0
    def __init__(self, e, playlist_name=None, permanent=False):
        super(VideoEntry, self).__init__(hexpand=True)

        self._playlist_name = playlist_name
        self._permanent = permanent

        self.get_style_context().add_class('entry_item')

        self.connect('clicked', self._detail_view_handler, e)

        button_grid = Gtk.Grid()
        button_grid.set_column_spacing(30)
        self.add(button_grid)

        img = Gtk.Image()

        if e['thumbnail']:
            thumbnail = '{}/video_{}.jpg'.format(tmp_dir, time())
            download_url(e['thumbnail'], thumbnail)
            img.set_from_file(thumbnail)
        else:
            img.set_from_file('{}/icons/no_thumbnail.png'.format(image_dir))

        img.set_size_request(self._ENTRY_HEIGHT, self._ENTRY_HEIGHT)
        img.get_style_context().add_class('thumb')
        button_grid.attach(img, 0, 0, 1, 4)

        title_str = e['title'] if len(
            e['title']) <= 70 else e['title'][:67] + '...'
        label = Gtk.Label(title_str, hexpand=True)
        label.set_alignment(0, 0.5)
        label.get_style_context().add_class('title')
        button_grid.attach(label, 1, 0, 1, 1)

        if playlist_name and not permanent:
            remove = RemoveButton()
            remove.connect('clicked', self._remove_from_playlist_handler, e,
                           playlist_name)
            button_grid.attach(remove, 2, 0, 1, 1)

        if e['local_path'] is None:
            stats_str = '{}K views - {}:{} min - by {}'.format(
                int(e['viewcount'] / 1000.0), e['duration_min'],
                e['duration_sec'], e['author'])
            label = Gtk.Label(stats_str)
            label.get_style_context().add_class('subtitle')
            label.set_alignment(0, 0.5)
            button_grid.attach(label, 1, 1, 2, 1)

            desc_str = e['description'] if len(
                e['description']) <= 100 else e['description'][:97] + '...'
            label = Gtk.Label(desc_str)
            label.get_style_context().add_class('subtitle')
            label.set_alignment(0, 0.5)
            button_grid.attach(label, 1, 2, 2, 1)

        action_grid = Gtk.Grid()
        button_grid.attach(action_grid, 1, 3, 2, 1)

        button = Button('WATCH')
        button.get_style_context().add_class('orange_linktext')
        self._button_handler_id = button.connect('clicked', self._play_handler,
                                                 e['video_url'],
                                                 e['local_path'])
        action_grid.attach(button, 0, 0, 1, 1)

        if not playlist_name:
            action_grid.attach(Spacer(), 1, 0, 1, 1)

            button = Button('SAVE')
            button.get_style_context().add_class('orange_linktext')
            self._button_handler_id = button.connect(
                'clicked', self.add_to_playlist_handler, e)
            action_grid.attach(button, 2, 0, 1, 1)
Esempio n. 15
0
    def _process_notification(self, entry):
        """ Cherry picks information from a Kano World notification
            based on its type and returns it in a dict.

            :param entry: A notification entry from the World API
            :returns: A dict that can be passed to the notification widget
        """

        MINECRAFT_SHARE_IMG = media_dir + "/images/notification/280x170/share-pong.png"
        PONG_SHARE_IMG = media_dir + "/images/notification/280x170/share-minecraft.png"
        SP_IMG = media_dir + "/images/notification/280x170/saturday-project.png"
        FOLLOWER_IMG = media_dir + "/images/notification/280x170/follower.png"
        GENERIC_ALERT_IMG = media_dir + "/images/notification/280x170/notification.png"

        n = {
            "id": entry["id"],
            "title": "Kano World",
            "byline": "",
            "image": GENERIC_ALERT_IMG,
            "command": "kano-world-launcher /notifications/open/{}".format(entry["id"]),
        }

        # Customise settings for known types
        if entry["category"] == "follows":
            n["title"] = "New follower!"
            n["byline"] = entry["title"]
            n["image"] = FOLLOWER_IMG

            # Link to whomever followed this user
            user = self._get_dict_value(entry, ["meta", "author", "username"])
            if user:
                n["command"] = "kano-world-launcher /users/{}".format(user)

        elif entry["category"] in ["share-items", "shares"]:
            n["title"] = "New share!"
            n["byline"] = entry["title"]

            if entry["type"] == "make-minecraft":
                n["image"] = MINECRAFT_SHARE_IMG
            elif entry["type"] == "make-pong":
                n["image"] = PONG_SHARE_IMG

            # Link to the share
            share_id = self._get_dict_value(entry, ["meta", "item", "id"])
            if share_id:
                n["command"] = "kano-world-launcher /shared/{}".format(share_id)

        elif entry["category"] == "comments":
            n["title"] = "New comment!"
            n["byline"] = entry["title"]

            slug = self._get_dict_value(entry, ["meta", "item", "slug"])
            if slug:
                obj_type = entry["meta"]["item"]["type"]
                if obj_type == "app":
                    n["command"] = "kano-world-launcher /apps/{}".format(slug)
                elif obj_type == "share":
                    n["command"] = "kano-world-launcher /shared/{}".format(slug)
                elif obj_type == "project":
                    n["command"] = "kano-world-launcher /projects/{}".format(slug)

        # If a notification has both the title and text, override the default
        if "title" in entry and entry["title"] and "text" in entry and entry["text"]:
            n["title"] = entry["title"]
            n["byline"] = entry["text"]

        # Some notifications may have images
        # If so, we need to download them and resize
        if "image_url" in entry and entry["image_url"]:
            filename = os.path.basename(entry["image_url"])

            img_path = "{}/notifications/{}".format(profile_dir, filename)
            ensure_dir(os.path.dirname(img_path))

            rv, e = download_url(entry["image_url"], img_path)
            if rv:
                # Resize image to 280x170
                # FIXME: We import GdkPixbuf locally to make sure not to
                # bugger up anything else, but we should move it up to the top.
                from gi.repository import GdkPixbuf

                pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(img_path, 280, 170)
                pixbuf.savev(img_path, "png", [None], [None])

                n["image"] = img_path
            else:
                msg = "Notifications image failed to download ({}).".format(e)
                logger.error(msg)

        # Certain notifications may come with a command as well.
        # If so, override the default one.
        cmd = self._get_dict_value(entry, ["meta", "cmd"])
        if cmd:
            n["command"] = cmd

        return n
Esempio n. 16
0
    def __init__(self, e, playlist_name=None, permanent=False):
        super(VideoEntry, self).__init__(hexpand=True)

        self._playlist_name = playlist_name
        self._permanent = permanent

        self.get_style_context().add_class('entry_item')

        self.connect('clicked', self._detail_view_handler, e)

        button_grid = Gtk.Grid()
        button_grid.set_column_spacing(30)
        self.add(button_grid)

        img = Gtk.Image()

        if e['thumbnail']:
            thumbnail = '{}/video_{}.jpg'.format(tmp_dir, time())
            download_url(e['thumbnail'], thumbnail)
            img.set_from_file(thumbnail)
        else:
            img.set_from_file('{}/icons/no_thumbnail.png'.format(image_dir))

        img.set_size_request(self._ENTRY_HEIGHT, self._ENTRY_HEIGHT)
        img.get_style_context().add_class('thumb')
        button_grid.attach(img, 0, 0, 1, 4)

        title_str = e['title'] if len(e['title']) <= 70 else e['title'][:67] + '...'
        label = Gtk.Label(title_str, hexpand=True)
        label.set_alignment(0, 0.5)
        label.get_style_context().add_class('title')
        button_grid.attach(label, 1, 0, 1, 1)

        if playlist_name and not permanent:
            remove = RemoveButton()
            remove.connect('clicked', self._remove_from_playlist_handler, e, playlist_name)
            button_grid.attach(remove, 2, 0, 1, 1)

        if e['local_path'] is None:
            stats_str = '{}K views - {}:{} min - by {}'.format(int(e['viewcount'] / 1000.0), e['duration_min'],
                                                               e['duration_sec'], e['author'])
            label = Gtk.Label(stats_str)
            label.get_style_context().add_class('subtitle')
            label.set_alignment(0, 0.5)
            button_grid.attach(label, 1, 1, 2, 1)

            desc_str = e['description'] if len(e['description']) <= 100 else e['description'][:97] + '...'
            label = Gtk.Label(desc_str)
            label.get_style_context().add_class('subtitle')
            label.set_alignment(0, 0.5)
            button_grid.attach(label, 1, 2, 2, 1)

        action_grid = Gtk.Grid()
        button_grid.attach(action_grid, 1, 3, 2, 1)

        button = Button('WATCH')
        button.get_style_context().add_class('orange_linktext')
        self._button_handler_id = button.connect('clicked', self._play_handler, e['video_url'], e['local_path'])
        action_grid.attach(button, 0, 0, 1, 1)

        if not playlist_name:
            action_grid.attach(Spacer(), 1, 0, 1, 1)

            button = Button('SAVE')
            button.get_style_context().add_class('orange_linktext')
            self._button_handler_id = button.connect('clicked', self.add_to_playlist_handler, e)
            action_grid.attach(button, 2, 0, 1, 1)
Esempio n. 17
0
def download_share(entry):
    app = entry['app']
    title = entry['title']
    description = entry['description']
    attachment_url = entry['attachment_url']
    cover_url = entry['cover_url']
    resource_url = entry['resource_url']

    data = {'title': title, 'description': description}

    app_profiles = read_json(app_profiles_file)

    if app not in app_profiles:
        logger.error("Cannot download share, app not found in app-profiles")
        return

    app_profile = app_profiles[app]

    folder = os.path.join(get_home(), app_profile['dir'], 'webload')
    ensure_dir(folder)

    title_slugified = slugify(title)

    # Download attachment
    attachment_ext = attachment_url.split('.')[-1]
    attachment_name = '{}.{}'.format(title_slugified, attachment_ext)
    attachment_path = os.path.join(folder, attachment_name)

    success, text = download_url(attachment_url, attachment_path)
    if not success:
        msg = "Error with downloading share file: {}".format(text)
        logger.error(msg)
        return False, msg

    # Download screenshot
    if cover_url:
        cover_ext = cover_url.split('.')[-1]
        cover_name = '{}.{}'.format(title_slugified, cover_ext)
        cover_path = os.path.join(folder, cover_name)

        success, text = download_url(cover_url, cover_path)
        if not success:
            msg = "Error with downloading cover file: {}".format(text)
            logger.error(msg)
            return False, msg

    # Download resource file
    if resource_url:
        resource_ext = resource_url.split('.')[-1]
        # Make sure we don't remove the tar from gz
        if 'tar.gz' in resource_url:
            resource_ext = 'tar.' + resource_ext
        resource_name = '{}.{}'.format(title_slugified, resource_ext)
        resource_path = os.path.join(folder, resource_name)

        success, text = download_url(resource_url, resource_path)
        if not success:
            msg = "Error with downloading resource file: {}".format(text)
            logger.error(msg)
            return False, msg

    # JSON file
    json_name = '{}.{}'.format(title_slugified, 'json')
    json_path = os.path.join(folder, json_name)
    write_json(json_path, data)
    return True, [title, attachment_path, app, attachment_name, folder]
Esempio n. 18
0
    def _process_notification(self, entry):
        """ Cherry picks information from a Kano World notification
            based on its type and returns it in a dict.

            :param entry: A notification entry from the World API
            :returns: A dict that can be passed to the notification widget
        """

        MINECRAFT_SHARE_IMG = media_dir + \
            '/images/notification/280x170/share-pong.png'
        PONG_SHARE_IMG = media_dir + \
            '/images/notification/280x170/share-minecraft.png'
        SP_IMG = media_dir + \
            '/images/notification/280x170/saturday-project.png'
        FOLLOWER_IMG = media_dir + \
            '/images/notification/280x170/follower.png'
        GENERIC_ALERT_IMG = media_dir + \
            '/images/notification/280x170/notification.png'

        n = {
            'id': entry['id'],
            'title': 'Kano World',
            'byline': '',
            'image': GENERIC_ALERT_IMG,
            'command': 'kano-world-launcher /notifications/open/{}'.format(
                       entry['id'])
        }

        # Customise settings for known types
        if entry['category'] == 'follows':
            n['title'] = 'New follower!'
            n['byline'] = entry['title']
            n['image'] = FOLLOWER_IMG

            # Link to whomever followed this user
            user = self._get_dict_value(entry, ['meta', 'author', 'username'])
            if user:
                n['command'] = "kano-world-launcher /users/{}".format(user)

        elif entry['category'] in ['share-items', 'shares']:
            n['title'] = 'New share!'
            n['byline'] = entry['title']

            if entry['type'] == 'make-minecraft':
                n['image'] = MINECRAFT_SHARE_IMG
            elif entry['type'] == 'make-pong':
                n['image'] = PONG_SHARE_IMG

            # Link to the share
            share_id = self._get_dict_value(entry, ['meta', 'item', 'id'])
            if share_id:
                n['command'] = "kano-world-launcher /shared/{}".format(
                    share_id)

        elif entry['category'] == 'comments':
            n['title'] = 'New comment!'
            n['byline'] = entry['title']

            slug = self._get_dict_value(entry, ['meta', 'item', 'slug'])
            if slug:
                obj_type = entry['meta']['item']['type']
                if obj_type == "app":
                    n['command'] = "kano-world-launcher /apps/{}".format(slug)
                elif obj_type == "share":
                    n['command'] = "kano-world-launcher /shared/{}".format(
                        slug)
                elif obj_type == "project":
                    n['command'] = "kano-world-launcher /projects/{}".format(
                        slug)

        # If a notification has both the title and text, override the default
        if 'title' in entry and entry['title'] and \
                'text' in entry and entry['text']:
            n['title'] = entry['title']
            n['byline'] = entry['text']

        # Some notifications may have images
        # If so, we need to download them and resize
        if 'image_url' in entry and entry['image_url']:
            filename = os.path.basename(entry['image_url'])

            img_path = "{}/notifications/{}".format(profile_dir, filename)
            ensure_dir(os.path.dirname(img_path))

            rv, e = download_url(entry['image_url'], img_path)
            if rv:
                # Resize image to 280x170
                # FIXME: We import GdkPixbuf locally to make sure not to
                # bugger up anything else, but we should move it up to the top.
                from gi.repository import GdkPixbuf

                pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                    img_path, 280, 170)
                pixbuf.savev(img_path, 'png', [None], [None])

                n['image'] = img_path
            else:
                msg = "Notifications image failed to download ({}).".format(e)
                logger.error(msg)

        # Certain notifications may come with a command as well.
        # If so, override the default one.
        cmd = self._get_dict_value(entry, ['meta', 'cmd'])
        if cmd:
            n['command'] = cmd

        return n