エキサイトブログとBloggerの記事を同期するプログラム - ExciteBlogToBloggerReplicator

概要

エキサイトブログBloggerの記事を同期するためのJavaのプログラムを書きました。
エキサイトブログに記事を追加・更新・削除した後、このコードを実行すると、エキサイトブログでの編集内容がBloggerに反映されます。

起動方法

本プログラムを実行するには、ExciteBlogToBloggerReplicatorクラスをjavaコマンドで起動します。その際、引数にアカウントファイルのパス渡します。
以下、javaコマンドの実行例です。

java ExciteBlogToBloggerReplicator account.txt
※アカウントファイルのパスがC:\account.txtの場合

アカウントファイル

アカウントファイルには、エキサイトブログBloggerへのログインに必要なアカウント情報を記載します。
以下、アカウントファイルの形式です。

ExciteBlogUser=エキサイトブログのユーザ
ExciteBlogPassword=エキサイトブログのパスワード
BloggerMail=Bloggerのメールアドレス
BloggerPassword=Bloggerのパスワード

ExciteBlogToBloggerReplicatorクラスのソースコード

以下、ExciteBlogToBloggerReplicatorクラスのソースコードです。

import java.io.*;
import java.util.*;

/**
 * エキサイトブログからBloggerへの最新記事の複製
 * @author nattou_curry
 */
public class ExciteBlogToBloggerReplicator {
	
	// アカウントファイルのエンコード
	private static final String ENCODING = "US-ASCII";
	
	public static void main( String[] args ) {
		
		/////////////////////////////////////////////////////////////////////////////
		// アカウントファイルからアカウント情報を取得する。
		/////////////////////////////////////////////////////////////////////////////

		// 引数からアカウントファイルを取得する。
		if ( args.length < 1 ) {
			System.err.println( "引数にアカウントファイルを指定してください。" );
			return;
		}
		
		String fileName = args[0];
		File file = new File( fileName );
		if ( ! file.exists() ) {
			System.err.println( "アカウントファイルが存在しません。ファイル名=[" + fileName + "]" );
			return;
		}
		
		// アカウントファイルの内容をマップに格納する。
		Map<String, String> accountInfo = new HashMap<String, String>();
		
		BufferedReader reader = null;
		try {
			reader = new BufferedReader( new InputStreamReader( new FileInputStream( fileName ), ENCODING ) );
			
			String line;
			while ( ( line = reader.readLine() ) != null ) {
				String[] tmp = line.split( "=", 2 );
				
				if ( tmp.length < 2 ) {
					continue;
				}
				
				String key = tmp[0];
				String value = tmp[1];
				
				accountInfo.put( key, value );
			}
			
		} catch ( IOException e ) {
			System.err.println( "アカウントファイルの読み込みに失敗しました。" );
			e.printStackTrace();
		} finally {
			if ( reader != null ) {
				try {
					reader.close();
				} catch ( IOException e ) {}
			}
		}
		
		// マップから必要なアカウント情報を取得する。
		String e_user = accountInfo.get( "ExciteBlogUser" );
		String e_password = accountInfo.get( "ExciteBlogPassword" );
		String b_mail = accountInfo.get( "BloggerMail" );
		String b_password = accountInfo.get( "BloggerPassword" );

		if ( e_user == null ) {
			System.err.println( "エキサイトブログのユーザが指定されていません。キー=[ExiciteBlogUser]" );
			return;
		}

		if ( e_password == null ) {
			System.err.println( "エキサイトブログのパスワードが指定されていません。キー=[ExiciteBlogPassword]" );
			return;
		}

		if ( b_mail == null ) {
			System.err.println( "Bloggerのメールアドレスが指定されていません。キー=[BloggerMail]" );
			return;
		}

		if ( b_password == null ) {
			System.err.println( "Bloggerのパスワードが指定されていません。キー=[BloggerPassword]" );
			return;
		}
		
		/////////////////////////////////////////////////////////////////////////////
		// エキサイトブログの記事を取得する。
		/////////////////////////////////////////////////////////////////////////////

		// エキサイトブログにログインする(SSL)。
		String e_cookie;
		try {
			e_cookie = ExciteBlogAccess.loginWithSSL( e_user, e_password );
		} catch ( Exception e ) {
			System.err.println( "エキサイトブログへのログインでエラーが発生しました。" );
			e.printStackTrace();
			return;
		}
		
		// エキサイトブログのログイン情報を取得する。
		Map<String, String> e_loginInfo;
		try {
			e_loginInfo = ExciteBlogAccess.getLoginInfo( e_cookie );
		} catch ( Exception e ) {
			System.err.println( "エキサイトブログのログイン情報の取得でエラーが発生しました。" );
			e.printStackTrace();
			return;
		}
		
		// エキサイトブログの最新の記事情報の一覧を取得する。
		List< Map<String, String>> e_articleList;
		try {
			e_articleList = ExciteBlogAccess.getArticleList( e_loginInfo );
		} catch ( Exception e ) {
			System.err.println( "エキサイトブログの最新の記事情報の一覧取得でエラーが発生しました。" );
			e.printStackTrace();
			return;
		}
		
		// エキサイトブログの記事情報を投稿日でソートする。
		Collections.sort( e_articleList, new Comparator<Map<String, String>>() {
			public int compare( Map<String, String> e_articleInfo1, Map<String, String> e_articleInfo2 ) {
				String e_pubDate1 = e_articleInfo1.get( "pubDate" );
				String e_pubDate2 = e_articleInfo2.get( "pubDate" );
				
				return e_pubDate1.compareTo( e_pubDate2 );
			}
		} );
		
		// 【デバッグ用】エキサイトブログの記事情報を表示
		for ( int i = 0; i < e_articleList.size(); ++i ) {
			Map<String, String> e_articleInfo = e_articleList.get( i );
			System.out.println( "[Excite] " + e_articleInfo.get( "pubDate" ) + " " + e_articleInfo.get( "title" ) );
		}

		/////////////////////////////////////////////////////////////////////////////
		// Bloggerの記事を取得する。
		/////////////////////////////////////////////////////////////////////////////

		// Bloggerにログインする(SSL)。
		String b_cookie;
		try {
			b_cookie = BloggerAccess.loginWithSSL( b_mail, b_password );
		} catch ( Exception e ) {
			System.err.println( "エキサイトブログへのログインでエラーが発生しました。" );
			e.printStackTrace();
			return;
		}
		
		// Bloggerにログイン情報を取得する。
		Map<String, String> b_loginInfo;
		try {
			b_loginInfo = BloggerAccess.getLoginInfo( b_cookie );
		} catch ( Exception e ) {
			System.err.println( "エキサイトブログのログイン情報の取得でエラーが発生しました。" );
			e.printStackTrace();
			return;
		}
		
		// Bloggerの最新の記事情報の一覧を取得する。
		List< Map<String, String>> b_articleList;
		try {
			b_articleList = BloggerAccess.getArticleList( b_loginInfo );
		} catch ( Exception e ) {
			System.err.println( "エキサイトブログの最新の記事情報の一覧取得でエラーが発生しました。" );
			e.printStackTrace();
			return;
		}
		
		// Bloggerの記事情報を投稿日でソートする。
		Collections.sort( b_articleList, new Comparator<Map<String, String>>() {
			public int compare( Map<String, String> b_articleInfo1, Map<String, String> b_articleInfo2 ) {
				String b_pubDate1 = b_articleInfo1.get( "pubDate" );
				String b_pubDate2 = b_articleInfo2.get( "pubDate" );
				
				return b_pubDate1.compareTo( b_pubDate2 );
			}
		} );

		// 【デバッグ用】Bloggerの記事情報を表示
		for ( int i = 0; i < b_articleList.size(); ++i ) {
			Map<String, String> b_articleInfo = b_articleList.get( i );
			System.out.println( "[Blogger] " + b_articleInfo.get( "pubDate" ) + " " + b_articleInfo.get( "title" ) );
		}

		/////////////////////////////////////////////////////////////////////////////
		// 追加対象の記事(エキサイトブログに存在し、Bloggerに存在しない記事)を探す。
		/////////////////////////////////////////////////////////////////////////////
		
		List<Map<String, String>> add_ArticleList = new ArrayList<Map<String, String>>();

		// 記事の比較のため、Bloggerの記事のハッシュテーブルを作成。
		Map<Object, Map<String, String>> b_hashTable = new HashMap<Object, Map<String, String>>();
		for ( int i = 0; i < b_articleList.size(); ++i ) {
			Map<String, String> b_articleInfo = b_articleList.get( i );
			
			String b_title = b_articleInfo.get( "title" );
			String b_pubDate = b_articleInfo.get( "pubDate" );
			String b_content = b_articleInfo.get( "content" );

			Object key = b_title + b_pubDate + b_content;
			b_hashTable.put( key, b_articleInfo );
		}

		// 記事を比較し、追加対象の記事を決定する。
		for ( int i = 0; i < e_articleList.size(); ++i ) {
			Map<String, String> e_articleInfo = e_articleList.get( i );
			String e_title = e_articleInfo.get( "title" );
			String e_pubDate = e_articleInfo.get( "pubDate" );
			String e_content = e_articleInfo.get( "content" );
			
			// エキサイトブログの記事とタイトル、投稿日、内容の全てが一致する記事が、Bloggerに存在しない場合、追加対象とする。
			String key = e_title + e_pubDate + e_content;
			if ( ! b_hashTable.containsKey( key ) ) {
				add_ArticleList.add( e_articleInfo );
			}
		}

		// 【デバッグ用】追加対象の記事を表示
		for ( int i = 0; i < add_ArticleList.size(); ++i ) {
			Map<String, String> e_articleInfo = add_ArticleList.get( i );
			String e_title = e_articleInfo.get( "title" );
			String e_pubDate = e_articleInfo.get( "pubDate" );

			System.out.println( "[ADD] " + e_title + " " + e_pubDate );
		}

		/////////////////////////////////////////////////////////////////////////////
		// 削除対象の記事(Bloggerに存在し、エキサイトブログに存在しない記事)を探す。
		/////////////////////////////////////////////////////////////////////////////
		
		List<Map<String, String>> delete_ArticleList = new ArrayList<Map<String, String>>();
		
		// エキサイトブログの最古の投稿日を取得する。
		String min_e_pubDate = "9999/99/99 99:99";
		for ( int i = 0; i < e_articleList.size(); ++i ) {
			Map<String, String> e_articleInfo = e_articleList.get( i );
			
			String e_pubDate = e_articleInfo.get( "pubDate" );
			
			if ( min_e_pubDate.compareTo( e_pubDate ) > 0 ) {
				min_e_pubDate = e_pubDate;
			}
		}
		
		// 【デバッグ用】エキサイトブログの最古の投稿日を表示
		System.out.println( "[Exciteの最古の投稿日] " + min_e_pubDate );

		// 記事の比較のため、エキサイトブログの記事のハッシュテーブルを作成。
		Map<Object, Map<String, String>> e_hashTable = new HashMap<Object, Map<String, String>>();
		for ( int i = 0; i < e_articleList.size(); ++i ) {
			Map<String, String> e_articleInfo = e_articleList.get( i );
			
			String e_title = e_articleInfo.get( "title" );
			String e_pubDate = e_articleInfo.get( "pubDate" );
			String e_content = e_articleInfo.get( "content" );
			
			Object key = e_title + e_pubDate + e_content;
			e_hashTable.put( key, e_articleInfo );
		}

		// 記事を比較し、削除対象の記事を決定する。
		for ( int i = 0; i < b_articleList.size(); ++i ) {
			Map<String, String> b_articleInfo = b_articleList.get( i );
			String b_title = b_articleInfo.get( "title" );
			String b_pubDate = b_articleInfo.get( "pubDate" );
			String b_content = b_articleInfo.get( "content" );
			
			// エキサイトブログの最古の投稿日以前のBloggerの記事は無視する。
			if ( b_pubDate.compareTo( min_e_pubDate ) < 0 ) {
				continue;
			}
			
			// Bloggerの記事とタイトル、投稿日、内容の全てが一致する記事が、エキサイトブログに存在しない場合、削除対象とする。
			String key = b_title + b_pubDate + b_content;
			if ( ! e_hashTable.containsKey( key ) ) {
				delete_ArticleList.add( b_articleInfo );
			}
		}

		// 【デバッグ用】削除対象の記事を表示
		for ( int i = 0; i < delete_ArticleList.size(); ++i ) {
			Map<String, String> b_articleInfo = delete_ArticleList.get( i );
			String b_title = b_articleInfo.get( "title" );
			String b_pubDate = b_articleInfo.get( "pubDate" );

			System.out.println( "[DELETE] " + b_title + " " + b_pubDate  );
		}

		/////////////////////////////////////////////////////////////////////////////
		// 記事を追加する。
		/////////////////////////////////////////////////////////////////////////////
		
		String b_blogID = b_loginInfo.get( "blogID" );
		String b_url = b_loginInfo.get( "url" );

		for ( int i = 0; i < add_ArticleList.size(); ++i ) {
			Map<String, String> e_articleInfo = add_ArticleList.get( i );
			
			String e_title = e_articleInfo.get( "title" );
			String e_pubDate = e_articleInfo.get( "pubDate" );
			String e_content = e_articleInfo.get( "content" );

			Map<String, String> postInfo = new HashMap<String, String>();
			postInfo.put( "blogID", b_blogID );
			postInfo.put( "url", b_url );
			postInfo.put( "title", e_title );
			postInfo.put( "postBody", e_content );
			postInfo.put( "pubDate", e_pubDate );

			try {
				BloggerAccess.postNewEntry( b_cookie, postInfo );
			} catch ( Exception e ) {
				System.err.println( "Blogerへの記事の追加でエラーが発生しました。タイトル=[" + e_title + "], 投稿日=[" + e_pubDate + "]" );
				e.printStackTrace();
				return;
			}
		}

		/////////////////////////////////////////////////////////////////////////////
		// 記事を削除する。
		/////////////////////////////////////////////////////////////////////////////

		for ( int i = 0; i < delete_ArticleList.size(); ++i ) {
			Map<String, String> b_articleInfo = delete_ArticleList.get( i );
			
			String b_title = b_articleInfo.get( "title" );
			String b_pubDate = b_articleInfo.get( "pubDate" );
			String b_postID = b_articleInfo.get( "postID" );
			
			try {
				BloggerAccess.deleteEntry( b_cookie, b_blogID, b_postID );
			} catch ( Exception e ) {
				System.err.println( "Blogerからの記事の削除でエラーが発生しました。タイトル=[" + b_title + "], 投稿日=[" + b_pubDate + "]" );
				e.printStackTrace();
				return;
			}
		}
	}
}

依存するクラスのソースコード

ExciteBlogToBloggerReplicatorクラスは、エキサイトブログBloggerへ接続するために以下のクラスを使用します。