Lua – Obtener los últimos estados de tu cuenta en un nodo GNUsocial

En realidad es algo más que solamente obtener los últimos estados. Este código escrito en lua5.1 es la mezcla de varios posts que ya hemos publicado por aquí.

Hace no mucho publicamos un articulo de como obtener archivos grandes con Lua. Por ejemplo un archivo de un vídeo grande. Para ello usábamos luacurl. Luego publicamos otro post sobre como publicar en GNUSocial estados en un programa escrito en Lua que también tiraba de luacurl.

Tanto en un post como en otro vimos como bajar archivos y guardarlos en nuestro disco así como la forma en la que podemos autenticarnos en un nodo gnusocial para publicar algo allí.

Publicar no requiere de bajar nada a disco pero si lo que buscamos es obtener el time line de estados de nuestro usuario vamos a tener que obtener un xml y parsearlo. Para esa tarea vamos a usar libXML.

Digamos pues que este ejemplo tira de libcurl y libXML para que todo funcione bien.
Aparte de tener lua5.1 en el sistema instalado requerimos de las librerías:

Si deseásemos almacenarlos en una base de datos mysql requeriríamos de luasql, puedes ver un ejemplo aquí: https://mierda.tv/2017/12/19/luasql-mysql-acceso-a-bases-de-datos-mariadb-desde-script-en-lua/

En debian tirando de luarocks se pueden instalar tanto luacurl como luaxml con la peculiaridad de que luacurl puede que nos de algún problemilla que se soluciona leyendo este post.

Vamos al lio.

Este código esta estructurado en 3 archivos y puedes bajarlo desde aquí: LuaGetUserTimeLineGNUsocial.tar.gz

  • main.lua — El archivo principal que ejecutaremos con lua5.1
  • conf.lua — Contiene la configuración de usuario y nodo gnusocial
  • functions.lua — 2 funciones, una para bajar el archivo xml del timeline del usuario y otra para parsearlo y mostrar los estados.

Comenzamos viendo el archivo main.lua:

require("functions")

get_user_timeline()
show_last_status()

Como vemos es muy sencillo. Basicamente incluye el archivo functions.lua que es en el que están las funciones que luego llamamos en orden.
Esas funciones son get_user_timeline() y show_last_status()

Veamos que hacen mirando el código de functions.lua :

function get_user_timeline()
	require("luacurl") -- https://luarocks.org/modules/luarocks/luacurl
	require("conf")

	headers = {
			"Accept: text/*",
			"Accept-Language: en",
			"Accept-Charset: iso-8859-1,*,utf-8",
			"Cache-Control: no-cache"
	}

	useragent = "Lua Music Social 0.1"
	userpwd = (user ..":" .. passwd)
	archivo = (user .. ".xml")
	f = assert(io.open(archivo, "w"))

	c = curl.new()
	c:setopt(curl.OPT_URL, hostname .. "/api/statuses/user_timeline/" .. user ..  ".xml")
	c:setopt(curl.OPT_HTTPGET, true)
	c:setopt(curl.OPT_ENCODING, "utf8")
	c:setopt(curl.OPT_USERPWD, userpwd)
	c:setopt(curl.OPT_USERAGENT, useragent)
	c:setopt(curl.OPT_SSL_VERIFYHOST, 0)
	c:setopt(curl.OPT_HTTPHEADER, 'headers')
	c:setopt(curl.OPT_BUFFERSIZE, 16000)-- 16K
	local t = {}
	c:setopt(curl.OPT_WRITEFUNCTION, function (param, buf)
		table.insert(t, buf)
		return #buf
	end)
	assert(c:perform())
	f:write(table.concat(t))
	c:close()
	io.close(f)
end

function show_last_status()
	require("LuaXML") -- https://luarocks.org/modules/djerius/luaxml
	require("conf")

	userTimeline = xml.load(user .. ".xml")
	status = {}

	for a, b in ipairs(userTimeline:find("statuses")) do
		for c, d in ipairs(userTimeline[a]:find("status")) do
			tag = d[0]
			valor = d[1]
			if tag == "text" then status.text = valor end
			if tag == "truncated" then status.truncated = valor end
			if tag == "created_at" then status.created_at = valor end
			if tag == "in_reply_to_status_id" then status.in_reply_to_status_id = valor end
			if tag == "uri" then status.uri = valor end
			if tag == "source" then status.source = valor end
			if tag == "source_link" then status.source_link = valor end
			if tag == "id" then status.id = valor end
			if tag == "in_reply_to_user_id" then status.in_reply_to_user_id = valor end
			if tag == "in_reply_to_screen_name" then status.in_reply_to_screen_name = valor end
			if tag == "geo" then status.geo = valor end
			if tag == "attachments" then status.attachments = valor end
			if tag == "user" then status.user = valor end
			if tag == "statusnet:html" then status.statusnet_html = valor end
			if tag == "statusnet:conversation_id" then status.statusnet_conversation_id = valor end
			if tag == "statusnet:in_groups" then status.statusnet_in_groups = valor end
			if tag == "external_url" then status.external_url = valor end
			if tag == "in_reply_to_profileurl" then status.in_reply_to_profileurl = valor end
			if tag == "in_reply_to_ostatus_uri" then status.in_reply_to_ostatus_uri = valor end
			if tag == "attentions" then status.attentions = valor end
			if tag == "fave_num" then status.fave_num = valor end
			if tag == "repeat_num" then status.repeat_num = valor end
			if tag == "is_post_verb" then status.is_post_verb = valor end
			if tag == "is_local" then status.is_local = valor end
			if tag == "favorited" then status.favorited = valor end
			if tag == "repeated" then status.repeated = valor end
		end
		print(status.text)
	end
end

Ambas funciones leen el archivo conf.lua que es este:

user = "tuusuario"
passwd = "tupassword"
hostname = "https://linuxinthenight.com" -- el host de tu nodo gnusocial

La función get_user_timeline() obtiene un archivo llamado como el usuario que hemos configurado en el archivo conf.lua. Por ejemplo si es benito pues bajará un archivo llamado benito.xml que contiene los últimos estados.

La función show_last_status() parsea todo el xml para mostrar lo que queramos mostrar. En el caso de este ejemplo solamente muestra el texto de los ultimos estados pero podría mostrar mucho más (por ejemplo el numero de favs y replys, la fecha de publicación, desde que cliente se ha realizado, …).

Esta función podría atacar a una base de datos e ir añadiendo los estados pero eso ya hace más complejo explicarlo por aquí.

No hace falta decir que esto funciona directamente con Lua5.1 sin necesidad de love2d. Si usásemos love2D podríamos ya hacer algo mucho más vistoso en el que por ejemplo se puedan ver los avatares de estados, mostrar las imágenes adjuntas de estados, …

No es la finalidad de este post relatar como crear un cliente entero para GNUSocial pero en cierto modo sirve como comienzo (o eso espero).

Saludos cordiales.

Deja un comentario