Ir al contenido principal

Ralsina.Me — El sitio web de Roberto Alsina

Publicaciones sobre programming (publicaciones antiguas, página 73)

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.

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

Nikola 1.2 en la calle!

Por­qué ha­cer si­tios es­tá­ti­co­s? Por­que no usan re­cur­so­s, por­que son a prue­ba de fu­tu­ro, por­que es fá­ci­l, son se­gu­ro­s, y por­que no te ata a una pla­ta­for­ma.

Fea­tu­res nue­vo­s:

  • Ga­­le­­rias de imá­­ge­­nes (po­­­nés fo­­­tos en una ca­r­­pe­­ta y lis­­to)

  • Se­r­­ver web in­­co­r­­po­­­ra­­do pa­­ra pre­­views ("­­doit -a se­r­­ve")

  • Co­­­man­­dos pa­­ra crear nue­­vos po­s­­ts fá­­ci­l­­men­­te ("­­doit -a new_­­po­s­­t")

  • So­­­po­r­­te de Google Si­te­­maps

  • Un ma­­nua­­l!

  • Si­­tio de de­­mo co­m­­ple­­ti­­to in­­cluí­­do

  • So­­­po­r­­ta de­­plo­­­y­­ment au­­to­­­má­­ti­­co ("­­doit -a de­­plo­­­y")

  • Re­­di­­re­c­­cio­­­nes clien­­t-­­si­­de

Y por su­pues­to los fea­tu­res vie­jo­s:

  • Es­­cri­­bís los po­s­­ts en res­­tru­c­­tu­­red text

  • Es­­ti­­lo li­m­­pio y cus­­to­­­mi­­za­­ble (con boots­­tra­­p)

  • Co­­­men­­ta­­rios via Dis­­qus

  • So­­­po­r­­ta cua­l­­quier sis­­te­­ma de ana­­li­­ti­­cas web

  • Blogs con tags, fee­­d­s, fee­­ds pa­­ra tags, pá­­gi­­nas de ín­­di­­ce, ín­­di­­ce por año, por ta­­g, y má­s.

  • Fun­­cio­­­na co­­­mo CMS pa­­ra co­­sas que no son pa­r­­te del blog

  • Te­m­­pla­­tes li­m­­pios y cus­­to­­­mi­­za­­bles (u­san­­do Mako)

  • Pu­­ro py­­thon y po­­­co py­­thon (u­­nas 600 lí­­nea­s)

  • Bui­l­­ds in­­te­­li­­gen­­tes (só­­­lo ge­­ne­­ra las pá­­gi­­nas ne­­ce­s­a­­ria­s, gra­­cias a doi­­t)

  • Fá­­cil de agre­­gar nue­­vos co­­­man­­dos y op­­cio­­­nes

  • Mues­­tra có­­­di­­go con re­s­al­­ta­­do de si­n­­ta­­xis

En es­te mo­men­to Niko­la ha­ce to­do lo que yo ne­ce­si­to, así que si al­guien lo prue­ba y ne­ce­si­ta al­go­... bue­no, es un buen mo­men­to pa­ra pe­dir :-)

Más in­fo en http://­niko­la-­ge­ne­ra­to­r.­google­co­de.­com

¡Nikola 1.1 en la calle!

Lo es­cri­bí pa­ra es­te mis­mo si­tio, pe­ro de­ci­dí que tal vez sea útil pa­ra otro­s. Los ob­je­ti­vos prin­ci­pa­les de Niko­la so­n:

  • Po­­­co có­­­di­­go: po­r­­que no quie­­ro man­­te­­ner un mon­s­­truo pa­­ra es­­te blo­­­g.

  • Ge­­ne­­ra­­ción rá­­pi­­da de pá­­gi­­na­s: aña­­dir un post no de­­be­­­ría ta­r­­dar mas de 5 se­­gun­­dos en re­­contruir el si­­tio.

  • Ge­­ne­­rar si­­tios es­­tá­­ti­­co­­s: de­­plo­­­y­­ment usan­­do rs­­yn­­c!

  • Ge­­ne­­ra­­ción fle­­xi­­ble de pá­­gi­­na­s: po­­­dés de­­ci­­dir ado­n­­de te­r­­mi­­na ca­­da co­­­sa en el si­­tio.

  • Te­m­­pla­­tes po­­­de­­ro­­sas: Usa Mako

  • Ma­­rkup li­m­­pio pa­­ra los po­s­­ts: Usa Do­­­cu­­tils

  • No ha­­ce bui­l­­ds idio­­­ta­s: Usa doit

  • HT­­ML li­m­­pio por de­­fau­l­­t: Usa boots­­trap

  • Co­­­men­­ta­­rios sin lío­­s: Usa Dis­­qus

  • Tags, con sus pro­­­pios fee­­ds

  • Fá­­cil pa­­ra ha­­cer blogs

  • Pá­­gi­­nas fue­­ra del blog

  • Si­­tios mu­l­­ti­­li­n­­gües

Creo que es­ta ver­sión ini­cial lo­gra esos ob­je­ti­vo­s, pe­ro por su­pues­to es me­jo­ra­ble. Se agra­de­ce el fee­dba­ck!

La pá­gi­na de Niko­la es http://­niko­la-­ge­ne­ra­to­r.­google­co­de.­com


Contents © 2000-2023 Roberto Alsina