导出Wordpress日志到新浪博客

  服务器即将到期,不想再续租,自己的博客已经转成静态的了,放到GitHub Pages上当然是最好的选择, 服务器上另一个朋友的博客打算入住新浪博客, 于是就涉及到怎么迁移数据的问题了, 好在新浪博客还算比较开放,支持MetaWeblog XML-RPC API,写了一段简单的脚本,搬家成功。

  不过新浪博客的API貌似不支持dateCreated,因此导入后所有日志的发布时间都变成当前时间了,另外脚本也没有对日志分类进行处理,好在日志不多,手动调整也不是那么麻烦。

<?php
/**
 * 导出Wordpress日志到新浪博客
 * Created by JinnLynn 2013.01.11 http://jeeker.net/
 */
require('./wp-blog-header.php');
require('wp-includes/class-IXR.php');

define('SINA_XMLRPC', 'http://upload.move.blog.sina.com.cn/blog_rebuild/blog/xmlrpc.php');

if ($_GET['action'] != 1) {
?>
<br />
<form action="?action=1" method="post">
    新浪账户: <input type="text" name="usr" value="" /><br />
    新浪密码: <input type="password" name="pwd" value="" /><br />
    <input type="submit" value="导出" /><br />
</form><br />
导出前请确认已开通了新浪博客,并设置了正确的账户密码。
<?php
    return;
}

$usr = trim($_POST['usr']);
$pwd = trim($_POST['pwd']);
if (empty($usr) || empty($pwd)) {
    echo '<br /><span style="color:red;">用户名或密码错误。</span><a href="javascript:history.back()">back</a>.';
    return;
}

// 登陆测试
$params = array(0, $usr, $pwd);
$sina_xmlrpc = new IXR_Client(SINA_XMLRPC);
$sina_xmlrpc->query('metaWeblog.getCategories', $params);
$res = $sina_xmlrpc->getResponse();
unset($sina_xmlrpc);
if (isset($res['faultCode'])) {
    echo '<br /><span style="color:red;">用户名或密码错误。</span><a href="javascript:history.back()">back</a>.';
    return;
}

$query = new WP_Query();
$query->query( array( 'post_type'       => array('post', 'page'), // 导出类型
                      'order'           => 'ASC',
                      'posts_per_page'  => 10000 )
              );
while ($query->have_posts()) {
    global $post;

    $query->the_post();

    $layout = $post->post_type;
    $title = get_the_title();
    $date = get_post_time('Y-m-d H:m:s');
    $author = get_the_author();
    $content = $post->post_content;
    $content = apply_filters('the_content', $content);
    $content = str_replace(']]>', ']]>', $content);

    $content .= '<p id="original-post-date" style="color:#ccc"><br />-----<br />原文发表于:'. $date . '</p>';

    $sina_post = array( 'title'       => $title,
                        'dateCreated' => get_post_time('Y-m-d\TH:m:s\Z', true), //!? 没有作用
                        'description' => $content);

    $params = array(0, $usr, $pwd, $sina_post, true);

    $sina_xmlrpc = new IXR_Client(SINA_XMLRPC);
    $sina_xmlrpc->query('metaWeblog.newPost', $params);
    $res = $sina_xmlrpc->getResponse();

    unset($sina_xmlrpc);

    if (isset($res['faultCode'])) {
        $res = '<span style="color:red;">导出失败</span>';
    }

    echo $title . '<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=> ' . $res . '<br /><br />';
}
?>

Source on gist

一个超简单的在Google中直接访问目标网址的脚本

  前段时间因开某会,悲催的Google一如以往的无法正常使用,常常搜索结果页面顺利出现了,点击链接却无法打开或打开很慢,产生这种现象的原因是Google通过跳转后才把目标网址返回给你,于是领导一个不高兴就又被墙了。

  下面的这段很简单的代码就是让你避免使用Google跳转,直接访问目标网址。

(function(){
    function getRealUrl(l) {
        if (l.indexOf('/url?') < 0)
            return null;
        var a = document.createElement('a'); 
        a.href = l;
        seg = a.search.replace(/^\?/,'').split('&');
        for (i = 0; i < seg.length; i++) { 
            if (!seg[i])
                continue;
            s = seg[i].split('='); 
            if (s[0] == 'url')
                return decodeURIComponent( s[1] );
        } 
        return null;
    }

    /**
     * 直接在载入http:://www.google.com/url?.... 中重定向到真实的目标网址
     * 问题:当目标网址无法访问时,地址栏中的地址信息并未改变到目标网址,可能产生误解
     */
    var real = getRealUrl(location.href);
    if (real) {
        window.location.href = real;
        return;
    };

    document.addEventListener('click', function(e){
        for(a = e.target; a; a = a.parentNode) {
            if(a.localName != 'a') 
                continue;
            real = getRealUrl( a.getAttribute('href') );
            if (real) {
                a.setAttribute( 'href', real );
                a.removeAttribute('onmousedown');
            }
            break;
        }
    }, false);
})();

Source on gist

你可以通过三种方法使用:

1. 通过Chrome扩展

  将url.js、manifest.json通过Chrome扩展开发工具打包成crx包。

2. 通过收藏栏链接

  将下面的链接拖到浏览器收藏栏中,需要时点击即可,在Chrome、Firefox中可用,Safari中似乎直接访问的就是目标地址了

Google Search URL Uncover

3. 通过用户脚本(UserScript)

  未测试过,不过理论上应该可行。在脚本前添加如下内容

// ==UserScript==
// @name           Google URL Uncover
// @namespace      http://jeeker.net/article/google-search-url-uncover/
// @description    Google 搜索结果链接去除google跳转,直接访问目标网址。
// @include        http://*.google.*/*
// @include        https://*.google.*/*
// @version        0.1
// @author         JinnLynn
// @license        MIT license
// ==/UserScript==

PS: 代码在Chrome下测试通过,IE没戏。

终端脚本统一入口

  相较Windows用户而言,Mac和*nix用户更喜欢用脚本处理一些日常的操作,脚本语言可以是Shell、Python、Ruby、Perl或甚至是Mac上的Applescript,一段时间下来可能累计了不少,但这时又会遇到想进行某项操作时却无法快速获取相应的脚本文件,失去了使用脚本原本该有的便捷与效率。

  其实我们可以建立一个简单的Shell文件做为这些脚本的入口,只要记住一些简单的命令就可以快速的执行相应的脚本,实现方法如下:

1. 建立统一入口脚本

#!/bin/bash

#检查环境变量
if [ -z $KITS ]; then
    . $(cd $(dirname $0); pwd)/build-env.sh
fi

#Applescrit接口文件
OSASPORT=$KITSSHELL/osasport.applescript

#使用说明
function usage() {
    more "${KITSSHELL}/misc/kits-usage.txt"
}

function sshkey() {
    if [ -f $KITSSHELL/private.sh ]; then 
        . $KITSSHELL/private.sh sshkey 
    else
        echo 'kits: sshkey is not a kits command.'
    fi
}

case $1 in
    'backup' )     #备份文件到NAS
        $KITSSHELL/backup/backup.sh
        ;;
    'genpac' )     #通过GenPAC生成自动代理配置文件
        $KITS/GenPAC/genpac.py
        ;;
    'mamp' )       #MAMP管理
        $KITSSHELL/mamp.sh $2
        ;;
    'itunes' )     #部分itunes操作
        osascript $OSASPORT itunes $2 $3
        ;;
    'sshkey' )     #SSH秘钥处理
        sshkey
        ;;
    'usage' )      #使用说明
        usage
        ;;
    '' )
        usage
        ;;
    * )
        echo "kits: '$1' is not a kits command. See 'kits usage'."
        ;;
esac

  将上述内容保存为kits.sh或其它任意名称,需要注意的是上面脚本里的内容是我个人所使用的,只是作为例子,大部分是无法运行的,你需要根据自己的需要修改。

2. 添加系统环境变量

  上面的脚本虽然已经实现了做为其它脚本入口的功能,但使用时还不够方便,需要将它系统环境变量中,更容易访问,可能有人已经注意到上面代码中出现的build-env.sh文件,它的目的就是建立一些环境变量。

#!/bin/bash

# 建立Kits的运行环境
# 在~/.bash_profile 添加 source PATH/TO/build-env.sh

# 注意 这里不能用相对路径

#Kits所在目录
export KITS="${HOME}/Developer/Misc/MacOSX-Kits"

export KITSSHELL="${KITS}/Shell"
export PATH="${KITSSHELL}:${PATH}"

#建立别名
alias kits="kits.sh"

  最后再在~/.bash_profile的末尾添加. /PATH/TO/builde-env.sh(或source /PATH/TO/builde-env.sh)让它在用户登陆终端时被执行。

  经过这样设置,在任意时候任意目录下只要在终端输入形如kits usagekit mamp start等命令就可以快速执行相应的脚本了。

  BTW: 我日常使用的部分脚本都陆续放到GitHub上了,有兴趣可以看看。

MacOSX Kits

让iTunes的歌曲自动获取歌词

Fetch Lyric for iTunes

  在4321.la看到使用AppleScript自动获取iTunes曲目歌词的脚本,相当不错,自己做了些修改,添加了当歌词已存在时忽略获取,可以通过Growl通知获取的结果等功能。代码如下:

-- FetchLyric
-- DESCRIPTION: 让iTunes内当前被选中的曲目自动下载并保存歌词,若歌词已存在将被忽略,支持Growl通知
-- AUTHOR: JinnLynn http:://jeeker.net
-- LAST UPDATED: 2012-05-04
-- INTRO PAGE: http://jeeker.net/fetch-lyric-for-itunes/
-- REF: Martian http://blog.4321.la/articles/2012/01/27/use-applescript-to-set-itunes-lyrics/
property scriptName : "FetchLyric"
property baseURL : "http://lyrics.sinaapp.com/"
property isGrowlRunning : false
property statusDesc : {"歌词已存在,无需再获取。", "歌词获取成功。", "歌词获取失败。", "未选择歌曲。"}
property STATUS_LYRIC_EXIST : 1
property STATUS_LYRIC_SUCCESS : 2
property STATUS_LYRIC_FAIL : 3
property STATUS_LYRIC_UNSELECTED : 4

tell application "System Events"
    set isGrowlRunning to (count of (every process whose bundle identifier is "com.Growl.GrowlHelperApp")) > 0
end tell

script growl
    on growlNotify(artist, title, status)
        if isGrowlRunning = false then return
        tell application id "com.Growl.GrowlHelperApp"
            if title = "" then set title to "unknown"
            set the_title to title
            if artist is not equal to "" then set the_title to artist & " - " & the_title
            set the_desc to item status of statusDesc
            set the allNotificationsList to {scriptName}
            set the enabledNotificationsList to {scriptName}
            register as application ¬
                scriptName all notifications allNotificationsList ¬
                default notifications enabledNotificationsList ¬
                icon of application "iTunes"
            notify with name ¬
                scriptName title ¬
                the_title description ¬
                the_desc application name scriptName
            -- 尝试使用歌曲封面作为Growl图标出错
        end tell
    end growlNotify
end script

tell application "iTunes"
    if selection is {} then
        tell growl to growlNotify("", "", STATUS_LYRIC_UNSELECTED)
        return
    end if
    set k to count (item of selection)
    set i to 1
    repeat
        set theTrack to (item i of selection)
        set this_artist to (get artist of theTrack)
        set this_title to (get name of theTrack)
        set this_lyric to (get lyrics of theTrack)
        -- set this_artwork to data of artwork 1 of theTrack

        set fetch_status to STATUS_LYRIC_FAIL

        if length of this_lyric < 1 then
            -- 只有当歌曲中未存在歌词时才尝试获取歌词
            set requestData to "title=" & this_title & "&artist=" & this_artist
            set songLyrics to do shell script "curl -d '" & requestData & "' " & baseURL
            if length of songLyrics > 1 then
                -- 歌词成功获取
                set lyrics of theTrack to songLyrics
                set fetch_status to STATUS_LYRIC_SUCCESS
            end if
        else
            set fetch_status to STATUS_LYRIC_EXIST
        end if

        tell growl to growlNotify(this_artist, this_title, fetch_status)

        set i to i + 1
        if i > k then exit repeat
    end repeat
    -- 如果Growl未运行则显示对话框
    if isGrowlRunning = false then
        display dialog return & "歌词获取结束!" buttons {"确定"} default button 1 with icon 1 giving up after 5 with title scriptName
    end if
end tell

  USAGE: 在AppleScript Editor中新建包含上述脚本的文件,保存在 ~/Library/iTunes/Scripts 目录下,这时在iTunes菜单栏中就会出现AppleScript的下拉菜单,选中需要的歌曲执行其中的命令即可。或者也可以使用Automator将上述脚本生成系统服务,具体本文不做详述,自行Google。

  实际上实现功能需要服务端的支持,上述脚本中使用了Martian搭建在SAE上的服务端,如果你想搭建自己的服务端可以在Martian的文章中找到代码,或下载下面的文件,里面也包含了一个在服务端运行的PHP文件。

Project on GitHubDownload

  BTW: 尝试过使用歌曲封面做为Growl的图标没有成功,总提示无法生成数据,不知道什么原因。

JKit: 部分禁用日志编辑自动保存

  在Wordpress中,日志版本管理(Post Revisions)和编辑日志时的自动保存都会在数据库中产生新的数据(编辑已发布的内容时),很显然这些数据的用处只是一时的,但却给今后数据库查询增加了无谓的额外开销。

  对于日志版本管理,我们在wp-config.php中添加一句define('WP_POST_REVISIONS', false); 即可以轻松的完全禁用此功能,但自动保存就没有这么简单,官方没有提供开关功能,现在网上找到的方法似乎都是通过屏蔽javascript脚本,这种方法虽然可行,但在某些浏览器下可能报错,同时换个角度来看,某些时候自动保存还是有些用处的,完全禁用似乎也不太可取。

  下面的代码实现了仅在编辑草稿、发表新日志或页面时启用自动保存,在重新编辑已发表的内容时则不会进行自动保存的操作,避免在数据库中产生无用的数据,方法则是在浏览器提交申请,服务器进行自动保存之前对日志的状态进行判断,如果是草稿或未找到日志ID(即新日志)则进行保存操作,否则直接退出。

Read more...