Exemple #1
0
    def handle(self, *args, **options):
        dry_run = not options.get('run')
        if not dry_run and not settings.DISABLE_GETCONNECT:
            self.stderr.write(
                'Refusing to do a live run with DISABLE_GETCONNECT set to false'
            )
            return
        elif dry_run:
            self.stdout.write('DRY RUN')

        with open(options.get('source')) as source:
            for i, line in enumerate(source):
                parsed = json.loads(line)
                try:
                    fake_req = FakeReq(ua=parsed['profile']['ua'] or 'Unknown',
                                       ip=parsed['profile']['ip'],
                                       country=parsed['profile']['country'])
                    podcast = parsed['podcast']
                except Exception as e:
                    self.stderr.write('(%d): %s' % (i, str(e)))
                    continue

                try:
                    raw_ts = TS_KILLA.match(parsed['timestamp']).group(1)
                except Exception:
                    self.stderr.write('(%d): Failed to parse ts %s' %
                                      (i, parsed['timestamp']))
                    continue

                ts = datetime.datetime.combine(
                    datetime.datetime.strptime(raw_ts,
                                               '%Y-%m-%dT%H:%M:%S').date(),
                    datetime.time.min)

                write_subscription(fake_req, podcast, ts=ts, dry_run=dry_run)

                if i % 500 == 0:
                    self.stdout.write('Progress: %d lines' % i)

        if dry_run:
            self.stdout.write(
                'Dry run: no results were committed. Use --run to actually run'
            )
    def handle(self, *args, **options):
        dry_run = not options.get('run')
        if not dry_run and not settings.DISABLE_GETCONNECT:
            self.stderr.write('Refusing to do a live run with DISABLE_GETCONNECT set to false')
            return
        elif dry_run:
            self.stdout.write('DRY RUN')

        with open(options.get('source')) as source:
            for i, line in enumerate(source):
                parsed = json.loads(line)
                try:
                    fake_req = FakeReq(
                        ua=parsed['profile']['ua'] or 'Unknown',
                        ip=parsed['profile']['ip'],
                        country=parsed['profile']['country'])
                    podcast = parsed['podcast']
                except Exception as e:
                    self.stderr.write('(%d): %s' % (i, str(e)))
                    continue

                try:
                    raw_ts = TS_KILLA.match(parsed['timestamp']).group(1)
                except Exception:
                    self.stderr.write('(%d): Failed to parse ts %s' % (i, parsed['timestamp']))
                    continue

                ts = datetime.datetime.combine(
                    datetime.datetime.strptime(raw_ts, '%Y-%m-%dT%H:%M:%S').date(),
                    datetime.time.min)

                write_subscription(fake_req, podcast, ts=ts, dry_run=dry_run)

                if i % 500 == 0:
                    self.stdout.write('Progress: %d lines' % i)

        if dry_run:
            self.stdout.write('Dry run: no results were committed. Use --run to actually run')
Exemple #3
0
def feed(req, podcast_slug):
    pod = get_object_or_404(Podcast, slug=podcast_slug)

    items = []
    episodes = pod.get_episodes()
    is_demo = UserSettings.get_from_user(pod.owner).plan == plans.PLAN_DEMO

    channel_explicit_tag = '<itunes:explicit>%s</itunes:explicit>' % (
        'yes' if pod.is_explicit else 'no')

    for ep in episodes:
        ep_url = _asset(ep.audio_url +
                        '?x-source=rss&x-episode=%s' % str(ep.id))

        md_desc = ep.get_html_description(is_demo=is_demo)

        explicit_tag = ''
        if ep.explicit_override != PodcastEpisode.EXPLICIT_OVERRIDE_CHOICE_NONE:
            explicit_tag = '<itunes:explicit>%s</itunes:explicit>' % (
                'yes' if ep.explicit_override ==
                PodcastEpisode.EXPLICIT_OVERRIDE_CHOICE_EXPLICIT else 'clean')
        else:
            explicit_tag = channel_explicit_tag

        items.append('\n'.join([
            '<item>',
            '<title>%s</title>' % escape(ep.title),
            '<description><![CDATA[%s]]></description>' % md_desc,
            '<link>%s</link>' % escape(ep_url),
            '<guid isPermaLink="false">https://pinecast.com/guid/%s</guid>' %
            escape(str(ep.id)),
            '<pubDate>%s</pubDate>' %
            formatdate(time.mktime(ep.publish.timetuple())),
            explicit_tag,
            '<itunes:author>%s</itunes:author>' % escape(pod.author_name),
            '<itunes:subtitle>%s</itunes:subtitle>' % escape(ep.subtitle),
            '<itunes:image href=%s />' % quoteattr(_asset(ep.image_url)),
            '<itunes:duration>%s</itunes:duration>' %
            escape(ep.formatted_duration()),
            '<enclosure url=%s length=%s type=%s />' %
            (quoteattr(ep_url), quoteattr(str(
                ep.audio_size)), quoteattr(ep.audio_type)),
            ('<dc:copyright>%s</dc:copyright>' %
             escape(ep.copyright)) if ep.copyright else '',
            ('<dc:rights>%s</dc:rights>' %
             escape(ep.license)) if ep.license else '',
            '</item>',
        ]))

    categories = sorted([c.category for c in pod.podcastcategory_set.all()],
                        key=lambda c: len(c))
    category_map = {}
    for cat in categories:
        spl = cat.split('/')
        cursor = category_map
        for i in spl:
            cursor.setdefault(i, {})
            cursor = cursor[i]

    def render_cat(c):
        for k, v in c.items():
            if not v:
                yield '<itunes:category text=%s />' % quoteattr(k)
            else:
                yield '<itunes:category text=%s>%s</itunes:category>' % (
                    quoteattr(k), '\n'.join(render_cat(v)))

    if pod.rss_redirect:
        canonical_url = pod.rss_redirect
    else:
        canonical_url = 'https://pinecast.com/feed/%s' % escape(pod.slug)

    content = [
        '<?xml version="1.0" encoding="UTF-8"?>',
        '<rss xmlns:atom="http://www.w3.org/2005/Atom"',
        '     xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"',
        '     xmlns:dc="http://purl.org/dc/elements/1.1/"',
        '     version="2.0">',
        '<channel>',
        '<title>%s</title>' % escape(pod.name),
        '<link>%s</link>' % escape(pod.homepage),
        '<atom:link href="%s" rel="self" type="application/rss+xml" />' %
        canonical_url,
        '<language>%s</language>' % escape(pod.language),
        '<copyright>%s</copyright>' % escape(pod.copyright),
        '<generator>Pinecast (https://pinecast.com)</generator>',
        ('<itunes:new-feed-url>%s</itunes:new-feed-url>' %
         escape(canonical_url) if pod.rss_redirect else ''),
        ('<itunes:subtitle>%s</itunes:subtitle>' %
         escape(pod.subtitle)) if pod.subtitle else '',
        '<itunes:author>%s</itunes:author>' % escape(pod.author_name),
        '<description><![CDATA[%s]]></description>' % pod.description,
        '<itunes:owner>',
        '<itunes:name>%s</itunes:name>' % escape(pod.author_name),
        '<itunes:email>%s</itunes:email>' % escape(pod.owner.email),
        '</itunes:owner>',
        channel_explicit_tag,
        '<itunes:image href=%s />' % quoteattr(_asset(pod.cover_image)),
        '<image>',
        '<title>%s</title>' % escape(pod.name),
        '<link>%s</link>' % escape(pod.homepage),
        '<url>%s</url>' % escape(_asset(pod.cover_image)),
        '</image>',
        '\n'.join(render_cat(category_map)),
        '\n'.join(items),
        '</channel>',
        '</rss>',
    ]
    if UserSettings.get_from_user(pod.owner).plan == plans.PLAN_DEMO:
        if len(episodes) > 10:
            content.append(
                '<!-- This feed is truncated because the owner is not a paid customer. -->'
            )
        else:
            content.append(
                '<!-- This feed will be truncated at 10 items because the owner is not a paid customer. -->'
            )

    # Write the log of this to the analytics back-end(s)
    analytics_log.write_subscription(req, pod)

    resp = HttpResponse('\n'.join(c for c in content if c),
                        content_type='application/rss+xml',
                        status=200 if not pod.rss_redirect else 301)
    if pod.rss_redirect:
        resp.setdefault('Location', pod.rss_redirect)

    resp.setdefault('Cache-Control', 'public, max-age=120')
    resp.setdefault('Access-Control-Allow-Origin', '*')
    resp.setdefault('Access-Control-Request-Method', 'GET')

    return resp
Exemple #4
0
def feed(req, podcast_slug):
    pod = get_object_or_404(Podcast, slug=podcast_slug)

    items = []
    episodes = pod.get_episodes()
    is_demo = UserSettings.get_from_user(pod.owner).plan == plans.PLAN_DEMO

    channel_explicit_tag = '<itunes:explicit>%s</itunes:explicit>' % ('yes' if pod.is_explicit else 'no')

    for ep in episodes:
        ep_url = _asset(ep.audio_url + '?x-source=rss&x-episode=%s' % str(ep.id))

        md_desc = ep.get_html_description(is_demo=is_demo)

        explicit_tag = ''
        if ep.explicit_override != PodcastEpisode.EXPLICIT_OVERRIDE_CHOICE_NONE:
            explicit_tag = '<itunes:explicit>%s</itunes:explicit>' % (
                'yes' if ep.explicit_override == PodcastEpisode.EXPLICIT_OVERRIDE_CHOICE_EXPLICIT else 'clean')
        else:
            explicit_tag = channel_explicit_tag

        items.append('\n'.join([
            '<item>',
            '<title>%s</title>' % escape(ep.title),
            '<description><![CDATA[%s]]></description>' % md_desc,
            '<link>%s</link>' % escape(ep_url),
            '<guid isPermaLink="false">https://pinecast.com/guid/%s</guid>' % escape(str(ep.id)),
            '<pubDate>%s</pubDate>' % formatdate(time.mktime(ep.publish.timetuple())),
            explicit_tag,
            '<itunes:author>%s</itunes:author>' % escape(pod.author_name),
            '<itunes:subtitle>%s</itunes:subtitle>' % escape(ep.subtitle),
            '<itunes:image href=%s />' % quoteattr(_asset(ep.image_url)),
            '<itunes:duration>%s</itunes:duration>' % escape(ep.formatted_duration()),
            '<enclosure url=%s length=%s type=%s />' % (
                quoteattr(ep_url), quoteattr(str(ep.audio_size)), quoteattr(ep.audio_type)),
            ('<dc:copyright>%s</dc:copyright>' % escape(ep.copyright)) if ep.copyright else '',
            ('<dc:rights>%s</dc:rights>' % escape(ep.license)) if ep.license else '',
            '</item>',
        ]))

    categories = sorted([c.category for c in pod.podcastcategory_set.all()], key=lambda c: len(c))
    category_map = {}
    for cat in categories:
        spl = cat.split('/')
        cursor = category_map
        for i in spl:
            cursor.setdefault(i, {})
            cursor = cursor[i]

    def render_cat(c):
        for k, v in c.items():
            if not v:
                yield '<itunes:category text=%s />' % quoteattr(k)
            else:
                yield '<itunes:category text=%s>%s</itunes:category>' % (
                    quoteattr(k), '\n'.join(render_cat(v)))

    if pod.rss_redirect:
        canonical_url = pod.rss_redirect
    else:
        canonical_url = 'https://pinecast.com/feed/%s' % escape(pod.slug)

    content = [
        '<?xml version="1.0" encoding="UTF-8"?>',
        '<rss xmlns:atom="http://www.w3.org/2005/Atom"',
        '     xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"',
        '     xmlns:dc="http://purl.org/dc/elements/1.1/"',
        '     version="2.0">',
        '<channel>',
        '<title>%s</title>' % escape(pod.name),
        '<link>%s</link>' % escape(pod.homepage),
        '<atom:link href="%s" rel="self" type="application/rss+xml" />' % canonical_url,
        '<language>%s</language>' % escape(pod.language),
        '<copyright>%s</copyright>' % escape(pod.copyright),
        '<generator>Pinecast (https://pinecast.com)</generator>',
        ('<itunes:new-feed-url>%s</itunes:new-feed-url>' % escape(canonical_url) if pod.rss_redirect else ''),
        ('<itunes:subtitle>%s</itunes:subtitle>' % escape(pod.subtitle)) if pod.subtitle else '',
        '<itunes:author>%s</itunes:author>' % escape(pod.author_name),
        '<description><![CDATA[%s]]></description>' % pod.description,
        '<itunes:owner>',
        '<itunes:name>%s</itunes:name>' % escape(pod.author_name),
        '<itunes:email>%s</itunes:email>' % escape(pod.owner.email),
        '</itunes:owner>',
        channel_explicit_tag,
        '<itunes:image href=%s />' % quoteattr(_asset(pod.cover_image)),
        '<image>',
        '<title>%s</title>' % escape(pod.name),
        '<link>%s</link>' % escape(pod.homepage),
        '<url>%s</url>' % escape(_asset(pod.cover_image)),
        '</image>',
        '\n'.join(render_cat(category_map)),
        '\n'.join(items),
        '</channel>',
        '</rss>',
    ]
    if UserSettings.get_from_user(pod.owner).plan == plans.PLAN_DEMO:
        if len(episodes) > 10:
            content.append('<!-- This feed is truncated because the owner is not a paid customer. -->')
        else:
            content.append('<!-- This feed will be truncated at 10 items because the owner is not a paid customer. -->')

    # Write the log of this to the analytics back-end(s)
    analytics_log.write_subscription(req, pod)

    resp = HttpResponse(
        '\n'.join(c for c in content if c),
        content_type='application/rss+xml',
        status=200 if not pod.rss_redirect else 301)
    if pod.rss_redirect:
        resp.setdefault('Location', pod.rss_redirect)

    resp.setdefault('Cache-Control', 'public, max-age=120')
    resp.setdefault('Access-Control-Allow-Origin', '*')
    resp.setdefault('Access-Control-Request-Method', 'GET')

    return resp