codeape2 / python-blogger

Publish reStructuredText (rst) formatted blog posts to blogger.

python-blogger / blogger.py
59fffdbe » codeape2 2009-06-22 New feature: can update posts. 1 import rstdirective
2
b2ffd4f3 » codeape2 2009-06-21 Initial version 3 def login(username, password):
7f81a6ab » codeape2 2009-06-21 ... 4 import gdata.service
b2ffd4f3 » codeape2 2009-06-21 Initial version 5 service = gdata.service.GDataService(username, password)
6 service.service = 'blogger'
7 service.server = 'www.blogger.com'
8 service.ProgrammaticLogin()
9 return service
10
59fffdbe » codeape2 2009-06-22 New feature: can update posts. 11 import atom
b2ffd4f3 » codeape2 2009-06-21 Initial version 12 def create_entry(title, content, draft=False):
7f81a6ab » codeape2 2009-06-21 ... 13 import gdata
59fffdbe » codeape2 2009-06-22 New feature: can update posts. 14 entry = update_entry(gdata.GDataEntry(), title, content)
b2ffd4f3 » codeape2 2009-06-21 Initial version 15 if draft:
16 control = atom.Control()
17 control.draft = atom.Draft(text='yes')
18 entry.control = control
19 return entry
20
59fffdbe » codeape2 2009-06-22 New feature: can update posts. 21 def update_entry(entry, title, content):
22 entry.title = atom.Title(title_type='text', text=title)
23 entry.content = atom.Content(content_type='html', text=content.encode('utf8'))
24 return entry
25
b2ffd4f3 » codeape2 2009-06-21 Initial version 26 def listblogs(service):
6e832cfa » codeape2 2009-06-22 Work in progress: GUI wrapp... 27 for blogid, title in getblogs(service):
28 print "%s: %s" % (blogid, title)
29
30 def getblogs(service):
b2ffd4f3 » codeape2 2009-06-21 Initial version 31 feed = service.Get('/feeds/default/blogs')
32 for blog in feed.entry:
6e832cfa » codeape2 2009-06-22 Work in progress: GUI wrapp... 33 yield (blog.GetSelfLink().href.split('/')[-1],
b2ffd4f3 » codeape2 2009-06-21 Initial version 34 blog.title.text)
35
22f1451a » codeape2 2009-06-21 Minor changes 36 def listposts(service, blogid):
37 feed = service.Get('/feeds/' + blogid + '/posts/default')
38 for post in feed.entry:
39 print post.GetEditLink().href.split('/')[-1], post.title.text, "[DRAFT]" if is_draft(post) else ""
40
41 def is_draft(post):
42 return post.control and post.control.draft and post.control.draft.text == 'yes'
43
59fffdbe » codeape2 2009-06-22 New feature: can update posts. 44 from docutils.examples import html_parts
b2ffd4f3 » codeape2 2009-06-21 Initial version 45 def read_blogpost(filename, rawhtml, rawhtmltitle):
46 if not rawhtml:
47 parts = html_parts(open(filename, 'rb').read().decode('utf8'))
48 title = parts['title']
49 content = parts['body']
50 else:
51 title = opts.title
52 content = open(filename, 'rb').read().decode('utf8')
53 return title, content
54
59fffdbe » codeape2 2009-06-22 New feature: can update posts. 55 def dump_blogpost(filename):
56 parts = html_parts(open(filename, 'rb').read().decode('utf8'))
57 print parts['whole']
58
59 USAGE="""
60 1. python blogger.py --listblogs --username someone@somewhere.com
61 2. python blogger.py --listposts --username someone@somewhere.com --blog blogid
62 3. python blogger.py --username someone@somewhere.com --blog blogid filename.rst
38cc8be4 » codeape2 2009-06-22 Fixed typo in usage string. 63 4. python blogger.py --username someone@somewhere.com --blog blogid --change postid filename.rst
59fffdbe » codeape2 2009-06-22 New feature: can update posts. 64
65 1. List blogs for user
66 2. List posts on blog
67 3. Publish blog post
68 4. Update an existing post
69 """
70
22f1451a » codeape2 2009-06-21 Minor changes 71 def parse_command_line():
7f81a6ab » codeape2 2009-06-21 ... 72 import getpass
b2ffd4f3 » codeape2 2009-06-21 Initial version 73 from optparse import OptionParser
74
59fffdbe » codeape2 2009-06-22 New feature: can update posts. 75 parser = OptionParser(usage=USAGE)
b2ffd4f3 » codeape2 2009-06-21 Initial version 76 parser.add_option("--username")
77 parser.add_option("--password")
59fffdbe » codeape2 2009-06-22 New feature: can update posts. 78 parser.add_option("--blog", metavar="BLOGID")
b2ffd4f3 » codeape2 2009-06-21 Initial version 79 parser.add_option("--rawhtml", action="store_true", default=False)
80 parser.add_option("--title", help="Only used with --rawhtml")
81 parser.add_option("--listblogs", action="store_true", default=False)
22f1451a » codeape2 2009-06-21 Minor changes 82 parser.add_option("--listposts", action="store_true", default=False)
59fffdbe » codeape2 2009-06-22 New feature: can update posts. 83 parser.add_option("--change", metavar="POSTID")
84 parser.add_option("--dump", action="store_true", default=False,
85 help="Write the HTML output to stdout instead of uploading to blogger")
b2ffd4f3 » codeape2 2009-06-21 Initial version 86
87 opts, args = parser.parse_args()
59fffdbe » codeape2 2009-06-22 New feature: can update posts. 88 if not opts.username and not opts.dump:
22f1451a » codeape2 2009-06-21 Minor changes 89 opts.username = raw_input("Username: ")
59fffdbe » codeape2 2009-06-22 New feature: can update posts. 90 if not opts.password and not opts.dump:
b2ffd4f3 » codeape2 2009-06-21 Initial version 91 opts.password = getpass.getpass()
59fffdbe » codeape2 2009-06-22 New feature: can update posts. 92 return parser, opts, args
22f1451a » codeape2 2009-06-21 Minor changes 93
94 if __name__ == '__main__':
59fffdbe » codeape2 2009-06-22 New feature: can update posts. 95 parser, opts, args = parse_command_line()
22f1451a » codeape2 2009-06-21 Minor changes 96
b2ffd4f3 » codeape2 2009-06-21 Initial version 97 if opts.listblogs:
98 listblogs(login(opts.username, opts.password))
22f1451a » codeape2 2009-06-21 Minor changes 99 elif opts.listposts:
7f81a6ab » codeape2 2009-06-21 ... 100 listposts(login(opts.username, opts.password), opts.blog)
b2ffd4f3 » codeape2 2009-06-21 Initial version 101 else:
102 if not args: parser.error("Specify file name")
103
59fffdbe » codeape2 2009-06-22 New feature: can update posts. 104 if opts.dump:
105 dump_blogpost(args[0])
106 else:
107 title, content = read_blogpost(args[0], opts.rawhtml, opts.title)
108 service = login(opts.username, opts.password)
109 if opts.change:
110 entry = service.Get('/feeds/%s/posts/default/%s' % (opts.blog, opts.change))
111 update_entry(entry, title, content)
112 service.Put(entry, entry.GetEditLink().href)
113 else:
114 service.Post(
115 create_entry(title, content),
116 '/feeds/' + opts.blogid + '/posts/default')