<?php
/* LiveJournal export-file renderer; (c) 2002 Matt Robinson
 * 
 * Change the configuration below depending on how you plan 
 * to use this script. It's a bit boneheaded at the moment, 
 * so feel free to improve it, but email matt at
 * lazycat.org and let me know, please. 
 * 
 * Current issues:
 *  - Bit messy, codewise
 *  - Export-files must be saved in XML format, and named in
 *    the following way: YYYY-MM.xml
 *  - Yes, that means the journals are rendered a month to a 
 *    page.  Don't write too much, I guess!
 *  - Output files are named YYYY-MM.html and are dumped
 *    wherever you run the script from.  
 */

/* Set this to your LJ username */
$user "makali";

/* Set this to the location of the data directory */
$data_dir "data";


/* Comment out the next line (remove the //) if you 
 * want to show friends-only and private posts as
 * well as the public ones. 
 */
define("HIDE_PRIVATE"TRUE);

/* ****************************************
 * You shouldn't need to change anything 
 * beyond this point.  Not that I mind or
 * anything!
 */

/* Journal Entry object */
class lj_entry {
    var 
$itemid;         // Entry ID; for building link to entry.
    
var $eventtime;      // Time & date of event, in English format (for now)
    
var $logtime;        // Er.. dunno?
    
var $subject;        // Entry subject line
    
var $event;          // Actual entry content
    
var $security;       // This is one of: public, friends, private, usemask
    
var $allowmask;      // This applies to "usemask" entries and is a list of friends to allow access to.
    
var $current_mood;   // Mood
    
var $current_music;  // Music.  With the right mood and the right music, anything can happen. Apparently.
    
    
function print_date() {
    return (empty(
$this->eventtime)) ? FALSE date("l jS F Y"strtotime($this->eventtime));
    }
    
    function 
print_event() {
    
/* Convert LJ-Cut to plain text */
    
$out preg_replace("/<lj\-cut.+text=\"(.+)\">/Ui""<span class=\"lj-cut\">$1</span>"$this->event);
    
$out str_replace("</lj-cut>"""$out);

    
/* Replace <lj user=""> with html equiv */
    
$out preg_replace("/<lj user=\"(.+)\">/Ui"
                
"<a href=\"http://www.livejournal.com/users/$1/\">$1</a>",
                
$out);

    
/* Return output */
    
return $out;
    }

    function 
set($field$value) {
    
/* Append the given data to the specified object property */
    
$this->$field .= $value;
    }
    
}


/* XML Parser object, loads and parses given file, and stores
 * it as an array of lj_entry objects. */

class journal {
    var 
$entries;
    var 
$current_entry;
    var 
$current_property;
    var 
$parser;

    
/* Constructor function; when a new object of this class is
     * created, set default values 
     */
    
function journal() {
    
$entries = array(); // Array of lj_entry objects
    
$current_entry 0// Array pointer to current object
    
$current_property NULL;
    }
    
    
    
/* XML Parser functions */
    
    
function startElement($parser$name$attrs) {
    switch (
$name) {
     case 
"LIVEJOURNAL":
        break;
     case 
"ENTRY":
        
$this->entries[$this->current_entry] = new lj_entry;
        break;
     default:
        
$this->current_property $name;
    }
    }
    
    function 
endElement($parser$name) {
    unset(
$this->current_property);
    if (
$name == "ENTRY") {
        
$this->current_entry++;
    }
    
    }
    
    function 
characterData($parser$data) {
    if (
trim($data) && !empty($this->current_property)) {
        
$this->entries$this->current_entry ]->set(strtolower($this->current_property), $data);
    }
    }
    

    function 
doconvert($matches) {
    return 
nl2br($matches);
    }
    
    
/* The main public function of this class */
    
function load_entries($filename) {
    
/* Load file into string, the create and run it through
     * a parser.
     */
    
$fp fopen($filename'rb') or die("Couldn't open file");
    
$file fread($fpfilesize ($filename));
    
fclose($fp);
    
    
$this->parser xml_parser_create();
    
xml_set_object($this->parser, &$this);
    
xml_parser_set_option($this->parserXML_OPTION_SKIP_WHITE1);

    
xml_set_element_handler($this->parser"startElement""endElement");
    
xml_set_character_data_handler($this->parser"characterData");

    if (!
xml_parse($this->parser$file)) {
        die(
sprintf("XML error: %s at line %d",
            
xml_error_string(xml_get_error_code($this->parser)),
            
xml_get_current_line_number($this->parser)));
    }
    
xml_parser_free($this->parser);
    }
}


/* Build the menu array */
$menu = array();
$out_menu "";
if (
$dp opendir($data_dir)) {
    while (
$filename readdir($dp)) {
    if (!
eregi("([0-9]{4}\-[0-9]{2}).xml"$filename$matches)) continue; // Skip non-conforming files.
    
$menu[] = $matches[1];
    
$out_menu .= "<li><a href=\"{$matches[1]}.html\">" date("F - Y"strtotime("{$matches[1]}-01")) . "</a></li>\n";
    }
    
sort($menu);
}


/* Loop through export files and rewrite output files */
foreach($menu as $month) {
    
$curr_month = new journal;
    if ( 
is_file("$data_dir/$month.xml") ) {
    
$curr_month->load_entries("$data_dir/$month.xml");
    
ob_start();
?><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<title>Journal Backup browser : <?=$month?>
</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<style type="text/css"><!--
a { color:  silver; }
body {
    background-color: #003391;
    background-repeat: no-repeat;
    background-attachment: fixed;
    color: white;
    font-family: Arial, Helvetica, sans-serif;
    font-size: 10pt;
}
.entry {
    position:relative;
    left: 35%;
    width: 60%;
    height: auto;
    border-top: 1px solid #0099FF;
    border-left: 1px solid #0099FF;
    border-right: 1px solid black;
    border-bottom: 1px solid black;
    margin: 1em;
    padding: 3px;
    background-color: #1852A7;
    background-repeat: repeat-x;
}
.entryheader {
    color: #ffffff;
    padding: 3px;
    background-color:  #003391;
    border-top: 1px solid black;
    border-right: 1px solid #0099FF;
    border-bottom: 1px solid #0099FF;
    border-left: 1px solid black;
    background-repeat: repeat-x;
}
.menu {
        position: fixed;
    left: 10px;
    width: 20%;
    height: auto;
    border-top: 1px solid #0099FF;
    border-left: 1px solid #0099FF;
    border-right: 1px solid black;
    border-bottom: 1px solid black;
    margin: 1em;
    padding: 3px;
    background-color:  #1D5FC5;
    top: 50px;
}
.titletext {
    position: fixed;
    font-style: italic; 
    font-size: xx-large; 
    font-family: 'Times New Roman', roman, serif;
}
-->
</style>
</head>
<body>

<div class="titletext">Journal</div>

<div class="menu">
 <p><b>Previous months</b>
  <ul>
   <?=$out_menu?>
 </ul>
 </p>
</div>

<p>&nbsp;<br>&nbsp;</p>
    
<?  // Build a <div> for each entry, and let the stylesheet take care of 
    // drawing it on the screen.  How handy!
foreach($curr_month->entries as $object) {
    
// Skip private/friends-only entries?
    
if (defined("HIDE_PRIVATE") && ( $object->security <> "public" ) )  continue;
?>    
 <div class="entry" id="<?=$object->itemid?>">
  <div class="entryheader">
   <p><b>Date: </b> <?=$object->print_date()?><br>
    <b>Subject: </b> <?=$object->subject?><br>
    <b>Link to this article:</b> <a href="?month=<?=$month?>#<?=$object->itemid?>"><?=$object->itemid?></a>
   </p>
  </div>
  <p>[<a href="http://www.livejournal.com/talkread.bml?journal=<?=$user?>&usescheme=lynx&itemid=<?=$object->itemid?>">View on LiveJournal (with comments)</a>]
   <br><?=$object->event?>
  </p>
 </div>
<?
}

?>
</body>
</html>
<?
    $output 
ob_get_contents();
    
ob_end_clean();
    if (!
$out_file fopen("$month.html"'w')) {
        die(
"Couldn't open output file");
    } else {
        
fwrite($out_file$output);
        
fclose($out_file);
    }
    }
}
?>Done.