Ejemplo n.º 1
0
Archivo: utils.py Proyecto: fk-lx/mygpo
def get_episode_link_target(episode, podcast, view_name='episode',
                            add_args=[]):
    """ Returns the link-target for an Episode, preferring slugs over Ids

    automatically distringuishes between relational Episode objects and
    CouchDB-based Episodes """

    from mygpo.core.models import Podcast

    # prefer slugs
    if episode.slug:
        args = [podcast.slug or podcast.get_id(), episode.slug]
        view_name = '%s-slug-id' % view_name

    # for short URLs, prefer oldids over CouchDB-IDs
    elif episode.oldid:
        args = [episode.oldid]

    # fallback: CouchDB-IDs
    else:
        if not podcast:
            if isinstance(episode.podcast, Podcast):
                podcast = episode.podcast
            elif isinstance(episode.podcast, basestring):
                podcast = podcast_by_id(episode.podcast)

        args = [podcast.slug or podcast.get_id(), episode._id]
        view_name = '%s-slug-id' % view_name

    return strip_tags(reverse(view_name, args=args + add_args))
Ejemplo n.º 2
0
def update_podcast_subscribers(podcast_id):
    """ Updates the subscriber count of a podcast """

    try:
        podcast = podcast_by_id(podcast_id)

        # calculate current number of subscribers
        subscriber_count = podcast_subscriber_count(podcast)
        subs_cur = SubscriberData(timestamp=datetime.utcnow(), subscriber_count=subscriber_count)

        # sort all subscriber data entries
        subs_all = sorted(podcast.subscribers + [subs_cur], key=lambda e: e.timestamp)

        # move all but latest two to history
        subs_history = subscriberdata_for_podcast(podcast_id)
        subs_history.subscribers = subs_all[:-2]
        subs_history.save()

        # move latest two to podcast
        podcast.subscribers = subs_all[-2:]
        podcast.save()

    # TODO: which exceptions?
    except Exception as ex:
        raise update_podcast_subscribers.retry(exc=ex)
Ejemplo n.º 3
0
Archivo: tasks.py Proyecto: fk-lx/mygpo
def flattr_thing(user, thing_id, domain, is_secure, thing_type):
    """ Task to flattr a thing """

    flattr = Flattr(user, domain, is_secure)

    if thing_type == 'Podcast':
        thing = podcast_by_id(thing_id)

    elif thing_type == 'Episode':
        thing = episode_by_id(thing_id)

    else:
        raise NotImplemented(_("Can't flattr a '%s'") % thing_type)


    if not thing.flattr_url:
        return False, _('No Payment URL available')

    try:
        success, msg = flattr.flattr_url(thing.flattr_url)

        if settings.FLATTR_MYGPO_THING:
            flattr.flattr_url(settings.FLATTR_MYGPO_THING)

    except Exception as ex:
        raise flattr_thing.retry(exc=ex)

    return success, msg
Ejemplo n.º 4
0
Archivo: views.py Proyecto: fk-lx/mygpo
def episode(request, episode):

    site = RequestSite(request)
    podcast = podcast_by_id(episode.podcast)

    if not check_publisher_permission(request.user, podcast):
        return HttpResponseForbidden()

    if request.method == 'POST':
        form = None  # EpisodeForm(request.POST, instance=e)
        # if form.is_valid():
        #    form.save()

    elif request.method == 'GET':
        form = None  # EpisodeForm(instance=e)

    timeline_data = list(episode_listener_data(episode))

    heatmap = EpisodeHeatmap(episode.podcast, episode._id,
              duration=episode.duration)

    return render(request, 'publisher/episode.html', {
        'is_secure': request.is_secure(),
        'domain': site.domain,
        'episode': episode,
        'podcast': podcast,
        'form': form,
        'timeline_data': timeline_data,
        'heatmap': heatmap,
        })
Ejemplo n.º 5
0
def add_action(request, episode):

    device = request.user.get_device(request.POST.get('device'))

    action_str = request.POST.get('action')
    timestamp = request.POST.get('timestamp', '')

    if timestamp:
        try:
            timestamp = dateutil.parser.parse(timestamp)
        except (ValueError, AttributeError):
            timestamp = datetime.utcnow()
    else:
        timestamp = datetime.utcnow()

    action = EpisodeAction()
    action.timestamp = timestamp
    action.upload_timestamp = get_timestamp(datetime.utcnow())
    action.device = device.id if device else None
    action.action = action_str

    state = episode_state_for_user_episode(request.user, episode)
    add_episode_actions(state, [action])

    podcast = podcast_by_id(episode.podcast)
    return HttpResponseRedirect(get_episode_link_target(episode, podcast))
Ejemplo n.º 6
0
Archivo: views.py Proyecto: fk-lx/mygpo
def update_episode_slug(request, episode):
    """ sets a new "main" slug, and moves the existing to the merged slugs """

    new_slug = request.POST.get('slug')
    podcast = podcast_by_id(episode.podcast)

    if new_slug:
        # remove the new slug from other episodes (of the same podcast)
        other_episodes = episodes_for_slug(podcast.get_id(), new_slug)

        for other_episode in other_episodes:

            if other_episode == episode:
                continue

            remove_episode_slug(other_episode, new_slug)
            messages.warning(request,
                _(u'Removed slug {slug} from {episode}'.format(
                    slug=new_slug, episode=other_episode.title))
            )

    set_episode_slug(episode, new_slug)

    # TODO: we should use better cache invalidation
    cache.clear()

    return HttpResponseRedirect(
        get_episode_link_target(episode, podcast, 'episode-publisher-detail')
    )
Ejemplo n.º 7
0
    def add_user_recursive(self, user, docs):
        """ adds a user and all the podcast and episodes it references """

        # User
        docs.add(user._id)

        # Suggestions
        suggestions = suggestions_for_user(user)
        docs.add(suggestions._id)

        progress(0, len(docs), '', stream=sys.stderr)

        # Podcast States
        for p_state in podcast_states_for_user(user):
            self.add_podcast_state(p_state, docs)

            progress(0, len(docs), p_state, stream=sys.stderr)

            # Podcast
            podcast = podcast_by_id(p_state.podcast)
            self.add_podcast(podcast, docs)

            progress(0, len(docs), podcast, stream=sys.stderr)

            # Episodes
            for episode in episodes_for_podcast(podcast):
                self.add_episode(episode, docs)
                progress(0, len(docs), episode, stream=sys.stderr)

                e_state = episode_state_for_user_episode(user, episode)
                self.add_episode_state(e_state, docs)
                progress(0, len(docs), e_state, stream=sys.stderr)
Ejemplo n.º 8
0
Archivo: tests.py Proyecto: fk-lx/mygpo
    def test_merge_podcasts(self):

        podcast1 = podcast_by_id(self.podcast1.get_id())
        podcast2 = podcast_by_id(self.podcast2.get_id())
        podcast3 = podcast_by_id(self.podcast3.get_id())

        # assert that the podcasts are actually grouped
        self.assertEqual(podcast2._id, podcast3._id)
        self.assertNotEqual(podcast2.get_id(), podcast2._id)
        self.assertNotEqual(podcast3.get_id(), podcast3._id)

        # Create additional data that will be merged
        state1 = episode_state_for_user_episode(self.user, self.episode1)
        state2 = episode_state_for_user_episode(self.user, self.episode2)

        action1 = EpisodeAction(action='play',
                timestamp=datetime.utcnow(),
                upload_timestamp=get_timestamp(datetime.utcnow()))
        action2 = EpisodeAction(action='download',
                timestamp=datetime.utcnow(),
                upload_timestamp=get_timestamp(datetime.utcnow()))

        add_episode_actions(state1, [action1])
        add_episode_actions(state2, [action2])

        # copy of the object
        episode2 = episode_by_id(self.episode2._id)

        # decide which episodes to merge
        groups = [(0, [self.episode1, self.episode2])]
        counter = Counter()

        pm = PodcastMerger([podcast2, podcast1], counter, groups)
        pm.merge()

        state1 = episode_state_for_user_episode(self.user, self.episode1)
        state2 = episode_state_for_user_episode(self.user, episode2)

        self.assertIn(action1, state1.actions)
        self.assertIn(action2, state1.actions)
        self.assertEqual(state2._id, None)

        episode1 = episode_by_id(self.episode1._id)

        # episode2 has been merged into episode1, so it must contain its
        # merged _id
        self.assertEqual(episode1.merged_ids, [episode2._id])
Ejemplo n.º 9
0
    def _decorator(request, id, *args, **kwargs):
        episode = episode_for_oldid(id)

        if episode is None:
            raise Http404

        # redirect to Id or slug URL
        podcast = podcast_by_id(episode.podcast)
        return HttpResponseRedirect(get_episode_link_target(episode, podcast))
Ejemplo n.º 10
0
def toggle_favorite(request, episode):
    episode_state = episode_state_for_user_episode(request.user, episode)

    is_fav = episode_state.is_favorite()
    set_episode_favorite(episode_state, not is_fav)

    podcast = podcast_by_id(episode.podcast)

    return HttpResponseRedirect(get_episode_link_target(episode, podcast))
Ejemplo n.º 11
0
    def handle(self, *args, **options):

        db = get_main_database()
        status = self.get_cmd_status()
        since = self.get_since(status, options)
        objects = self.get_objects(db, since)
        actions = Counter()


        # create unfinished command run status
        run_status = CommandRunStatus()
        run_status.timestamp_started = datetime.utcnow()
        run_status.start_seq = since
        # add it to existing one (if any)
        status.runs.append(run_status)
        status.save()

        total = db.info()['update_seq']

        has_slug = lambda x: bool(x.slug)

        for seq, obj in objects:
            total = db.info()['update_seq']

            if isinstance(obj, PodcastGroup):
                podcasts = filter(has_slug, obj.podcasts)

            if isinstance(obj, Podcast):
                podcasts = filter(has_slug, [obj])

            elif isinstance(obj, Episode):
                if has_slug(obj):
                    continue

                podcast = podcast_by_id(obj.podcast)
                if not podcast:
                    continue
                podcasts = filter(has_slug, [podcast])

            updated = self.handle_podcasts(podcasts)
            actions['updated'] += updated

            if not options['silent']:
                status_str = ', '.join('%s: %d' % x for x in actions.items())
                progress(seq, total, status_str)


        # finish command run status
        run_status.timestamp_finished = datetime.utcnow()
        run_status.end_seq = total
        run_status.status_counter = dict(actions)
        # and overwrite existing one (we could keep a longer log here)
        status.runs = [run_status]
        status.save()
Ejemplo n.º 12
0
def episode(request, episode):

    podcast = podcast_by_id(episode.podcast)

    podcast = check_restrictions(podcast)

    user = request.user

    if not podcast:
        raise Http404

    if user.is_authenticated():

        episode_state = episode_state_for_user_episode(user, episode)
        is_fav = episode_state.is_favorite()


        # pre-populate data for fetch_data
        podcasts_dict = {podcast.get_id(): podcast}
        episodes_dict = {episode._id: episode}

        has_history = bool(list(episode_state.get_history_entries()))

        played_parts = EpisodeHeatmap(podcast.get_id(),
                episode._id, user._id, duration=episode.duration)

        devices = dict( (d.id, d.name) for d in user.devices )
        can_flattr = user.get_wksetting(FLATTR_TOKEN) and episode.flattr_url

    else:
        has_history = False
        is_fav = False
        played_parts = None
        devices = {}
        can_flattr = False

    is_publisher = check_publisher_permission(user, podcast)

    prev = podcast.get_episode_before(episode)
    next = podcast.get_episode_after(episode)

    return render(request, 'episode.html', {
        'episode': episode,
        'podcast': podcast,
        'prev': prev,
        'next': next,
        'has_history': has_history,
        'is_favorite': is_fav,
        'played_parts': played_parts,
        'actions': EPISODE_ACTION_TYPES,
        'devices': devices,
        'can_flattr': can_flattr,
        'is_publisher': is_publisher,
    })
Ejemplo n.º 13
0
    def _decorator(request, p_slug_id, e_slug_id, *args, **kwargs):
        episode = episode_for_slug_id(p_slug_id, e_slug_id)

        if episode is None:
            raise Http404

        # redirect when Id or a merged (non-cannonical) slug is used
        if episode.slug and episode.slug != e_slug_id:
            podcast = podcast_by_id(episode.podcast)
            return HttpResponseRedirect(
                    get_episode_link_target(episode, podcast))

        return f(request, episode, *args, **kwargs)
Ejemplo n.º 14
0
def remove_podcast_from_podcastlist(plist, podcast_id):

    if podcast_id in plist.podcasts:
        plist.podcasts.remove(podcast_id)

    if not podcast_id in plist.podcasts:
        # the podcast might be there with another id
        podcast = podcast_by_id(podcast_id)
        for podcast_id in podcast.get_ids():
            if podcast_id in plist.podcasts:
                plist.podcasts.remove(podcast_id)

    plist.save()
Ejemplo n.º 15
0
def mytags(request):
    tags_podcast = {}
    tags_tag = defaultdict(list)

    for podcast_id, taglist in tags_for_user(request.user).items():
        podcast = podcast_by_id(podcast_id)
        tags_podcast[podcast] = taglist

        for tag in taglist:
            tags_tag[ tag ].append(podcast)

    return render(request, 'mytags.html', {
        'tags_podcast': tags_podcast,
        'tags_tag': dict(tags_tag.items()),
    })
Ejemplo n.º 16
0
def episode_data(episode, domain, podcast=None):

    podcast = podcast or podcast_by_id(episode.podcast)

    data = {
        "title": episode.title,
        "url": episode.url,
        "podcast_title": podcast.title if podcast else '',
        "podcast_url": podcast.url if podcast else '',
        "description": episode.description,
        "website": episode.link,
        "mygpo_link": 'http://%(domain)s%(res)s' % dict(domain=domain,
            res=get_episode_link_target(episode, podcast)) if podcast else ''
        }

    if episode.released:
        data['released'] = episode.released.strftime('%Y-%m-%dT%H:%M:%S')

    return data
Ejemplo n.º 17
0
def episode_state_for_user_episode(user, episode):

    if not user:
        raise QueryParameterMissing('user')

    if not episode:
        raise QueryParameterMissing('episode')


    key = 'episode-state-userid-%s-episodeid-%s' % (sha1(user._id).hexdigest(),
            sha1(episode._id).hexdigest())

#   Disabled as cache invalidation does not work properly
#   state = cache.get(key)
#   if state:
#       return state

    udb = get_userdata_database()
    state = get_single_result(udb, 'episode_states/by_user_episode',
            key          = [user._id, episode._id],
            include_docs = True,
            limit        = 1,
            schema       = EpisodeUserState,
        )

    if state:
        cache.set(key, state)
        return state

    else:
        podcast = podcast_by_id(episode.podcast)

        state = EpisodeUserState()
        state.episode = episode._id
        state.podcast = episode.podcast
        state.user = user._id
        state.ref_url = episode.url
        state.podcast_ref_url = podcast.url
        # don't cache here, because the state is saved by the calling function

        return state
Ejemplo n.º 18
0
def history(request, episode):
    """ shows the history of the episode """

    user = request.user
    podcast = podcast_by_id(episode.podcast)
    episode_state = episode_state_for_user_episode(user, episode)

    # pre-populate data for fetch_data
    podcasts_dict = {podcast.get_id(): podcast}
    episodes_dict = {episode._id: episode}

    history = list(episode_state.get_history_entries())
    HistoryEntry.fetch_data(user, history,
            podcasts=podcasts_dict, episodes=episodes_dict)

    devices = dict( (d.id, d.name) for d in user.devices )

    return render(request, 'episode-history.html', {
        'episode': episode,
        'podcast': podcast,
        'history': history,
        'actions': EPISODE_ACTION_TYPES,
        'devices': devices,
    })
Ejemplo n.º 19
0
def flattr_episode(request, episode):
    """ Flattrs an episode, records an event and redirects to the episode """

    user = request.user
    site = RequestSite(request)

    # Flattr via the tasks queue, but wait for the result
    task = flattr_thing.delay(user, episode._id, site.domain,
            request.is_secure(), 'Episode')
    success, msg = task.get()

    if success:
        action = EpisodeAction()
        action.action = 'flattr'
        action.upload_timestamp = get_timestamp(datetime.utcnow())
        state = episode_state_for_user_episode(request.user, episode)
        add_episode_actions(state, [action])
        messages.success(request, _("Flattr\'d"))

    else:
        messages.error(request, msg)

    podcast = podcast_by_id(episode.podcast)
    return HttpResponseRedirect(get_episode_link_target(episode, podcast))
Ejemplo n.º 20
0
Archivo: tests.py Proyecto: fk-lx/mygpo
    def test_merge(self):

        p1 = Podcast()
        p1.urls = ['http://example.com/podcast1.rss']
        p1.save()

        p2 = Podcast()
        p2.urls = ['http://example.com/podcast2.rss']
        p2.save()


        e1 = Episode()
        e1.title = 'Episode 1'
        e1.podcast = p1.get_id()
        e1.urls = ['http://example.com/podcast1/e1.mp3']
        e1.save()

        e2 = Episode()
        e2.title = 'Episode 2'
        e2.podcast = p1.get_id()
        e2.urls = ['http://example.com/podcast1/e2.mp3']
        e2.save()

        e3 = Episode()
        e3.title = 'Episode 3'
        e3.podcast = p2.get_id()
        e3.urls = ['http://example.com/podcast2/e2.mp3']
        e3.save()

        e4 = Episode()
        e4.title = 'Episode 4'
        e4.podcast = p2.get_id()
        e4.urls = ['http://example.com/podcast2/e3.mp3']
        e4.save()

        user = User()
        user.username = '******'
        user.email = '*****@*****.**'
        user.set_password('secret')

        device1 = Device()
        device1.uid = 'dev1'

        device2 = Device()
        device2.uid = 'dev2'

        user.devices.append(device1)
        user.devices.append(device2)
        user.save()


        p1.subscribe(user, device1)
        time.sleep(1)
        p1.unsubscribe(user, device1)
        time.sleep(1)
        p1.subscribe(user, device1)
        p2.subscribe(user, device2)

        s1 = episode_state_for_user_episode(user, e1)
        add_episode_actions(s1, [EpisodeAction(action='play',
                    upload_timestamp=get_timestamp(datetime.utcnow()))])

        s3 = episode_state_for_user_episode(user, e3)
        add_episode_actions(s3, [EpisodeAction(action='play',
                    upload_timestamp=get_timestamp(datetime.utcnow()))])

        # we need that for later
        e3_id = e3._id

        actions = Counter()

        # decide which episodes to merge
        groups = [(0, [e1]), (1, [e2, e3]), (2, [e4])]

        # carry out the merge
        pm = PodcastMerger([p1, p2], actions, groups)
        pm.merge()

        e1 = episode_by_id(e1._id)
        es1 = episode_state_for_user_episode(user, e1)
        self.assertEqual(len(es1.actions), 1)

        # check if merged episode's id can still be accessed
        e3 = episode_by_id(e3_id)
        es3 = episode_state_for_user_episode(user, e3)
        self.assertEqual(len(es3.actions), 1)

        p1 = podcast_by_id(p1.get_id())
        ps1 = podcast_state_for_user_podcast(user, p1)
        self.assertEqual(len(ps1.get_subscribed_device_ids()), 2)

        self.assertEqual(len(list(episodes_for_podcast(p1))), 3)
Ejemplo n.º 21
0
 def post(self, request, podcast_id):
     podcast = podcast_by_id(podcast_id)
     state = podcast_state_for_user_podcast(request.user, podcast)
     set_podcast_privacy_settings(state, self.public)
     return HttpResponseRedirect(reverse('privacy'))