]> www.wagner.pp.ru Git - oss/ljdump.git/blob - convertdump.py
937403b43bf1b137fa8ecca42e795298613efd2f
[oss/ljdump.git] / convertdump.py
1 #!/usr/bin/python
2
3 # Copyright 2009, Sean M. Graham (www.sean-graham.com)
4 # All rights reserved.
5
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions are
8 # met:
9
10 # - Redistributions of source code must retain the above copyright notice,
11 #   this list of conditions and the following disclaimer.
12
13 # - Redistributions in binary form must reproduce the above copyright notice,
14 #   this list of conditions and the following disclaimer in the documentation
15 #   and/or other materials provided with the distribution.
16
17 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18 # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20 # EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23 # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
27
28 import xml.dom.minidom 
29 import os
30 import codecs
31 import sys
32 import getopt
33 import re
34
35 from time import strptime, strftime
36
37 def getNodeText(doc, nodename):
38     rc = ""
39
40     try:
41         nodelist = doc.getElementsByTagName(nodename)[0].childNodes
42     except:
43         return ""
44
45     for node in nodelist:
46         if node.nodeType == node.TEXT_NODE:
47             rc = rc + node.data
48
49     return rc
50
51 def appendTextNode(doc, parent, nodename, value):
52     nodeValue = value
53
54     # make sure value is properly encoded
55     try:
56         bytes = nodeValue.encode("UTF-8")
57     except:
58         bytes = nodeValue.encode("cp1252")
59         nodeValue = unicode(bytes, "UTF-8")
60
61     element = doc.createElement(nodename)
62
63     if( nodeValue != "" ): 
64         textNode = doc.createTextNode(nodeValue)
65         element.appendChild(textNode)
66
67     parent.appendChild(element)
68
69
70 def addEntryForId(outDoc, element, username, id, includeSecure):
71     entryFile = open("%s/L-%s" % (username,id), "r")
72     inDoc = xml.dom.minidom.parse(entryFile)
73
74     # Create an entry element
75     entry = outDoc.createElement("entry")
76
77     # Create an itemid element
78     appendTextNode(outDoc, entry, "itemid", getNodeText(inDoc,"itemid"))
79
80     # Create an eventtime element
81     appendTextNode(outDoc, entry, "eventtime", getNodeText(inDoc, "eventtime"))
82
83     # Create an subject element
84     appendTextNode(outDoc, entry, "subject", getNodeText(inDoc, "subject"))
85
86     # Create an event node (special case because for some reason there are two
87     # 'event' elements in the pydump output, which is probably LJ's fault)
88     event = inDoc.getElementsByTagName("event")[0]
89     eventText = getNodeText(event, "event")
90
91     appendTextNode(outDoc, entry, "event", replaceLJTags(eventText))
92
93     security = getNodeText(inDoc, "security")
94
95     if(security != ""):
96         # don't append this entry unless the user provided the argument
97         if(includeSecure == False):
98             print("omitting secure entry: L-%s" % id)
99             return 
100         else:
101             if(security == "usemask"):
102                 print("including allowmask entry: L-%s" % id)
103
104                 # Create an allowmask element 
105                 maskText = getNodeText(inDoc, "allowmask")
106
107                 if(maskText != ""):
108                     appendTextNode(outDoc, entry, "allowmask", maskText)
109                 else:
110                     appendTextNode(outDoc, entry, "allowmask", "0")
111             else:
112                 print("including private entry: L-%s" % id)
113
114         appendTextNode(outDoc, entry, "security", security)
115
116     # Create a taglist element
117     appendTextNode(outDoc, entry, "taglist", getNodeText(inDoc, "taglist"))
118
119     # XXXSMG: make sure there is a comment file before trying to do anything
120     # with it
121     addCommentsForId(outDoc, entry, username, id)
122
123     element.appendChild(entry)
124
125 def addCommentsForId(outDoc, entry, username, id):
126     try: 
127         commentFile = open("%s/C-%s" % (username,id), "r")
128     except IOError:  # there are no comments for this entry
129         return
130
131     inDoc = xml.dom.minidom.parse(commentFile)
132
133     comments = inDoc.getElementsByTagName("comment")
134
135     for comment in comments:
136         outComment = outDoc.createElement("comment")
137         entry.appendChild(outComment)
138
139         # add the item id for the comment
140         appendTextNode(outDoc, outComment, "itemid", 
141             getNodeText(comment, "id"))
142
143         # convert the time string
144         timeString = getNodeText(comment, "date")
145         if( timeString != "" ):
146             inDate = strptime(timeString, "%Y-%m-%dT%H:%M:%SZ")
147             outDate = strftime("%Y-%m-%d %H:%M:%S", inDate)
148             appendTextNode(outDoc, outComment, "eventtime", outDate)
149         else:
150             emptyTime = outDoc.createElement("eventtime")
151             outComment.appendChild(emptyTime)
152
153         # Create an subject element
154         appendTextNode(outDoc, outComment, "subject", 
155             getNodeText(comment, "subject"))
156
157         # Create an event element
158         bodyText = getNodeText(comment, "body")
159         appendTextNode(outDoc, outComment, "event", replaceLJTags(bodyText))
160
161         # Create the author element
162         author = outDoc.createElement("author")
163         outComment.appendChild(author)
164
165         try:
166             cUser = getNodeText(comment, "user")
167         except:
168             cUser = "anonymous"
169
170         appendTextNode(outDoc, author, "name", cUser)
171         appendTextNode(outDoc, author, "email", cUser + "@livejournal.com")
172         
173         # Create the parent_itemid
174         parentId = getNodeText(comment, "parentid")
175         if(parentId != ""): 
176             appendTextNode(outDoc, outComment, "parent_itemid", parentId)
177
178 def replaceLJTags(entry):
179     # regex to replace <lj user="jeebus" /> tags
180     fixedUserTags = re.sub("<lj user=\"(.*?)\" ?/?>", "<a href=\"http://\\1.livejournal.com/\" class=\"lj-user\">\\1</a>", entry)
181
182     return fixedUserTags
183
184
185 def usage():
186     print( "Usage: convertdump.py [arguments]" )
187     print( """
188 This will convert a pydump archive into something compatible with the
189 WordPress LiveJournal importer.  This is the same format used by the Windows
190 ljArchive exporter.
191
192 Arguments:
193     -u  --user      username of archive to process [required]
194     -l  --limit     limit the number of entries in each xml file (default 250)
195     -i  --insecure  include private and protected entries in the output
196     -h  --help      show this help page
197
198 Example:
199     ./convertdump.py --user stevemartin --limit 200 --insecure
200 """)
201
202
203 def main(argv): 
204     username = ""
205     entryLimit = 250
206     includeSecure = False;
207
208     if( len(argv) == 0 ):
209         usage()
210         sys.exit(2)
211
212     try:
213         opts, args = getopt.getopt(sys.argv[1:], "hu:l:i", ["help",
214                                                             "user=",
215                                                             "limit=",
216                                                             "insecure"])
217     except getopt.GetoptError, err:
218         # print help information and exit:
219         print str(err) # will print something like "option -a not recognized"
220         usage()
221         sys.exit(2)
222
223     for o, a in opts:
224         if o == "-v":
225             verbose = True
226         elif o in ("-u", "--user"):
227             username = a
228         elif o in ("-l", "--limit"):
229             entryLimit = int(a)
230         elif o in ("-i", "--insecure"):
231             print( "Warning:  Including secure entries in XML output" )
232             includeSecure = True
233         elif o in ("-h", "--help"):
234             usage()
235             sys.exit()
236         else:
237             assert False, "unhandled option"
238
239     userDir = os.listdir(username)
240
241     highNum = -1
242     entryArray = []
243
244     # get the list of entries
245     for file in userDir:
246         if file.startswith("L-"):
247             entryNum = int(file.replace("L-",""))
248
249             entryArray.append(entryNum)
250
251             if( highNum < entryNum ):
252                 highNum = entryNum
253
254     entryArray.sort()
255
256     # Create the minidom document
257     outDoc = xml.dom.minidom.Document()
258
259     # Create the <livejournal> base element
260     ljElement = outDoc.createElement("livejournal")
261     outDoc.appendChild(ljElement)
262
263     currentFileEntry = 0
264
265     # start processing entries
266     for entry in entryArray:
267         addEntryForId(outDoc, ljElement, username, entry, includeSecure)
268
269         currentFileEntry += 1
270
271         if( currentFileEntry == entryLimit or entry == entryArray[-1] ):
272
273             f = open("%s - %s.xml" % (username, entry), "w")
274             tempXML = outDoc.toxml("UTF-8")
275             f.write(tempXML)
276             
277             currentFileEntry = 0
278
279             # Create the minidom document
280             outDoc = xml.dom.minidom.Document()
281
282             # Create the <livejournal> base element
283             ljElement = outDoc.createElement("livejournal")
284             outDoc.appendChild(ljElement)
285
286 if __name__ == "__main__":
287     main(sys.argv[1:])
288