キャンペーン開始通知スクリプト

先日の#pyfesでjsonファイルを操作したことないなー、と思ったのでこんなのを作ってました。

@search_accountの最新3ツイートを取得し、それぞれ5分以内のものか判定した上でsearch wordが含まれているかを判定します。
最後の部分でメール送信なり、自分にmentionなり、boxcarにプッシュなりを設定し、
数分間隔で定期実行させればキャンペーン開始通知として使えそうです。

ところでPythonの変数って推奨の銘々則ってあるんですかね?PEPとかに。
ObjCみたくキャメルケースで書いてしまってるけど。

Twitter botを定期実行させるPaaS先選定

Twitter上で早い者勝ちのキャンペーン等がされる事が最近多いため、定期的にそのTwitterアカウントのツイートを取得してキャンペーン関連のツイートが行われたら通知を受け取りたいと思います。
流石にこのためだけにPCを立ち上げっぱなしにするのも嫌なので、デプロイ先PaaSをどれにするか調べたメモ。

■heroku

RubyもPythonも使えていい感じのherokuさんですが、
Cronが有料($3)でHourlyと今回の目的にそぐわない感じです。
出来れば数分以内に通知を受け取りたいわけなので、
分間隔で使えるCronが欲しいところです。

と、思っていたらclockwork使えば秒単位で実行できそうでした。
Schedulerは10分間隔で可能みたいです。後でやってみます。

■fluxflex

国産のfluxflexさん。
#!/usr/bin/env python

import datetime

print 'Content-type: text/html\n\n'
print '<html><body>'
nowtime = datetime.datetime.now()
print 'Now time is %s' % nowtime
print '</body></html>'
などという軽量極まりないコードを1回実行させるとCPU時間が
0.265増えたので、3分間隔で実行させると、
0.265 * 480 = 127.2というわけで結構余裕ありそうですが、定期実行がしにくい感じです。

デプロイがgitだったりgithubからimportできたらtwitterアカウントでログインできたり、好印象。



■GoogleAppEngine

Cronが最短1分間隔で使えます。無料のQuotaは色々とややこしいのですが、
結論から言えばBotを動かす程度だとこんな感じで収まります。

Gmailからのメール送信がすごく簡単なのが良い。

■で、どれ使うの

Cloud FoundryとかDotCloudとか名前だけ知ってるやつも試したい。
DotCloudはSSHで入ってcrontabいじるみたいで楽しそう。

とりあえずGAEで作成済みなので次回はそれで。

Bylineのキャッシュが終わったらLocal Notificationを発行する

■BylineTweetFormatter v0.0.3

BylineTweetFormatterを修正して、Sylfeedのように同期 キャッシュが終わったタイミングでLocal Notificationを出すようにしてみました。
Local Notificationなのでフォアグラウンドの場合は出ません。
加えてキャッシュ完了数で判定しているため、1つもキャッシュしない設定や同期の場合通知されません。


https://github.com/r-plus/BylineTweetFormatter

DictGoogle v0.3 スワイプで辞書画面を終了

普段左手持ちで左の親指で全て操作してるのですが、この持ち方だと画面右上がちょっと遠い。
そこそこの頻度で利用するDefineメニューのDoneボタンを押すのがそろそろ面倒になったので、
左右どちらかのスワイプで破棄できるようにDictGoogleに機能追加しました。

モーダルビューの破棄に限定したので、iPadではスワイプしても意味はないです。

PreferenceBundleで同じリストの管理をしやすく

■PreferenceLoaderでのリスト選択について

PreferenceLoaderのplistでリスト選択させたい場合、大抵は下記のようにして
PSListItemsControllerクラスにvalidValuesとvalidTitlesのArrayを書いてあげれば良いので非常に楽です。
detail
PSListItemsController
validValues

    80
    100
    120
    160
    200

validTitles

    80(default)
    100
    120
    160
    200(insensitive)
が、このリストへのリンクが1つ2つならまだ平気ですが、10個とかになると億劫になってきて、
追加や削除が面倒なことうけあいです。

PreferenceBundleにするとこの辺りは非常に楽になります。

■まずはBundleへ誘導するPreferenceLoader用のplistを作成

entry.plistを作成します。detailが自作するクラス名になります。
{
 entry = {
  bundle = "SleipnizerSettings";
  cell = PSLinkCell;
  detail = "RootPreferenceController";
  icon = "SleipnizerforSafari.png";
  isController = 1;
  label = "Sleipnizer for Safari";
 };
}

このentry.plistはMakefileの記述でビルド時に適切にリネーム・移動します。

BUNDLE_NAME = SleipnizerSettings
SleipnizerSettings_FILES = Preference.m
SleipnizerSettings_INSTALL_PATH = /Library/PreferenceBundles
SleipnizerSettings_FRAMEWORKS = UIKit
SleipnizerSettings_PRIVATE_FRAMEWORKS = Preferences

include $(THEOS_MAKE_PATH)/bundle.mk

internal-stage::
 $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences$(ECHO_END)
 $(ECHO_NOTHING)cp entry.plist $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences/SleipnizerforSafari.plist$(ECHO_END)

■今までPreferenceLoader用に記述していたplistを読み込む

今まで記述していたPreferenceLoader用のplistがそのまま使えますので、
Bundle用の格納ディレクトリであるResourcesの中に放り込みます。

放り込んだplistを読むために以下のメソッドを書いておきます。ここでのクラス名がentry.plistのdetailに記述したものと同一になるようにします。loadSpecifiersFromPlistNameの引数はplistの名前を書きます。

#import <Preferences/Preferences.h>

__attribute__((visibility("hidden")))
@interface RootPreferenceController : PSListController
@end

@implementation RootPreferenceController
- (id)specifiers {
  if(_specifiers == nil) {
    _specifiers = [[self loadSpecifiersFromPlistName:@"SleipnizerforSafari" target:self] retain];
  }
  return _specifiers;
}
@end

これでこれまでと同じ状態に出来ました。

■リスト用のメソッドを指定する

PreferenceLoader用のkeyの中に、そのためのものがあります。valuesDataSourceとtitlesDataSourceです。
冒頭のこれまで長々と書いていた部分を置き換えます。

detail
PSListItemsController
valuesDataSource
valuesSource:
titlesDataSource
titlesSource:

■メソッドを記述する

NSArray *を返すように記述してあげます。

- (NSArray *)valuesSource:(id)target {
  return [NSArray arrayWithObjects:@"80", @"100", @"120", @"160", @"200", nil];
}

- (NSArray *)titlesSource:(id)target {
  return [NSArray arrayWithObjects:@"80(default)", @"100", @"120", @"160", @"200(insensitive)", nil];
}

これでリストを編集したければ、こちらのコードを弄れば参照箇所全てに反映されます。