emacs-blogger / blogger.py

'''
Python library but maybe it overcomes the BloggerClient API
'''
from gdata import service
import gdata
import atom
from collections import namedtuple
from dateutil.parser import parse

Entry = namedtuple("Entry", "title content id published updated category feed")

class Blog(object):
    '''
    Encapsulate a Blog object, this istance should no be istantiated,
    but obtained from the Blogger object with Blogger.get_blogs
    '''
    def __init__(self, name, id_, service):
        self.name = name
        self.id = id_
        self.service = service

    def update_post(self, post_id, title=None, content=None):
        '''
        Update the post identified by post_id
        '''
        entry = self.get_entry(post_id)
        
        if title!=None:
            entry.feed.title = atom.Title('xhtml',title)
        if content!=None:
            entry.feed.content = atom.Content(content_type='html',text=content)
        
        self.service.Put(entry.feed, entry.feed.GetEditLink().href)
        
    def add_tags(self, post_id, tags, replace=False):
        """Add or remove labels on a post.
        if replace is True, remove all old tags.
        """
        scheme = 'http://www.blogger.com/atom/ns#'
        post = self.get_entry(post_id).feed

        if replace:
            # Remove categories that match the scheme we are updating.
            post.category = [c for c in post.category if c.scheme != scheme]
        
        new_tags = [atom.Category(term=tag, scheme=scheme) for tag in tags]
        post.category.extend(new_tags)

        self.service.Put(post, post.GetEditLink().href)

    def remove_tags(self, post_id, tags):
        '''
        Remove tags from a post
        '''
        scheme = 'http://www.blogger.com/atom/ns#'
        post = self.get_entry(post_id).feed
        
        post.category = [c for c in post.category \
                             if c.scheme != scheme or \
                             (c.scheme == scheme and c.term not in tags)]
        self.service.Put(post, post.GetEditLink().href)
    
    def get_entries(self):
        '''Generate Entry objects for the blog 
        '''
        
        feed = self.service.GetFeed('/feeds/' + self.id + '/posts/default')
        
        for entry in feed.entry:
            yield self._convert_entry_feed(entry)

    def get_entry(self, post_id):
        return next(entry for entry in self.get_entries() if entry.id == post_id)

    def publish_post(self, title, content, tags=None, draft=False):
        '''
        publish post with the given entries, return the post itself
        '''
        entry = gdata.GDataEntry()
        entry.title = atom.Title('xhtml', title)
        entry.content = atom.Content(content_type='html', text=content)
        
        if draft:
              control = atom.Control()
              control.draft = atom.Draft(text='yes')
              entry.control = control
        
        post = self._convert_entry_feed(self.service.Post(entry, '/feeds/%s/posts/default' % self.id))
        
        if tags:
            self.add_tags(post.id, tags)
        
        return post

    def delete_post(self, post_id):
        '''
        Delete post identified by post_id
        '''
        entry = self.get_entry(post_id)
        self.service.Delete(entry.feed.GetEditLink().href)
  

        
    def _convert_entry_feed(self, entry):
        '''Convert the entry feed returned by the method of the
        service in an Entry Object (a namedtuple, actually)
        '''
        
        title = entry.title.text
        content = entry.content.text
        post_id = entry.GetSelfLink().href.split('/')[-1]
        published = parse(entry.published.text)
        updated = parse(entry.updated.text)
        tags = [tag.term for tag in entry.category]

        return Entry(title, content, post_id, published, updated, tags, entry)        
        

class Blogger(object):
    '''
    Blogger client that returns python objects (usually tuples and
    namedtuples) instead of xml entries
    '''
    
    def __init__(self, username, password):
        s = service.GDataService(username, password)
        s.source = "gl-emacsblogging-0.1"
        s.service = "blogger"
        s.account_type = "GOOGLE"
        s.server = "www.blogger.com"
        s.ProgrammaticLogin()
        self.service = s

    def get_blogs(self):
        '''Return a list of blogs for the current user
        '''
        
        query = service.Query()
        query.feed = "/feeds/default/blogs"
        feed = self.service.Get(query.ToUri())
        
        for entry in feed.entry:
            name = entry.title.text
            blog_id = entry.GetSelfLink().href.split("/")[-1]
            yield Blog(name, blog_id, self.service)


def test_getting():
    blogger = Blogger(username, password)
    blog = next(i for i in blogger.get_blogs())
    entries = blog.get_entries()
    
    for entry in entries:
        print "Entry", entry.title,"Published", entry.published.strftime("%d/%m/%Y"), "Id", entry.id

def test_updating():
    blogger = Blogger(username, password)
    blog = next(i for i in blogger.get_blogs())
    blog.update_post('6296823132147746563', title="Ok", content="Fubbo")
    blog.add_tags('6296823132147746563',["hello", "world"])
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.