Ir al contenido principal

Ralsina.Me — El sitio web de Roberto Alsina

Publicaciones sobre python (publicaciones antiguas, página 74)

Screencast de Nikola

Lo nuevo es el comando nikola init foldername, el resto es todo viejo. Básicamente, no tenés más una copia de Nikola por sitio, y está todo en un lugar centralizado.

Todavía podés hacer tus propios temas poniéndolos en themes/themename y agregar tareas, archivos, etc. La configuración en dodo.py no cambia excepto el pedacito mágico que es diferente.

En­ton­ce­s: no muy in­va­si­vo, fá­cil de mi­gra­r, y per­mi­te up­da­tes más sen­ci­llos en el fu­tu­ro, mien­tras no rom­pa­mos na­da de for­ma in­com­pa­ti­ble.

El vi­deo:

Soporte de Jinja en Nikola, listo para probar

La ver­da­d, no hay gran di­fe­ren­cia en la API:

//ralsina.me/galleries/random/jinjavsmako.thumbnail.png

¡Has­ta por­té el te­ma de­fault a Jin­ja! Y no, tam­po­co es muy dis­tin­to del la­do de los tem­pla­tes:

//ralsina.me/galleries/random/jinjavsmako1.thumbnail.png

Pe­ro bue­no, so­bre gus­tos no hay na­da es­cri­to, di­jo la vie­ja la­mien­do sapo­s. Otros mo­to­res de tem­pla­te son pro­ba­ble­men­te fá­ci­les de usar mien­tras ten­gan se­mán­ti­cas pa­re­ci­da­s.

Bran­ch pa­ra re­view acá en gi­thub y sí, cual­quie­ra que es­té le­yen­do es­to y se­pa de Jin­ja2 o Py­thon es bien­ve­ni­do a ha­cer un re­view.

Un port de blog.txt a Nikola

Si tie­ne al­go lin­do, lo hi­zo él. Si tie­ne al­go feo o ro­to, lo hi­ce yo.

Lo hi­ce bá­si­ca­men­te pa­ra ver si era di­fí­cil por­tar te­mas de wor­dpress a Niko­la. Y es po­si­ble, pe­ro con­sis­te en leer php y rees­cri­bir co­mo tem­pla­tes de Mako.

Si bien no es un port per­fec­to ni mu­cho me­no­s, es un pun­to de par­ti­da pa­ra al­guien que real­men­te le in­te­re­se.

Así se ve:

//ralsina.me/galleries/random/blogtxt.png

Y acá es­tá el ar­chi­vo. Pa­ra usar­lo, ex­pan­dir­lo en la car­pe­ta the­me­s, con­fi­gu­rar el do­do­.­py pa­ra qu THE­ME sea "blo­gtx­t", re­build y lis­to.

Es­te te­ma es LGPL (ver li­cen­se.­txt in­cluí­do­). Buen pro­ve­cho!

Smiljan, un Mini Generador de Planetas

Ha­ce po­co, cam­bian­do un pla­ne­ta de un ser­ver a otro, se pin­chó to­do. Los pos­ts vie­jos eran nue­vo­s, fee­ds que no te­nían un post ha­ce 2 años se po­nían siem­pre pri­me­ra­s... un de­sas­tre.

Po­dría ha­ber vuel­to al ser­ver vie­jo, y em­pe­za­do a de­bu­guear por­qué raw­dog ha­cía eso, o cam­biar a pla­ne­t, o bus­car otro pro­gra­ma, o usar un agre­ga­dor on­li­ne.

En vez de ha­cer eso, me pu­se a pen­sar... ya es­cri­bí va­rios lec­to­res de fee­d­s... Fee­dpar­ser es­tá sien­do man­te­ni­do ac­ti­va­men­te... raw­dog y pla­net es­tán aban­do­na­dos (pa­re­ce)... es di­fí­cil im­ple­men­tar el pla­ne­ta mí­ni­mo?

Bue­no, no, la ver­dad que no. Ti­po que me lle­vó 4 ho­ras y no fué muy di­fí­ci­l.

Un mo­ti­vo por el cual ha­cer es­to fué más fá­cil que pa­ra los que hi­cie­ron raw­dog o pla­ne­t, es que no me pu­se a ha­cer un ge­ne­ra­dor de si­tios es­tá­ti­co­s, por­que ya ten­go uno así que to­do lo que es­te pro­gra­ma (se lla­ma Smi­l­jan) ha­ce es:

  • Pa­r­­sea una lis­­ta de fee­­ds y la gua­r­­da en una ba­­se de da­­tos si ha­­ce fa­l­­ta.

  • Des­­ca­r­­ga esos fee­­ds (res­­pe­­tan­­do etag y mo­­­di­­fie­­d-­­si­n­­ce)

  • Pa­r­­sea esos fee­­ds bus­­can­­do po­s­­ts (lo ha­­ce fee­­dpa­r­se­­r)

  • Ca­r­­ga los po­s­­ts (un su­­b­­co­­­jun­­to de esos da­­to­­s) en la ba­­se de da­­to­­s.

  • Usa esas en­­tra­­das pa­­ra ge­­ne­­rar en­­tra­­da pa­­ra Niko­­­la

  • Usa Niko­­­la pa­­ra ge­­ne­­rar y su­­bir el si­­tio

Así que acá es­tá el re­sul­ta­do fi­na­l: http://­pla­ne­ta.­p­y­tho­n.or­g.ar que to­da­vía ne­ce­si­ta te­mas y otras co­sas, pe­ro an­da.

Im­ple­men­té Smi­l­jan co­mo 3 ta­reas de doi­t, lo que lo in­te­gra muy fa­cil­men­te con Niko­la (si pro­bas­te Niko­la: po­nés "from smi­l­jan im­port *" en tu do­do­.­p­y, y un ar­chi­vo fee­ds con los fee­ds en for­ma­to raw­dog y lis­to) y voi­lá, co­rrer es­to ha­ce un pla­ne­t:

doit load_feeds update_feeds generate_posts render_site deploy

Acá es­tá el có­di­go de smi­l­jan.­py en es­ta­do "ha­ck chan­cho que an­da". Buen pro­ve­cho!

# -*- coding: utf-8 -*-
import codecs
import datetime
import glob
import os
import sys

from doit.tools import timeout
import feedparser
import peewee


class Feed(peewee.Model):
    name = peewee.CharField()
    url = peewee.CharField(max_length = 200)
    last_status = peewee.CharField()
    etag = peewee.CharField(max_length = 200)
    last_modified = peewee.DateTimeField()

class Entry(peewee.Model):
    date = peewee.DateTimeField()
    feed = peewee.ForeignKeyField(Feed)
    content = peewee.TextField(max_length = 20000)
    link = peewee.CharField(max_length = 200)
    title = peewee.CharField(max_length = 200)
    guid = peewee.CharField(max_length = 200)

Feed.create_table(fail_silently=True)
Entry.create_table(fail_silently=True)

def task_load_feeds():
    feeds = []
    feed = name = None
    for line in open('feeds'):
        line = line.strip()
        if line.startswith('feed'):
            feed = line.split(' ')[2]
        if line.startswith('define_name'):
            name = ' '.join(line.split(' ')[1:])
        if feed and name:
            feeds.append([feed, name])
            feed = name = None

    def add_feed(name, url):
        f = Feed.create(
            name=name,
            url=url,
            etag='caca',
            last_modified=datetime.datetime(1970,1,1),
            )
        f.save()

    def update_feed_url(feed, url):
        feed.url = url
        feed.save()

    for feed, name in feeds:
        f = Feed.select().where(name=name)
        if not list(f):
            yield {
                'name': name,
                'actions': ((add_feed,(name, feed)),),
                'file_dep': ['feeds'],
                }
        elif list(f)[0].url != feed:
            yield {
                'name': 'updating:'+name,
                'actions': ((update_feed_url,(list(f)[0], feed)),),
                }


def task_update_feeds():
    def update_feed(feed):
        modified = feed.last_modified.timetuple()
        etag = feed.etag
        parsed = feedparser.parse(feed.url,
            etag=etag,
            modified=modified
        )
        try:
            feed.last_status = str(parsed.status)
        except:  # Probably a timeout
            # TODO: log failure
            return
        if parsed.feed.get('title'):
            print parsed.feed.title
        else:
            print feed.url
        feed.etag = parsed.get('etag', 'caca')
        modified = tuple(parsed.get('date_parsed', (1970,1,1)))[:6]
        print "==========>", modified
        modified = datetime.datetime(*modified)
        feed.last_modified = modified
        feed.save()
        # No point in adding items from missinfg feeds
        if parsed.status > 400:
            # TODO log failure
            return
        for entry_data in parsed.entries:
            print "========================================="
            date = entry_data.get('updated_parsed', None)
            if date is None:
                date = entry_data.get('published_parsed', None)
            if date is None:
                print "Can't parse date from:"
                print entry_data
                return False
            date = datetime.datetime(*(date[:6]))
            title = "%s: %s" %(feed.name, entry_data.get('title', 'Sin título'))
            content = entry_data.get('description',
                    entry_data.get('summary', 'Sin contenido'))
            guid = entry_data.get('guid', entry_data.link)
            link = entry_data.link
            print repr([date, title])
            entry = Entry.get_or_create(
                date = date,
                title = title,
                content = content,
                guid=guid,
                feed=feed,
                link=link,
            )
            entry.save()
    for feed in Feed.select():
        yield {
            'name': feed.name.encode('utf8'),
            'actions': [(update_feed,(feed,))],
            'uptodate': [timeout(datetime.timedelta(minutes=20))],
            }

def task_generate_posts():

    def generate_post(entry):
        meta_path = os.path.join('posts',str(entry.id)+'.meta')
        post_path = os.path.join('posts',str(entry.id)+'.txt')
        with codecs.open(meta_path, 'wb+', 'utf8') as fd:
            fd.write(u'%s\n' % entry.title.replace('\n', ' '))
            fd.write(u'%s\n' % entry.id)
            fd.write(u'%s\n' % entry.date.strftime('%Y/%m/%d %H:%M'))
            fd.write(u'\n')
            fd.write(u'%s\n' % entry.link)
        with codecs.open(post_path, 'wb+', 'utf8') as fd:
            fd.write(u'.. raw:: html\n\n')
            content = entry.content
            if not content:
                content = u'Sin contenido'
            for line in content.splitlines():
                fd.write(u'    %s\n' % line)

    for entry in Entry.select().order_by(('date', 'desc')):
        yield {
            'name': entry.id,
            'actions': [(generate_post, (entry,))],
            }

Nikola 2.1.1 + GitHub

Por otro la­do, si pro­bas­te 2.1 y no te fun­cio­nó, pro­bá 2.1.1, por­que me ol­vi­dé de agre­gar un par de ar­chi­vos en uno de los te­mas en 2.1


Contents © 2000-2023 Roberto Alsina