# blogger wordpress api libraries
# Author: Yichao Zhang
# Email: yichao.zhang@gmail.com


import httplib
import urllib
import xmlrpclib
import time
from xmlrpclib import Error

# set debug mode        
DEBUG = False
myencoding = 'utf-8' 

# set your wordpress username, password, xmlrpc url     
wp_username = 'admin'   
wp_passwd = 'mypwd'
wp_url = 'http://localhost/wordpress/xmlrpc.php'
                        
# set your blogger email, password, blogid
# blogid is in your blogspot Dashboard url, for example:
# http://www2.blogger.com/posts.g?blogID=18083698, "18083698" is your blogid.
blogger_email = 'yichao.zhang@gmail.com'
blogger_passwd = 'mypwd'
blogger_blogid = '18083698'

# set how many recent posts do you want to import from wordpress to blogger
wp_recent_posts_num = 5  
# set how many times do you want to try if it fails to post to blogger
tryCounter = 3

class SyncWorker:
    def main(self):
        wp = WordpressClient(wp_username, wp_passwd, wp_url)
        blogs = wp.getRecentPosts(wp_recent_posts_num)
        
        clientLogin = GoogleClientLogin(blogger_email, blogger_passwd, 'blogger', 'easter.blogsync')
        auth = clientLogin.getAuth()
        bg = BloggerClient(auth, blogger_blogid)  
        
        failedList = []
        for blog in blogs:
            title = blog['title'].encode(myencoding)
            content = blog['description'].encode(myencoding)
            labels = ','.join([c for c in blog['categories']]).encode(myencoding)
            publishedDate = blog['dateCreated'] 
            postid = blog['postid']
            entry = Entry(title, content, labels, publishedDate)   
            print '>>>> starting postid == %s' % postid
            print '>>>> ........ title  == %s' % title  
            isSuccessfull = bg.insertEntry(entry)  
            counter = tryCounter;
            while counter > 0 and not isSuccessfull:  
                print 'post failed, try again!'
                isSuccessfull = bg.insertEntry(entry) 
                counter -= 1  
            if isSuccessfull:
                print '>>>> post successfully\n'
            else: 
                failedList.append(postid)
                print '>>>> post unsuccessfully\n'
        if failedList:  
            print '>>>> these posts not added:'
            print failedList
            
class GoogleClientLogin:
    def __init__(self, email, passwd, service, source):
        params = urllib.urlencode({'Email': email, 'Passwd': passwd, 'service': service, 'source': source})
        headers = {"Content-type": "application/x-www-form-urlencoded"}
        conn = httplib.HTTPSConnection("www.google.com")
        conn.request("POST", "/accounts/ClientLogin", params, headers)
        response = conn.getresponse()
        data = response.read()
        # failed
        if response.status == 403:
            self.auth = None
        else:
            self.auth = data.splitlines()[2].split('=')[1]
        conn.close()

    def getAuth(self):
        return self.auth

class BloggerClient:
    def __init__(self, auth, blogid):
        self.auth = auth
        self.blogid = blogid
        self.host = 'www.blogger.com'
        self.path = '/feeds/%s/posts/default' % (self.blogid)

    def insertEntry(self, entry):   
        return self.insertEntryXML(entry.getEntryXML(), self.host, self.path)
    
    def insertEntryXML(self, entryXML, host, path):
        headers = {"Authorization": "GoogleLogin auth=%s" % self.auth, "Content-type": "application/atom+xml"}
        conn = httplib.HTTPConnection(self.host)
        conn.request("POST", self.path, entryXML, headers)
        data = conn.getresponse()  
        if DEBUG:  
            print '>>>> response.status == %s' % data.status
            print '>>>> blogger server response:'
            print data.read()
        if data.status == 302:
            location = data.getheader('location')[7:].split('/', 1)
            host = location[0]
            path = '/' + location[1]
            self.insertEntryXML(entryXML, host, path)
        elif data.status == 201:
            return True
        else:
            return False

class Entry:
    def __init__(self, title, content, labels, publishedDate):
        self.title = title
        self.content = content
        self.labels = labels
        self.publishedDate = publishedDate

    def getLabelXML(self, label):
        return '<category scheme="http://www.blogger.com/atom/ns#" term="%s"/>' % label

    def __getLabelsXML(self):
        return ''.join([self.getLabelXML(label) for label in self.labels.split(',')])

    def __getPublishedDate(self):
        date = str(self.publishedDate)
        timezone = time.timezone
        if timezone > 0:
            sign = '-'
        else:
            sign = '+'
            timezone = -timezone
        tzHours = timezone/3600
        tzMinutes = timezone % 3600 / 60
        return '%(year)s-%(month)s-%(other)s%(sign)s%(hours)02d:%(minutes)02d' % \
	        {'year':date[0:4], 'month':date[4:6], 'other':date[6:], 'sign':sign, 'hours':tzHours, 'minutes':tzMinutes}
    
    def getEntryXML(self):
        entryXML = \
            '''
            <entry xmlns='http://www.w3.org/2005/Atom'>
              <title type='text'><![CDATA[%s]]></title>
              <published>%s</published>
              %s
              <content type="text"><![CDATA[%s]]></content>
            </entry>
            ''' % (self.title, self.__getPublishedDate(), self.__getLabelsXML(), self.content)
        return entryXML  

class WordpressClient:
    def __init__(self, username, passwd, url):
        self.username = username
        self.passwd = passwd
        self.url = url
        self.wp = xmlrpclib.ServerProxy(url)
    def getRecentPosts(self, num):  
        try:
            blogs = self.wp.metaWeblog.getRecentPosts('', self.username, self.passwd, num)    
        except Error, v:  
            print v
        return blogs

if __name__ == "__main__":
    SyncWorker().main()