Conversion from Wordpres to PyBlosxom

Alec Berryman <alec-93qrncnF8/[email protected]>
Newsgroups gmane.comp.web.pyblosxom.devel
Message-ID <[email protected]>
Attached is a script I wrote to help me convert from Wordpress to
PyBlosxom.  I hope someone else will find it useful.

Fill in the configuration information, run the script, and you'll have a
directory with the entries and another with the comments.  Wordpress
allows entries to be in multiple categories; this doesn't fit in with
PyBlosxom, so I didn't deal with it at all and entries will need to be
manually re-sorted.  There's a quick shell hack in the comments that
will resort comments when you're done with the entries.

You'll want the linebreaks, pyfilenamemtime, and comments plugins.



As an unrelated question, does anyone have a copy of the tags cloud
plugin?  The link from the website is dead.
wp-to-pyblosxom.py (text/x-python, 7 KB)
#!/usr/bin/env python
#
# Convert Wordpress entries and comments to PyBlosxom ones.
# Copyright (C) 2006  Alec Berryman <alec-93qrncnF8/[email protected]>
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
# Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#
# You should have the linebreaks, pyfilenamemtime, and comments plugins.
#
# Usage: fill in the configuration variables below and run the script.  You'll
# see two new subdirectories, by default 'entries' and 'comments'.
#
#
# The conversion process doesn't consider Wordpress category information.
# Wordpress entries may be filed under multiple categories; this doesn't work in
# PyBlosxom.  Instead, all entries are dumped in one folder and comments in
# another; you'll need to sort through them manually afterwards.  After I sorted
# the entries into categories, I ran the following bash script to place the
# comments where they needed to go:
#
# for cat in activities computers life opinion travel; do
#    for entry in $(find ~/log/entries/${cat}/ -type f -exec basename {} .txt \;); do
#        mv -v ~/tmp/tmp/comments/${entry}* ~/log/comments/${cat}/ 2>/dev/null;
#    done;
# done
#
# Adjust as needed.
#
#      -- Alec Berryman <alec-93qrncnF8/[email protected]>, 2006-03-19


### Configuration
mysql_hostname = ""
mysql_username = ""
mysql_password = ""
mysql_database = ""
entries_output_folder = "entries"
comments_output_folder = "comments"

import MySQLdb
import sys
import os
import time
import re
import string

### Helping functions

def except_fatal(e):
    "Handle fatal exceptions"
    print "Error %d: %s" % (e[0], e[1])
    sys.exit(1)

WPTIME_MATCH = re.compile('([0-9]{4})-([0-1][0-9])-([0-3][0-9]) ([0-2][0-9]):([0-5][0-9])')
wp_pyfilenamemtime = {}
def wp2pyfilenamemtime(wptime):
    "Convert Wordpress-style times to pyfilenamemtime-style ones."
    if wp_pyfilenamemtime.has_key(str(wptime)):
        return wp_pyfilenamemtime[str(wptime)]
    else:
        match = WPTIME_MATCH.search(str(wptime))
        if match:
            groups = match.groups()
            wp_pyfilenamemtime[str(wptime)] = "%s-%s-%s-%s-%s" % \
                                              (groups[0], groups[1], \
                                               groups[2], groups[3], groups[4])
            return wp_pyfilenamemtime[str(wptime)]
        else:
            except_fatal([1, "Couldn't parse Wordpress date/time"])

wp_epoch = {}
def wp2epoch(wptime):
    "Convert Wordpress-style times to seconds since the Epoch."
    if wp_epoch.has_key(str(wptime)):
        return wp_epoch[str(wptime)]
    else:
        match = WPTIME_MATCH.search(str(wptime))
        if match:
            groups = match.groups()
            wp_epoch[str(wptime)] = time.mktime((int(groups[0]), \
                                                 int(groups[1]), \
                                                 int(groups[2]), \
                                                 int(groups[3]), \
                                                 int(groups[4]), \
                                                 0, 0, 0, -1))
            return wp_epoch[str(wptime)]
        else:
            except_fatal([1, "Couldn't parse Wordpress date/time"])

def make_dir(directory):
    "Make a directory if it doesn't exist."
    try:
        if os.path.isdir(directory):
            except_fatal([1, "directory exists"])
        else:
            os.mkdir(directory)
    except IOError, e:
        except_fatal(e)

def sanitize(body):
    """Sanitize the comment body.

    Convert newlines to '<br />'; html-ize '<' and '>'.
    """
    body = string.replace(body, '\r\n', '\n')
    body = string.replace(body, '\r', '\n')
    body = string.replace(body, '\n', '<br />')
    body = string.replace(body, '<', '&lt;')
    body = string.replace(body, '>', '&gt;')
    return body

### main

id_to_nametime = {}

try:
    # connect up
    db = MySQLdb.connect(host=mysql_hostname, user=mysql_username,
                         passwd=mysql_password, db=mysql_database)
    cursor = db.cursor()


    # entries
    select_query = "SELECT post_name, post_date, post_title, post_content, ID" + \
                   " FROM wp_posts" + \
                   ' WHERE wp_posts.post_status = "publish"'
    cursor.execute(select_query)
    make_dir(entries_output_folder)
    rows = cursor.fetchall()
    for row in rows:
        # construct the filename, pyfilenamemtime-style
        entryname = os.path.join(entries_output_folder, "%s-%s.txt" % (row[0], wp2pyfilenamemtime(row[1])))
        
        # construct the entry
        contents = "%s\n#parser linebreaks\n\n%s\n" % (row[2], row[3])
        
        # write it to a file
        entry = file(entryname, 'w')
        entry.write(contents)
        entry.close()

        # build a dict of ID:(post_name,time) for comments
        id_to_nametime[str(row[4])] = (row[0], wp2pyfilenamemtime(row[1]))
        

    # comments
    select_query = "SELECT comment_post_ID, comment_author, comment_author_email," + \
                   "       comment_author_url, comment_author_IP, comment_date_gmt," + \
                   "       comment_content" + \
                   " FROM wp_comments" + \
                   ' WHERE wp_comments.comment_approved = "1"'
    cursor.execute(select_query)
    make_dir(comments_output_folder)
    rows = cursor.fetchall()
    for row in rows:
        # construct the filename, pyfilenamemtime-style plus epoch seconds
        filename = "%s-%s-%s.cmt" % (id_to_nametime[str(row[0])][0], \
                                     id_to_nametime[str(row[0])][1], \
                                     wp2epoch(row[5]))
        commentname = os.path.join(comments_output_folder, filename)

        # construct the entry
        contents = '<?xml version="1.0" encoding="utf-8"?>\n'
        contents += '<item>\n'
        contents += '<title>%s</title>\n' % id_to_nametime[str(row[0])][0]
        contents += '<ipaddress>%s</ipaddress>\n' % row[4]
        contents += '<author>%s</author>\n' % row[1]
        contents += '<link>%s</link>\n' % row[3]
        contents += '<email>%s</email>\n' % row[2]
        contents += '<source></source>\n' # XXX what's this field for?
        contents += '<pubDate>%s</pubDate>\n' % wp2epoch(row[5])
        contents += '<description>%s</description>\n' % sanitize(row[6])
        contents += '</item>\n'
        
        # write it to a file
        comment = file(commentname, 'w')
        comment.write(contents)
        comment.close()
    
except IOError, e:
    except_fatal(e)
signature.asc (application/pgp-signature, 189 B)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.2 (FreeBSD)

iD8DBQFEHeZ6Aud/2YgchcQRAhi0AJ0ZF1oBLinvWYom8HAFvxgabBICAgCcD+vj
dSAR8aogw0EAYgY5oSBYM/s=
=HgnX
-----END PGP SIGNATURE-----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.