iPhoneやiPadのSafariとかでクソ見づらいULOGの記事をまともに読む方法
注意: 下記方法で有料記事を読むことはできません。
問題点: iPhoneやiPadのSafariだと、ULOGの記事を途中までしか読めない
解決策1: 2本指フリックでスクロールする
解決策2: Instapaperを使う
本記事では、2の「Instapaper」を使ってULOGをiPhone/iPadでも見やすくする方法を解説します。
試してませんがAndroidでもだいたい同じだと思います。
1. SafariでInstapaper Mobilizerを使って見やすくする
ULOGのページを見ているときに、あるブックマークを選択すると、見やすく変換してくれる機能です。(ブックマークレットといいます)
まずブックマークレットを登録します。
iPhoneのSafariで下記のURLを開いてください。
iPhone/iPod touch用ブックマークレット登録支援
下のようなページに行きますね。そしたらブックマークに追加します。
タイトルはとりあえず「Read Now」にしておきましょう。
追加したら、今度はいま追加したブックマークを編集します。
ブックマーク一覧で「編集」をタップして、「Read Now」を選びます。
編集画面で、URLの先頭から # までを削除します。
以上で登録完了です。
では使ってみましょう。読みたいULOG記事に移動してください。
今回は下記の記事を読んでみます。
この状態で、ブックマークから「Read Now」を選ぶと、読みやすく変換されたページが表示されます。
お疲れ様でした!
2. SafariからInstapaperアプリに送ってアプリで読む
上で書いた方法ですが、画像が見切れたりとかすることあります。
アプリを使うと、オフラインでも読めるのはもちろん、文字サイズを調整できたり、画像を個別に表示できたり、さらに色々捗ります。
こっちの始め方の解説はいろんな記事が出ているのでそちらに譲ります。
こことか。
http://netafull.net/lifehack/034678.html
よく使うシェルスクリプト基本構文とサンプル
シェルスクリプト書くときだいたいいつも必要になるけど、たまにしか書かないので忘れがちなやつをメモ。随時更新予定。
なお、全てMac OS Xの/bin/shを想定している。
絶対パスを得る
fullpath=$(cd $(dirname $0) && pwd)
$0はシェルスクリプト自身を表すので、シェルスクリプトファイルの相対パスが得られる。
そのディレクトリでpwdすると、絶対パスが得られる。
$0のかわりに相対パスを与えると、そのファイルの絶対パスが得られる。
なお、括弧の中でcdしているが、その後の処理には影響しない。
配列
配列を作成
arr=(a b c) echo ${arr[0]} # => a
${配列変数名[index]}と、"{}"で囲む必要あり
インデックスはshでは0始まりだが、bashやzshだと違うみたい?なので注意
配列の要素数を得る
$#arr # => 3 ${#arr} # => 3
配列に要素を追加
arr=(1 2 3) arr=(${arr[*]} 4) echo ${arr[*]} # => 1 2 3 4
なお、上記では、変数$arrが存在しない場合、4という1つの要素をもつ配列になる。
分岐(よく使うパターン)
- パス存在チェック
if [ -e $path ]; then (パスが存在する場合実行される) fi
- ファイル存在チェック
if [ -f $file ]; then (パスが存在し、かつファイルである場合実行される) fi
- ディレクトリ存在チェック
if [ -d $dir ]; then (パスが存在し、かつディレクトリである場合実行される) fi
- 複数ファイルの存在チェック
if [ "$(ls $dir | grep '.html$')" != '' ]; then (拡張子がhtmlのファイルが存在する場合実行される) fi
[ -e *.html ] などとすると、複数存在する場合は [ コマンドのエラーになり、存在しない場合はシェルのグラブ展開エラーになるため、上記のようにした。(他にもっといい方法があるかも)
終了ステータス
- 正常時
exit 0
- 異常時
exit 1
LDRのpinをInstapaperにポストするpythonスクリプト
LDRのAPIを使うにはログインが必要だが、python版mechanizeを使うとcookieなどの処理を意識せず簡単にできる。
#! /usr/bin/env python # coding: utf-8 import mechanize import json import urllib def account(service_name): import sys, os import yaml # スクリプトのディレクトリ dir = os.path.abspath(os.path.dirname(__file__)) return yaml.load(open(dir + '/accounts.yaml'))[service_name] class LDRbrowser(object): LD_LOGIN_URL = 'https://member.livedoor.com/login/index' LD_READER_URL = 'http://reader.livedoor.com/' LD_GET_PIN_URL = 'http://reader.livedoor.com/api/pin/all' LD_REMOVE_PIN_URL = 'http://reader.livedoor.com/api/pin/remove' def __init__(self, username, password): ''' インスタンス生成時にログイン ''' self.client = mechanize.Browser() self.client.open(self.LD_LOGIN_URL) self.client.select_form('loginForm') self.client['livedoor_id'] = username self.client['password'] = password self.client.submit() # ApiKeyを取得するため一度LDRにアクセスし、クッキーを解析 info = str(self.client.open(self.LD_READER_URL).info()) for line in info.split('\n'): key = 'reader_sid=' if key in line: self.apikey = line[line.find(key) + len(key):line.find(';')] def get_pin(self): # 第二引数Dataを与えるとPOSTメソッドになる self.client.open(self.LD_GET_PIN_URL, '') # JSON形式がかえってくる pin_json = self.client.response().read() # JSON形式のデータをdictに変換 list = json.loads(pin_json) return list def remove_pin(self, entry_list): ''' entry_listはキー link を含む辞書のリスト entry_list = [{'link': 'http://...'}, {...}, ...] 戻り値はURLとレスポンスコードの辞書 ''' result = {} pd = {'ApiKey': self.apikey} for entry in entry_list: pd['link'] = entry['link'] params = urllib.urlencode(pd) response = self.client.open(self.LD_REMOVE_PIN_URL, params) result[entry['link']] = response.code return result def add_to_instapaper(entry_list, username, password): ''' entry_list はキー link, title を含む辞書のリスト entry_list = [{'link': 'http://...', 'title': '...'}, {...}, ...] 戻り値はURLとレスポンスコードの辞書 ''' INSTAPAPER_API_URL = 'https://www.instapaper.com/api/add' pd = {'username':username, 'password':password} result = {} for entry in entry_list: pd['url'] = entry['link'] pd['title'] = entry['title'].encode('UTF-8') params = urllib.urlencode(pd) response = urllib.urlopen(INSTAPAPER_API_URL, params) result[entry['link']] = response.code return result if __name__ == '__main__': from datetime import datetime # Livedoorにログイン ldac = account('livedoor') br = LDRbrowser(ldac['username'], ldac['password']) # ピン一覧を取得 entries = br.get_pin() # Instapaperにpost # post成功したものをピンから削除 ipac = account('instapaper') ip_result = add_to_instapaper(entries, ipac['username'], ipac['password']) remove_urls = [] log = [] for url, code in ip_result.iteritems(): if 200 <= code and code < 300: remove_urls.append({'link': url}) log.append('%s Post to Instapaper: %s %s' % (datetime.now(), url, code)) pin_result = br.remove_pin(remove_urls) for url, code in pin_result.iteritems(): log.append('%s Remove from Pin: %s %s' % (datetime.now(), url, code)) f = open('/var/log/ldrpin_to_instapaper_log.txt', 'a') if log: f.write('\n'.join(log) + '\n') f.close()
インスタンス生成時にログインし、セッションとapikeyを使い回すようにした。
が、ログイン失敗時などの処理をしておくべきかもしれない。今後の課題か。
スクリプトと同じディレクトリにLivedoorとInstapaperのID, Passwordを書いたYAMLファイルを置いておく
accounts.yaml
livedoor: username: xxxx password: xxxx instapaper: username: xxxx password: xxxx
このスクリプトを10分くらいの間隔で実行するようcronに登録しておくと、iPhone上で
- LDRをチェック -> pin登録 -> 軽量かつオフライン閲覧可能なInstapaperアプリで読む
ことができる。
Livedoorの二重ログインが問題になるかと思ったが、数日使ってみたところ特に問題なく使えている。
LDRのAPIについては以下のエントリが参考になる。
Livedoor ReaderのAPIを探して全部まとめてみた。 - ガジェカツ~在宅SEのガジェット活動ブログ~
python版mechanizeの使い方は以下のエントリの、はてなにログインするスクリプトを参考にした。
はてなのバックアップスクリプトをPythonに移植してみた - とある誰かの覚え書き
pythonのfeedparserを使う
インストール
progdmac% sudo easy_install feedparser
#! /usr/bin/env python # coding: utf-8 import feedparser def get_links(feed_url, log_file): """ 指定したURLのフィードからlinkを抜き出して、そのリストを返す。 ログファイルに既に存在するlinkはリストに含めない。 抜き出したlinkはログファイルに保存する。 """ file = open(log_file, 'r') log_list = file.readlines() file.close() feed_list = feedparser.parse(feed_url) link_list = [] for feed in feed_list.entries: if (feed['link'] + '\n') not in log_list: link_list.append(feed['link']) file = open(log_file, 'a') file.write('%s\n' % '\n'.join(link_list)) file.close() return link_list if __name__ == '__main__': feed_url = 'http://d.hatena.ne.jp/progd/rss' print get_links(feed_url, '/var/log/hoge.log')
適当だけどとりあえず使える。
FLACをMP3に変換→タグのコピー
http://d.hatena.ne.jp/progd/20091227/1261914093 の方法だとMP3のタグが無い状態になってしまう。
以下のPythonスクリプトでFLACファイルからタグを移植する。
#!/usr/bin/env python2.6 #coding: utf-8 import sys from mutagen.flac import FLAC from mutagen.easyid3 import EasyID3, EasyID3KeyError # コマンドライン引数を取得 argvs = sys.argv if len(argvs) != 2: print "usage: python %s flacfile" % argvs[0] quit() flac = FLAC(argvs[1]) mp3 = EasyID3(argvs[1] + ".mp3") for key, value in flac.iteritems(): try: mp3[key] = value except EasyID3KeyError: print "%s is passed" % key mp3.save() print argvs[1] + ".mp3 writed"
注意点
- easy_installでmutagenをインストールしておくこと
- 普通にLAMEでMP3を作るとタグが無い状態のファイルができる。mutagenではタグの無いMP3ファイルは読み込めないので、lameコマンドに--add-id3v2オプションを付加すること
- mutagen.easyid3では処理できるキーに制約がある。処理可能なキーの一覧はEasyID3.valid_keys.keys()で見られる。mutagen.id3ならば自由に編集できるようだが、ID3タグの仕様を理解していないと使えない
使い方
ubuntu:progd% cat flac2mp3.sh #!/bin/sh echo decoding: $1 flac --decode --stdout "$1" | lame --add-id3v2 - "$1".mp3 python tag.py "$1" ubuntu:progd% find . -name "*.flac" -exec ./flac2mp3.sh {} \; ubuntu:progd% find . -name "*.mp3" | perl -lne '$o=$_; s/\.flac//; rename $o,$_;'
指定したサイトから文字列を正規表現で抜き出すpythonスクリプト
#!/usr/bin/env python2.6 #coding: utf-8 import urllib2 import chardet import sys import re # コマンドライン引数を取得 argvs = sys.argv if len(argvs) != 3: print "usage: python %s url regex" % argvs[0] quit() url = argvs[1].decode('utf-8') regex = argvs[2].decode('utf-8') # 引数の正規表現文字列を( )で囲んで、正規表現オブジェクトを生成 reg_patt = re.compile(u"(%s)" % regex) # WebページのHTMLを取得 html = urllib2.urlopen(url).read() # ページのエンコードを取得 encoding = chardet.detect(html)['encoding'].decode() # HTMLをUnicodeに変換 html = unicode(html, encoding, 'ignore') try: match_list = [] while 1: m = reg_patt.search(html) # マッチしないと m = None match_list.append(m.group()) # マッチ部分の文字列をリストに追加 html = html[m.end():] # 検索した部分を取り除く except AttributeError: pass for s in match_list: print s
メソッドにまとめる
#!/usr/bin/env python2.6 #coding: utf-8 import urllib2 import chardet import sys import re def get_page(url): url = unicode(url) # WebページのHTMLを取得 html = urllib2.urlopen(url).read() # ページのエンコードを取得 encoding = chardet.detect(html)['encoding'].decode() # HTMLをUnicodeに変換 html = unicode(html, encoding, 'ignore') return html def search_all(str, reg_patt): try: match_list = [] while 1: m = reg_patt.search(str) # マッチしないと m = None match_list.append(m.group()) # マッチ部分の文字列をリストに追加 str = str[m.end():] # 検索した部分を取り除く except AttributeError: pass return match_list if __name__ == "__main__": # コマンドライン引数を取得 argvs = sys.argv if len(argvs) != 3: print "usage: python %s url regex" % argvs[0] quit() html = get_page(argvs[1]) regex = argvs[2].decode('utf-8') # 引数の正規表現文字列を( )で囲んで、正規表現オブジェクトを生成 reg_patt = re.compile(u"(%s)" % regex) for s in search_all(html, reg_patt): print s
ちなみに、URLなどを取り出すときに「&」が「&」などになってしまうのが困る場合、cgi.unescapeを使えばよい。
sudo easy_install cgi.unescape
でインストールして、スクリプトに以下を追記。
from cgi import unescape
print unescape(s)