Sleepy / sleepy / facebookish.py

from facebook import GraphAPI, GraphAPIError
import re

from sleepy.shorties import date_parse, dt_str, s, PubUpMixin, lazy_property
from sleepy.lonsies import Entries, cacher, config
from sleepy.tipes import TipeMixin
from sleepy.youtubish import video

import logging

log = logging.getLogger( __name__ )
if not logging.root.handlers:
    logging.basicConfig()
log.setLevel( logging.DEBUG )

def _token():
    return config[ "facebook_token" ]

_api = None
def _service():
    global _api
    if not _api:
        _api = GraphAPI( _token())
    return _api

_exceptions = ( IOError,
                GraphAPIError )

event_re = re.compile( r"""
                            facebook.com
                            . *
                            event
                            . *?
                            (?P<id>
                              \d { 10, }
                            )
                            . *
                           """,
                          re.X )

class Event( object ):
    def __init__( self,
                  d ):
        self._start = d[ "start_time" ]
        self._end = d[ "end_time" ]
        self._updated = d[ "updated_time" ]
        self.description = d.get( "description" )
        self.name = d.get( "name" )
        self.id = d.get( "id" )
        self.location = d.get( "location" )
        self.privacy = d.get( "privacy" )
        self.venue = d.get( "venue" )
        self._data = d

    @lazy_property
    def start( self ):
        return date_parse( self._start )

    @lazy_property
    def end( self ):
        return date_parse( self._end )

    @lazy_property
    def updated( self ):
        return date_parse( self._updated )

def event( id ):
    return Event( cacher( cache_name="facebook_events",
                          key=id,
                          createfunc=lambda:
                                      _service().get_object( id )))

class Picture( object ):
    def __init__( self,
                  d,
                  user=None,
                  use_cache=True ):
        self.yd = d[ "id" ]
        self.summary = d.get( "name" )
        self._published = d[ "created_time" ]
        self._updated = d[ "updated_time" ]
        self.link = d[ "link" ]
        self.uri = d[ "source" ]
        self.thumbnail = d[ "picture" ]
        self.images = d[ "images" ]
        self.height = d[ "height" ]
        self.width = d[ "width" ]
        self.portrait = ( self.height
                           > self.width )
        self._data = d

def picture( id ):
    return Picture( cacher( cache_name="facebook_pictures",
                            key=id,
                            cache_expire=None,
                            createfunc=lambda:
                                        _service()
                                         .get_object( id )))

class Album( TipeMixin,
             PubUpMixin ):
    sort_key = "updated"

    def __init__( self,
                  d,
                  user=None,
                  use_cache=True ):
        self.yd = d[ "id" ]
        self.title = d[ "name" ]
        self.summary = d.get( "description" )
        self._published = d[ "created_time" ]
        self._updated = d[ "updated_time" ]
        self.pictures = pictures( self,
                                  user,
                                  use_cache )
        self.uri = d[ "link" ]
        self._data = d

def pictures( album,
              user=None,
              use_cache=True ):
    return Entries( entry_class=Picture,
                    user_config_key="facebook_user",
                    createfunc=lambda user:
                                _service()
                                 .get_connections( album.yd,
                                                   "photos" )
                                 [ "data" ],
                    handle_exceptions=_exceptions,
                    cache_name=s( "facebook_album_{{ album }}",
                                  album=album.yd ))( user=user,
                                                     use_cache=use_cache )

albums = Entries( entry_class=Album,
                  user_config_key="facebook_user",
                  createfunc=lambda user:
                              _service()
                               .get_connections( user,
                                                 "albums" )
                               [ "data" ],
                  handle_exceptions=_exceptions,
                  cache_name="facebook_albums" )

class Post( TipeMixin,
            PubUpMixin ):
    @lazy_property
    def markup_template_uri( self ):
        return ( "/sleepy/facebookish/"
                  + self.classification
                  + ".mako" )

    def __init__( self,
                  d,
                  user=None,
                  use_cache=True ):
        self._published = d[ "created_time" ]
        self._updated = d[ "updated_time" ]
        self.message = d.get( "message" )
        self.link = d.get( "link" )
        self.frum = d.get( "from" )
        self.tipe = d.get( "type" )
        self.id = d.get( "id" )
        self.object_id = d.get( "object_id" )
        self.name = d.get( "name" )
        self.icon = d.get( "icon" )
        self.story = d.get( "story" )
        self.event = self._event()
        self.properties = self._properties( d.get( "properties" ))
        self.picture = d.get( "picture" )
        self.description = d.get( "description" )
        self.source = d.get( "source" )
        self.caption = d.get( "caption" )
        self.classification = self._classification()
        self.video = self._video()
        self._data = d

    def _classification( self ):
        try:
            if self.link.find( "youtube.com" ) > -1:
                return "youtube"
        except AttributeError:
            pass

        if self.story:
            return "story"
        if self.tipe == "link":
            if self.event:
                return "event"
            return "link"
        if self.tipe == "video":
            return "video"
        return self.tipe

    @lazy_property
    def _picture( self ):
        if self.tipe == "photo":
            return picture( self.object_id )

    def _video( self ):
        if self.classification != "youtube":
            return None
        return video( uri=self.source
                           or self.link,
                      fetch_metadata=True )

    def _event( self ):
        if not self.link:
            return None
        match = event_re.search( self.link )
        if not match:
            return None
        else:
            return event( match.group( "id" ))

    def _properties( self,
                     props ):
        if not props:
            return []

        def _property( prop ):
            try:
                # was parsing video lengths as dates
                if len( prop[ "text" ] ) < 10:
                    return prop

                dt = date_parse( prop[ "text" ] )
                prop[ "text" ] = dt_str( self.event
                                             .start,
                                         smusher=None,
                                         weekday=True,
                                         time_space=False )
                return prop
            except ( ValueError,
                     KeyError ):
                return prop

        properties = []
        for prop in props:
            _p = _property( prop )
            properties.append( _p )
        return properties

posts = Entries( entry_class=Post,
                 user_config_key="facebook_user",
                 cache_name="facebook_posts",
                 handle_exceptions=_exceptions,
                 createfunc=lambda user:
                             _service().get_connections( user,
                                                         "posts" )
                                       [ "data" ] )
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.