トップページ

2006年01月13日

Yahoo Blogの画像付きエントリーをMovableTypeインポート形式に出力

新年お蔵入りPHPスクリプト集そのいち。

Yahoo Blog(とlivedoor Blog)の記事と画像を、このサイトに移転するのに作ったもので、二度と使うことはない筈なので、記念カキコ。
エントリーをMovableTypeのインポート形式に書き出すだけならさして面倒ではないわけですが、自分の場合、Yahoo Blogは(「2GBのディスク容量」という謳い文句にダマされて)写真置き場にしていたので、かなりの数の画像があり、それらをアップロードし直して、サムネイルを作って、本文のリンクを修正して、という気の遠くなる作業はやりたくねえや、ということで、その辺りを自動化するために作ったのがこれ。

注意点とか

Yahoo Blogの画像付きエントリーをMovableTypeインポート形式に出力 ウェブブラウザでスクリプトにアクセスして表示される画面で、「Next Entry」欄にエントリーのURLを入力して送信すると、そのエントリーのHTMLソースを読み込み、本文中にあるJPEG画像のオリジナル(最拡大版)を保存し、そのサムネイルを作成し、リンクなどを書き換えた本文、題名、日付、及び「次の」エントリーのURLを入力フォームと、現状でのプレビューを表示します。プレビューを確認し、必要に応じてフォームの各フィールドに編集を加えた上で、「Export Current Entry」をチェックして送信すると、MovableTypeのインポート形式ファイルを出力し、「次の」エントリーに移動します。以下繰り返し。
JPEG画像のファイル名は、日付+同日のエントリーの連番+同一エントリー内の画像の連番で、サムネイルには「-thumb」が付きます。
文章にすると判りづらいな、これ。つうかぶっちゃけ作ってから随分経つので、かなり忘れてるし。

<?php

// --------------------------------------------------------------------
// 設定
// --------------------------------------------------------------------

// 出力する「MovableTypeの読み込みフォーマット」ファイル名(拡張子は任意)
define('EXPORT_FILE', './exports.txt');

// EXPORT_FILEの文字コード
define('PUBLISH_CHARSET', 'UTF-8');

// Yahooブログの文字コード(通常はEUC-JP)
define('ORIGINAL_CHARSET', 'EUC-JP');

// JPEGファイルを保存するローカルパス
define('LOCAL_IMAGE_STORE', './contents/images/');

// LOCAL_IMAGE_STOREのURL(本文に反映されるのでhttpからのフルパス推奨)
define('REMOTE_IMAGE_STORE', 'http://www.rcdtokyo.com/ucb/contents/images/');

// プレビュー用のCSSファイルのURL
define('CSS_URL', 'http://www.rcdtokyo.com/ucb/styles-site.css');

// 画像のサムネイルの横幅(ピクセル単位)
define('THUMB_IMAGE_WIDTH', 160);

// --------------------------------------------------------------------
// メイン
// --------------------------------------------------------------------

$message = null;
$next = null;
$title = null;
$date = null;
$entry_date = null;
$url = null;
$body = null;
$node_img = array();

// 書き込み指定のチェックボックスがチェックされていれば
if (isset($_POST['p']) and $_POST['p'] == 'on') {

  // EXPORT_FILEに同じ内容があれば書き込みをせず
  // 書き込み済みである旨のメッセージを用意する
  if ($fetched = @file_get_contents(EXPORT_FILE)
    and mb_strpos($fetched, $_POST['t'])
    and mb_strpos($fetched, $_POST['ed'])
    and mb_strpos($fetched, $_POST['b'])) {
    $message = 'The entry seems to have exported already.';
  } else {
    // EXPORT_FILEに書き込む内容
    $export =

<<<EXPORT
AUTHOR:
TITLE: {$_POST['t']}
STATUS: Publish
ALLOW COMMENTS: 1
CONVERT BREAKS: 0
ALLOW PINGS: 1
PRIMARY CATEGORY:
CATEGORY:

DATE: {$_POST['ed']}
-----
BODY:
{$_POST['b']}
-----
EXTENDED BODY:

-----
EXCERPT:

-----
KEYWORDS:

-----


--------

EXPORT;

    // 以上をEXPORT_FILEの末尾に追加する
    $handle = fopen(EXPORT_FILE, 'a');
    fwrite($handle, $export);
    fclose($handle);
  }
}

// URLの指定がなければなにもしない
if (isset($_POST['u']) and $_POST['u'] !== null) {

  // 指定されたURLのエントリーのHTMLソースを取得し文字コードを変換
  $fetched = file_get_contents($_POST['u']);
  mb_convert_variables(PUBLISH_CHARSET, ORIGINAL_CHARSET, $fetched);

  // 次のエントリーのURLを抽出
  if (preg_match('/^.*<a\shref="(.+?)">次の記事へ<\/a>.*$/si', $fetched, $matches)) {
    $next = 'http://blogs.yahoo.co.jp'.preg_replace('/(.+\.html)\??.*$/si', '$1', $matches[1]);
  }

  // DC:TITLEから現在のエントリーのタイトルを抽出
  if (preg_match('/^.*\sdc:title="(.+?)"\s.*$/si', $fetched, $matches)) {
    $title = $matches[1];
  }
  // DC:DATEから現在のエントリーの日付を抽出(画像ファイル名の生成用YY/MM/DD形式)
  if (preg_match('/^.*\sdc:date="(\d{2}(\d{2})-(\d{2})-(\d{2})T\d{2}:\d{2}:\d{2}\+\d{2}:\d{2})"\s.*$/si', $fetched, $matches)) {
    $date = $matches[2].$matches[3].$matches[4];
    $entry_date =  date('m/d/Y h:i:s A', strtotime($matches[1]));
  }
  // 直前に処理したエントリーと同日のエントリーなら日付連番を加算
  if ($_POST['d'] !== null and $_POST['s'] !== null and $_POST['d'] == $date) {
    $serialnum = (int) $_POST['s'] +1;
  } else {
    $serialnum = 1;
  }
  // 日付連番が1桁なら先頭に0を加える
  if (preg_match('/^\d$/', $serialnum)) {
    $serial = '0'.$serialnum;
  } else {
    $serial = $serialnum;
  }

  // 現在のエントリーの本文を抽出
  if (preg_match('/^.*<tr>\s*?<td style="padding:5 0 10 0;line-height:180%;word-break:break-all;line-height:normal">\s*?<p align="justify">(.+?)<\/p>\s*?<\/td>\s*?<\/tr>.*$/si', $fetched, $matches)) {
    $body = $matches[1];
  }
  unset($fetched);

  // 現在のエントリーのIMG要素を抽出
  if (preg_match_all('/<p align=center><a href="javascript:wiki_img_view\(\'(http:\/\/img\.blogs\.yahoo.co\.jp\/.+?)\'\)"><img\s[^>]+?><\/a><\/p>/si', $body, $matches)) {
    for ($i = 0; $i < count($matches[0]); $i++) {

      // ファイル連番(1桁なら先頭に0を加える)
      $count = $i +1;
      if (preg_match('/^\d$/', $count)) {
        $count = '0'.$count;
      }
      $imagefile = $date.$serial.$count;

      // 画像をLOCAL_IMAGE_STOREに保存
      if (!file_exists(LOCAL_IMAGE_STORE.$imagefile.'.jpg')
        and $fetched = file_get_contents($matches[1][$i])) {
        $handle = fopen(LOCAL_IMAGE_STORE.$imagefile.'.jpg', 'w');
        fwrite($handle, $fetched);
        fclose($handle);
        unset($fetched);
      }

      // 保存した画像ファイルからサムネイルを生成
      if (!file_exists(LOCAL_IMAGE_STORE.$imagefile.'-thumb.jpg')
        and $size = getImageSize(LOCAL_IMAGE_STORE.$imagefile.'.jpg')) {
        $thumb_height = round($size[1] * THUMB_IMAGE_WIDTH / $size[0]);
        $original = imageCreateFromJPEG(LOCAL_IMAGE_STORE.$imagefile.'.jpg');
        $new = imageCreateTrueColor(THUMB_IMAGE_WIDTH, $thumb_height);
        imageCopyResampled($new, $original, 0, 0, 0, 0, THUMB_IMAGE_WIDTH, $thumb_height, $size[0], $size[1]);
        imageJPEG($new, LOCAL_IMAGE_STORE.$imagefile.'-thumb.jpg', 75);
      } elseif ($size = getImageSize(LOCAL_IMAGE_STORE.$imagefile.'-thumb.jpg')) {
        $thumb_height = $size[1];
      }

      if (file_exists(LOCAL_IMAGE_STORE.$imagefile.'.jpg')
        and file_exists(LOCAL_IMAGE_STORE.$imagefile.'-thumb.jpg')) {
        // IMG要素の置換
        $body = str_replace($matches[0][$i], null, $body);
        $node_img[$i] = '<a href="'.
          REMOTE_IMAGE_STORE.$imagefile.'.jpg"><img src="'.
          REMOTE_IMAGE_STORE.$imagefile.'-thumb.jpg" width="'.
          THUMB_IMAGE_WIDTH.'" height="'.
          $thumb_height.'" /></a>';
      } else {
        $message = 'File creation seems to have been failed.';
      }
    }
  }

  // エントリー本文の整形
  $body = str_replace('<A ', '<a ', $body);
  $body = str_replace(' HREF=', ' href=', $body);
  $body = preg_replace('/\starget="?_blank"?/si', null, $body);
  $body = preg_replace('/\[(<a\s[^>]+?>).+?<\/a>\s(.+?)\]/si', '$1$2</a>', $body);
  $body = preg_replace('/<div class=\'wiki\'>\s*(.+?)\s*<\/div>\s*/si', '$1', $body);
  $body = preg_replace('/(?:<br \/>){2,}\s*/si', '</p>
<p>', $body);
  $body = '<p>'.$body.'</p>';
  $body = preg_replace('/<br \/><\/p>/si', '</p>', $body);
  if ($node_img) {
    foreach ($node_img as $value) {
      $body .= '
'.$value;
    }
  }
}

// --------------------------------------------------------------------
// 以下HTML出力
// --------------------------------------------------------------------

header('Content-Type:text/html; charset='.PUBLISH_CHARSET);
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<meta http-equiv="content-style-type" content="text/css" />
<link rel="stylesheet" href="<?php echo CSS_URL ?>" type="text/css" />
<style type="text/css">
  input[type="text"], textarea {width:100%}
  textarea {height:10em}
</style>
<body>

<div id="container">
  <div class="content">
    <?php echo $message? '<em>'.$message.'</em>': null ?>

    <!--入力フォーム-->
    <form action="" method="post">
      <input type="hidden" name="d" value="<?php echo $date ?>" />
      <input type="hidden" name="s" value="<?php echo $serialnum ?>" />
      <h3><label for="next">Next Entry</label></h3>
      <p><input id="next" type="text" name="u" value="<?php echo $next ?>" /></p>
      <h3><label for="title">Current Entry Title</label></h3>
      <p><input id="title" type="text" name="t" value="<?php echo $title ?>"></p>
      <h3><label for="body">Current Entry Body</label></h3>
      <p><textarea id="body" name="b"><?php echo htmlspecialchars($body) ?></textarea></p>
      <h3><label for="date">Current Entry Date</label></h3>
      <p><input id="date" type="text" name="ed" value="<?php echo $entry_date ?>"></p>
      <p><input id="export" type="checkbox" name="p" <?php echo ($body and $entry_date)? 'checked': null ?>/>
      <label for="export">Export Current Entry</label>
      <input type="submit" /></p>
    </form>

    <!--プレビュー-->
    <?php echo $title? '<h2><a href="'.$_POST['u'].'" target="_blank">'.$title.'</a></h2>': null ?>
    <?php echo $body ?>
  </div>
</div>

</body>
</html>

お約束

  • このプログラムはGNU GPLでライセンスされます。著作権は放棄されていませんが、なんの保証もありません。利用や改造はGNU GPLの定めに従って、自前のリスクでご自由に。お蔵入りにするくらいなので、ちゃんと検証してたりするわけもなく、あれこれ不具合がある筈ですが、なんらかの不利益を被っても一切関知しません。
  • ヤフー株式会社と、このプログラム及びその作者とはなんの関係もありませんよ。

Category: ウェブ制作
Posted 2006年01月13日 23:06

トラックバック

このエントリーのトラックバックURL:
http://www.rcdtokyo.com/mt/mt-rcdtokyo5428-tb.cgi/697

コメント

コメントをどうぞ



保存しますか?


Aoaka Style Valid Aoaka