示例#1
0
    def update(self, podcast_url):
        """ Update the podcast for the supplied URL """

        try:
            parsed = self._fetch_feed(podcast_url)
            self._validate_parsed(parsed)

        except (ParserException, FetchFeedException, NoEpisodesException,
                VimeoError, ValueError, socket.error, urllib2.HTTPError) as ex:
            #TODO: catch valueError (for invalid Ipv6 in feedservice)

            if isinstance(ex, VimeoError):
                logger.exception('Problem when updating Vimeo feed %s',
                                 podcast_url)

            # if we fail to parse the URL, we don't even create the
            # podcast object
            p = podcast_for_url(podcast_url, create=False)
            if p:
                # if it exists already, we mark it as outdated
                self._mark_outdated(p, 'error while fetching feed: %s' %
                    str(ex))
                return p

            else:
                raise NoPodcastCreated(ex)

        assert parsed, 'fetch_feed must return something'
        p = podcast_for_url(podcast_url, create=True)
        episodes = self._update_episodes(p, parsed.episodes)
        self._update_podcast(p, parsed, episodes)
        return p
示例#2
0
文件: legacy.py 项目: fk-lx/mygpo
def upload(request):
    try:
        emailaddr = request.POST['username']
        password  = request.POST['password']
        action    = request.POST['action']
        protocol  = request.POST['protocol']
        opml      = request.FILES['opml'].read()
    except MultiValueDictKeyError:
        return HttpResponse("@PROTOERROR", mimetype='text/plain')

    user = auth(emailaddr, password)
    if (not user):
        return HttpResponse('@AUTHFAIL', mimetype='text/plain')

    dev = get_device(user, LEGACY_DEVICE_UID,
            request.META.get('HTTP_USER_AGENT', ''))

    existing_urls = [x.url for x in dev.get_subscribed_podcasts()]

    i = Importer(opml)

    podcast_urls = [p['url'] for p in i.items]
    podcast_urls = map(normalize_feed_url, podcast_urls)
    podcast_urls = filter(None, podcast_urls)

    new = [u for u in podcast_urls if u not in existing_urls]
    rem = [u for e in existing_urls if u not in podcast_urls]

    #remove duplicates
    new = list(set(new))
    rem = list(set(rem))

    for n in new:
        p = podcast_for_url(n, create=True)

        try:
            p.subscribe(user, dev)
        except SubscriptionException as e:
            logger.exception('Legacy API: %(username)s: could not subscribe to podcast %(podcast_url)s on device %(device_id)s' %
                {'username': user.username, 'podcast_url': p.url, 'device_id': dev.id})

    for r in rem:
        p = podcast_for_url(r, create=True)
        try:
            p.unsubscribe(user, dev)
        except SubscriptionException as e:
            logger.exception('Legacy API: %(username): could not unsubscribe from podcast %(podcast_url) on device %(device_id)' %
                {'username': user.username, 'podcast_url': p.url, 'device_id': dev.id})

    return HttpResponse('@SUCCESS', mimetype='text/plain')
示例#3
0
文件: lists.py 项目: fk-lx/mygpo
def create(request, username, format):
    """ Creates a new podcast list and links to it in the Location header """

    title = request.GET.get('title', None)

    if not title:
        return HttpResponseBadRequest('Title missing')

    slug = slugify(title)

    if not slug:
        return HttpResponseBadRequest('Invalid title')

    plist = podcastlist_for_user_slug(request.user._id, slug)

    if plist:
        return HttpResponse('List already exists', status=409)

    urls = parse_subscription(request.body, format)
    podcasts = [podcast_for_url(url, create=True) for url in urls]
    podcast_ids = map(Podcast.get_id, podcasts)

    plist = PodcastList()
    plist.created_timestamp = get_timestamp(datetime.utcnow())
    plist.title = title
    plist.slug = slug
    plist.user = request.user._id
    plist.podcasts = podcast_ids
    plist.save()

    response = HttpResponse(status=201)
    list_url = reverse('api-get-list', args=[request.user.username, slug, format])
    response['Location'] = list_url

    return response
示例#4
0
    def handle(self, *args, **options):

        if len(args) != 5:
            print 'Usage: ./manage.py group-podcasts <url1> <url2> <group-name> <name1> <name2>'
            return

        p1_url = args[0]
        p2_url = args[1]
        group_title = args[2]
        myname = args[3]
        othername = args[4]

        p1 = podcast_for_url(p1_url)
        p2 = podcast_for_url(p2_url)

        p1.group_with(p2, group_title, myname, othername)
示例#5
0
    def handle(self, *args, **options):

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

        for username in options.get('users', []):
            user = User.get_user(username)
            self.add_user_recursive(user, docs)

        if options.get('toplist', False):
            toplist = PodcastToplist()
            for n, podcast in toplist[:25]:
                self.add_podcast_recursive(podcast, docs)

        for podcast_url in options.get('podcasts'):
            podcast = podcast_for_url(podcast_url, docs)
            if not podcast:
                logger.warn('podcast not found for URL "%s"', podcast_url)

            else:
                self.add_podcast_recursive(podcast, docs)

        db = get_main_database()
        docs = sorted(docs)
        self.dump(docs, db)
示例#6
0
文件: episode.py 项目: fk-lx/mygpo
def list_favorites(request):
    user = request.user
    site = RequestSite(request)

    episodes = favorite_episodes_for_user(user)

    recently_listened = get_latest_episodes(user)

    podcast_ids = [episode.podcast for episode in episodes + recently_listened]
    podcasts = podcasts_to_dict(podcast_ids)

    recently_listened = fetch_episode_data(recently_listened, podcasts=podcasts)
    episodes = fetch_episode_data(episodes, podcasts=podcasts)

    favfeed = FavoriteFeed(user)
    feed_url = favfeed.get_public_url(site.domain)

    podcast = podcast_for_url(feed_url)

    token = request.user.favorite_feeds_token

    return render(request, 'favorites.html', {
        'episodes': episodes,
        'feed_token': token,
        'site': site,
        'podcast': podcast,
        'recently_listened': recently_listened,
        })
示例#7
0
文件: backend.py 项目: fk-lx/mygpo
    def _get_obj_fun(self, action):
        url, op = action

        podcast = self.podcasts.get(url,
                podcast_for_url(url, create=True))

        state = podcast_state_for_user_podcast(self.user, podcast)

        fun = self.operations[op]
        return (state, fun)
示例#8
0
文件: views.py 项目: fk-lx/mygpo
    def post(self, request):
        podcast_url = request.POST.get('feed')
        podcast = podcast_for_url(podcast_url)

        if not podcast:
            messages.error(request, _('Podcast with URL "%s" does not exist' %
                                      (podcast_url,)))
            return HttpResponseRedirect(reverse('admin-unify-slugs-select'))

        res = unify_slugs.delay(podcast)
        return HttpResponseRedirect(reverse('admin-unify-slugs-status',
                    args=[res.task_id]))
示例#9
0
文件: views.py 项目: fk-lx/mygpo
def search_podcast(request):
    form = SearchPodcastForm(request.POST)
    if form.is_valid():
        url = form.cleaned_data['url']

        podcast = podcast_for_url(url)
        if not podcast:
            raise Http404

        url = get_podcast_link_target(podcast, 'podcast-publisher-detail')
    else:
        url = reverse('publisher')

    return HttpResponseRedirect(url)
示例#10
0
def search_podcasts(q, limit=20, skip=0):

    if is_url(q):
        url = normalize_feed_url(q)

        podcast = podcast_for_url(url, create=False)

        if not podcast or not podcast.title:

            updater = PodcastUpdater()

            try:
                updater.update(url)
            except NoPodcastCreated as npc:
                return [], 0

        podcast = podcast_for_url(url)
        if podcast:
            return [podcast], 1
        else:
            return [], 0

    return search(q, skip, limit)
示例#11
0
    def handle(self, *args, **options):

        urls = list(map(str.strip, fileinput.input(args)))

        try:
            examples = ExamplePodcasts.get(EXAMPLES_DOCID)
        except ResourceNotFound:
            examples = ExamplePodcasts()
            examples._id = EXAMPLES_DOCID

        podcasts = filter(None, [podcast_for_url(url) for url in urls])
        examples.podcast_ids = [podcast.get_id() for podcast in podcasts]
        examples.updated = datetime.utcnow()
        examples.save()
示例#12
0
文件: podcast.py 项目: fk-lx/mygpo
def subscribe_url(request):
    url = request.GET.get('url', None)

    if not url:
        raise Http404('http://my.gpodder.org/subscribe?url=http://www.example.com/podcast.xml')

    url = normalize_feed_url(url)

    if not url:
        raise Http404('Please specify a valid url')

    podcast = podcast_for_url(url, create=True)

    return HttpResponseRedirect(get_podcast_link_target(podcast, 'subscribe'))
示例#13
0
文件: directory.py 项目: fk-lx/mygpo
def podcast_info(request):
    url = normalize_feed_url(request.GET.get('url', ''))

    # 404 before we query for url, because query would complain
    # about missing param
    if not url:
        raise Http404

    podcast = podcast_for_url(url)
    if not podcast:
            raise Http404
    domain = RequestSite(request).domain
    resp = podcast_data(podcast, domain)

    return JsonResponse(resp)
示例#14
0
文件: episode.py 项目: fk-lx/mygpo
def episode_for_podcast_url(podcast_url, episode_url, create=False):

    if not podcast_url:
        raise QueryParameterMissing('podcast_url')

    if not episode_url:
        raise QueryParameterMissing('episode_url')


    podcast = podcast_for_url(podcast_url, create=create)

    if not podcast:  # podcast does not exist and should not be created
        return None

    return episode_for_podcast_id_url(podcast.get_id(), episode_url, create)
示例#15
0
文件: views.py 项目: fk-lx/mygpo
    def get(self, request):
        user = request.user

        favfeed = FavoriteFeed(user)
        site = RequestSite(request)
        feed_url = favfeed.get_public_url(site.domain)

        podcast = podcast_for_url(feed_url)

        token = request.user.favorite_feeds_token

        return render(request, 'share/favorites.html', {
            'feed_token': token,
            'site': site,
            'podcast': podcast,
            })
示例#16
0
文件: views.py 项目: fk-lx/mygpo
    def post(self, request):
        user = request.user

        feed = FavoriteFeed(user)
        site = RequestSite(request)
        feed_url = feed.get_public_url(site.domain)

        podcast = podcast_for_url(feed_url, create=True)

        if not podcast.get_id() in user.published_objects:
            user.published_objects.append(podcast.get_id())
            user.save()

        updater = PodcastUpdater()
        updater.update(feed_url)

        return HttpResponseRedirect(reverse('share-favorites'))
示例#17
0
文件: views.py 项目: fk-lx/mygpo
def overview(request):
    user = request.user
    site = RequestSite(request)

    subscriptions_token = user.get_token('subscriptions_token')
    userpage_token = user.get_token('userpage_token')
    favfeed_token = user.get_token('favorite_feeds_token')

    favfeed = FavoriteFeed(user)
    favfeed_url = favfeed.get_public_url(site.domain)
    favfeed_podcast = podcast_for_url(favfeed_url)

    return render(request, 'share/overview.html', {
        'site': site,
        'subscriptions_token': subscriptions_token,
        'userpage_token': userpage_token,
        'favfeed_token': favfeed_token,
        'favfeed_podcast': favfeed_podcast,
        })
示例#18
0
文件: tests.py 项目: fk-lx/mygpo
    def test_merge_podcasts(self):
        self.podcast2.subscribe(self.user, self.device)

        # merge podcast2 into podcast1
        pm = PodcastMerger([self.podcast1, self.podcast2], Counter(), [])
        pm.merge()

        # seems that setting delayed_commit = false in the CouchDB config, as
        # well as a delay here fix the intermittent failures.
        # TODO: further investiation needed
        import time
        time.sleep(2)

        # get podcast for URL of podcast2 and unsubscribe from it
        p = podcast_for_url(self.P2_URL)
        p.unsubscribe(self.user, self.device)

        subscriptions = subscribed_podcast_ids_by_user_id(self.user._id)
        self.assertEqual(0, len(subscriptions))
示例#19
0
文件: lists.py 项目: fk-lx/mygpo
def update_list(request, plist, owner, format):
    """ Replaces the podcasts in the list and returns 204 No Content """

    is_own = owner == request.uuser

    if not is_own:
        return HttpResponseForbidden()

    urls = parse_subscription(request.body, format)
    podcasts = [podcast_for_url(url, create=True) for url in urls]
    podcast_ids = map(Podcast.get_id, podcasts)

    @repeat_on_conflict(['podcast_ids'])
    def _update(plist, podcast_ids):
        plist.podcasts = podcast_ids
        plist.save()

    _update(plist=plist, podcast_ids=podcast_ids)

    return HttpResponse(status=204)
示例#20
0
def episode_state_for_ref_urls(user, podcast_url, episode_url):

    if not user:
        raise QueryParameterMissing('user')

    if not podcast_url:
        raise QueryParameterMissing('podcast_url')

    if not episode_url:
        raise QueryParameterMissing('episode_url')


    cache_key = 'episode-state-%s-%s-%s' % (user._id,
            sha1(podcast_url).hexdigest(),
            sha1(episode_url).hexdigest())

    state = cache.get(cache_key)
    if state:
        return state

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

    if state:
        state.ref_url = episode_url
        state.podcast_ref_url = podcast_url
        cache.set(cache_key, state, 60*60)
        return state

    else:
        podcast = podcast_for_url(podcast_url, create=True)
        episode = episode_for_podcast_id_url(podcast.get_id(), episode_url,
            create=True)
        return episode_state_for_user_episode(user, episode)
示例#21
0
文件: views.py 项目: fk-lx/mygpo
    def post(self, request):
        username = request.POST.get('username')
        user = User.get_user(username)
        if user is None:
            messages.error(request, 'User "{username}" not found'.format(username=username))
            return HttpResponseRedirect(reverse('admin-make-publisher-input'))

        feeds = request.POST.get('feeds')
        feeds = feeds.split()
        podcasts = set()

        for feed in feeds:
            podcast = podcast_for_url(feed)

            if podcast is None:
                messages.warning(request, 'Podcast with URL {feed} not found'.format(feed=feed))
                continue

            podcasts.add(podcast)

        self.set_publisher(request, user, podcasts)
        self.send_mail(request, user, podcasts)
        return HttpResponseRedirect(reverse('admin-make-publisher-result'))
示例#22
0
文件: views.py 项目: fk-lx/mygpo
    def get(self, request):

        site = RequestSite(request)

        # check if we're doing a query
        url = request.GET.get('q', None)

        if not url:
            podcast = None
            can_add = False

        else:
            podcast = podcast_for_url(url)

            # if the podcast does already exist, there's nothing more to do
            if podcast:
                can_add = False

            # check if we could add a podcast for the given URL
            else:
                podcast = False
                updater = PodcastUpdater()

                try:
                    can_add = updater.verify_podcast_url(url)

                except (ParserException, FetchFeedException,
                        NoEpisodesException) as ex:
                    can_add = False
                    messages.error(request, unicode(ex))

        return render(request, 'missing.html', {
                'site': site,
                'q': url,
                'podcast': podcast,
                'can_add': can_add,
            })
示例#23
0
    def _update_podcast(self, podcast, parsed, episodes):
        """ updates a podcast according to new parser results """

        # we need that later to decide if we can "bump" a category
        prev_latest_episode_timestamp = podcast.latest_episode_timestamp

        old_json = copy.deepcopy(podcast.to_json())

        podcast.title = parsed.title or podcast.title
        podcast.urls = list(set(podcast.urls + parsed.urls))
        podcast.description = parsed.description or podcast.description
        podcast.subtitle = parsed.subtitle or podcast.subtitle
        podcast.link = parsed.link or podcast.link
        podcast.logo_url = parsed.logo or podcast.logo_url
        podcast.author = parsed.author or podcast.author
        podcast.language = parsed.language or podcast.language
        podcast.content_types = parsed.content_types or podcast.content_types
        podcast.tags['feed'] = parsed.tags or podcast.tags.get('feed', [])
        podcast.common_episode_title = parsed.common_title or podcast.common_episode_title
        podcast.new_location = parsed.new_location or podcast.new_location
        podcast.flattr_url = parsed.flattr or podcast.flattr_url
        podcast.hub = parsed.hub or podcast.hub
        podcast.license = parsed.license or podcast.license


        if podcast.new_location:
            new_podcast = podcast_for_url(podcast.new_location)
            if new_podcast != podcast:
                self._mark_outdated(podcast, 'redirected to different podcast')
                return

            elif not new_podcast:
                podcast.urls.insert(0, podcast.new_location)


        logger.info('Retrieved %d episodes in total', len(episodes))

        # latest episode timestamp
        eps = filter(lambda e: bool(e.released), episodes)
        eps = sorted(eps, key=lambda e: e.released)

        podcast.update_interval = get_update_interval(eps)

        if eps:
            podcast.latest_episode_timestamp = eps[-1].released

        podcast.episode_count = episode_count_for_podcast(podcast)


        self._update_categories(podcast, prev_latest_episode_timestamp)

        # try to download the logo and reset logo_url to None on http errors
        found = self._save_podcast_logo(podcast.logo_url)
        if not found:
            podcast.logo_url = None

        # The podcast is always saved (not just when there are changes) because
        # we need to record the last update
        logger.info('Saving podcast.')
        podcast.last_update = datetime.utcnow()
        podcast.save()


        try:
            subscribe_at_hub(podcast)
        except SubscriptionError as se:
            logger.warn('subscribing to hub failed: %s', str(se))

        assign_slug(podcast, PodcastSlug)
        assign_missing_episode_slugs(podcast)
示例#24
0
文件: settings.py 项目: fk-lx/mygpo
 def podcast_settings(user, url):
     podcast = podcast_for_url(url)
     if not podcast:
         raise Http404
     obj = podcast_state_for_user_podcast(user, podcast)
     return obj, obj, udb
示例#25
0
def episodes(request, username, version=1):

    version = int(version)
    now = datetime.now()
    now_ = get_timestamp(now)
    ua_string = request.META.get('HTTP_USER_AGENT', '')

    if request.method == 'POST':
        try:
            actions = parse_request_body(request)
        except (JSONDecodeError, UnicodeDecodeError, ValueError) as e:
            msg = ('Could not decode episode update POST data for ' +
                   'user %s: %s') % (username,
                   request.body.decode('ascii', errors='replace'))
            logger.warn(msg, exc_info=True)
            return HttpResponseBadRequest(msg)

        logger.info('start: user %s: %d actions from %s' % (request.user._id, len(actions), ua_string))

        # handle in background
        if len(actions) > dsettings.API_ACTIONS_MAX_NONBG:
            bg_handler = dsettings.API_ACTIONS_BG_HANDLER
            if bg_handler is not None:

                modname, funname = bg_handler.rsplit('.', 1)
                mod = import_module(modname)
                fun = getattr(mod, funname)

                fun(request.user, actions, now, ua_string)

                # TODO: return 202 Accepted
                return JsonResponse({'timestamp': now_, 'update_urls': []})


        try:
            update_urls = update_episodes(request.user, actions, now, ua_string)
        except DeviceUIDException as e:
            logger.warn('invalid device UID while uploading episode actions for user %s', username)
            return HttpResponseBadRequest(str(e))

        except InvalidEpisodeActionAttributes as e:
            msg = 'invalid episode action attributes while uploading episode actions for user %s' % (username,)
            logger.warn(msg, exc_info=True)
            return HttpResponseBadRequest(str(e))

        logger.info('done:  user %s: %d actions from %s' % (request.user._id, len(actions), ua_string))
        return JsonResponse({'timestamp': now_, 'update_urls': update_urls})

    elif request.method == 'GET':
        podcast_url= request.GET.get('podcast', None)
        device_uid = request.GET.get('device', None)
        since_     = request.GET.get('since', None)
        aggregated = parse_bool(request.GET.get('aggregated', False))

        try:
            since = int(since_) if since_ else None
        except ValueError:
            return HttpResponseBadRequest('since-value is not a valid timestamp')

        if podcast_url:
            podcast = podcast_for_url(podcast_url)
            if not podcast:
                raise Http404
        else:
            podcast = None

        if device_uid:

            try:
                device = request.user.get_device_by_uid(device_uid)
            except DeviceDoesNotExist as e:
                return HttpResponseNotFound(str(e))

        else:
            device = None

        changes = get_episode_changes(request.user, podcast, device, since,
                now_, aggregated, version)

        return JsonResponse(changes)