Fb2RSS

A Facebook to RSS conversion tool
git clone git://xatko.vsos.ethz.ch/Fb2RSS.git
Log | Files | Refs | Submodules

commit a1d3ab1f71accbe429a3e48d9169243c70473bf0
parent 705400ea6b1e429729c684f215356172a1e1981e
Author: Dominik Schmidt <das1993@hotmail.com>
Date:   Tue, 30 Jun 2015 12:55:22 +0200

First implementation of Facebook2RSS

Diffstat:
Fb2RSS.d | 169+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 169 insertions(+), 0 deletions(-)

diff --git a/Fb2RSS.d b/Fb2RSS.d @@ -0,0 +1,169 @@ +import std.net.curl; +import std.stdio; +import std.conv; +import std.utf; +import std.string; +import std.datetime; +import std.range; +import kxml.xml; + +class FBStream : RandomFiniteAssignable!(Post){ + Post posts[]; + string url; + private string fetch_url; + string title; + XmlNode dataNodes[]; + string document; + string userAgent="Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20110504 Firefox/7.0.1"; + XmlNode root; + @property RandomFiniteAssignable!(Post) save(){ + FBStream str=this.clone(); + str.posts=this.posts.save; + return str; + } + @property void front(Post newVal){ + posts~=newVal; + } + @property void back(Post newVal){ + posts=[newVal]~posts; + } + void opIndexAssign(Post val, size_t index){ + posts[index]=val; + } + Post opIndex(size_t i){ + return posts[i]; + } + Post moveAt(size_t i){ + return posts.moveAt(i); + } + private FBStream clone(){ + FBStream str=new FBStream(this.fetch_url); + str.url=this.url; + str.posts=this.posts; + str.title=this.title; + str.dataNodes=this.dataNodes; + str.document=this.document; + str.userAgent=this.userAgent; + str.root=this.root; + return str; + } + @property size_t length(){ + return posts.length; + } + RandomFiniteAssignable!(Post) opSlice(size_t a, size_t b){ + FBStream str=this.clone(); + str.posts=this.posts[a..b]; + return str; + } + @property Post back(){ + return posts.back(); + } + Post moveBack(){ + return posts.moveBack(); + } + void popBack(){ + posts.popBack(); + } + int opApply(int delegate(Post) func){ + int result=0; + foreach(ref Post p; posts){ + result=func(p); + if(result) break; + } + return result; + } + int opApply(int delegate(size_t,Post) func){ + int result=0; + foreach(size_t c,ref Post p; posts){ + result=func(c,p); + if(result) break; + } + return result; + } + @property bool empty(){ + return posts.empty; + } + void popFront(){ + posts.popFront(); + } + Post moveFront(){ + return posts.moveFront(); + } + @property Post front(){ + return posts.front; + } + this(string fetch_url){ + this.fetch_url=fetch_url; + } + + public void fetch(){ + auto h=HTTP(); + h.setUserAgent(userAgent); + document=cast(string)get(fetch_url,h); + } + public void parse(){ + XmlNode[] arr; + root=readDocument(document); + arr=root.parseXPath(`//meta[@property="og:url"]`); + url=arr[0].getAttribute("content"); + arr=root.parseXPath(`//meta[@property="og:title"]`); + title=arr[0].getAttribute("content"); + + XmlNode[] nodes=root.parseXPath(`//code`); + generatePosts(nodes); + } + private void generatePosts(XmlNode[] nodes){ + foreach(ref XmlNode node; nodes){ + XmlNode subTree=readDocument((cast(XmlComment)(node.getChildren()[0]))._comment); + XmlNode[] matches=subTree.parseXPath(`//div[@data-time]`); + if(matches.length==0){continue;} + dataNodes~=subTree; + foreach(ref XmlNode match; matches){ + appendPost(match); + } + } + } + private void appendPost(XmlNode match){ + XmlNode[] usercontent=match.parseXPath(`//div[@class="_5pbx userContent"]`); + if(usercontent.length==0){ + return; + } + SysTime t=SysTime(unixTimeToStdTime(to!ulong(match.getAttribute("data-time")))); + XmlNode[] href=match.parseXPath(`//a[@class="_5pcq"]`); + posts~=Post(usercontent[0],t,href[0].getAttribute("href")); + } + + public void generateRSS(File into){ + XmlNode rss = new XmlNode("feed"); + rss.setAttribute("xmlns","http://www.w3.org/2005/Atom"); + rss.addChild(new XmlNode("id").addCData(url)); + rss.addChild(new XmlNode("title").addCData(title)); + //rss.addChild(new XmlNode("author").addChild(new XmlNode("name").addCData(title))); + //rss.addChild(new XmlNode("updated").addCData(posts[0].time.toISOExtString())); + foreach(ref Post p; posts){ + XmlNode e=new XmlNode("entry"); + e.addChild(new XmlNode("title").addCData(p.time.toString())); + e.addChild(new XmlNode("link").setAttribute("href","http://facebook.com"~p.href)); + e.addChild(new XmlNode("id").addCData("http://facebook.com"~p.href)); + e.addChild(new XmlNode("published").addCData(p.time.toISOExtString())); + e.addChild(new XmlNode("updated").addCData(p.time.toISOExtString())); + e.addChild(new XmlNode("content").setAttribute("type","text/html").addCData(p.content.toString())); + rss.addChild(e); + } + into.writeln(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>`); + into.writeln(rss); + } +} + +struct Post{ + XmlNode content; + SysTime time; + string href; +} + +void main(string args[]){ + FBStream str=new FBStream(args[1]); + str.fetch(); + str.parse(); + str.generateRSS(stdout); +}