動かざることバグの如し

近づきたいよ 君の理想に

ShangriLa Anime APIで遊ぶ

ShangriLa Anime APIというAPIをこの前知った。秋葉原IT戦略研究所というところが無料で出しているらしいが、結構データが豊富で面白い。ここのサークルは以前の技術書典で本買った記憶がある。

が、ドキュメントが幾つか分散していたのでまとめメモ

共通仕様

ここで記述するAPIの共通仕様

  • すべてGETパラメータ
  • httpで書いているがhttpsでも取得可能

アニメ一覧取得

:yearは2018のような西暦が入る以下はhttp://api.moemoe.tokyo/anime/v1/master/2018 の取得例

[
  {
    "id": 673,
    "title": "探偵オペラ ミルキィホームズ アルセーヌ 華麗なる欲望"
  },
  {
    "id": 674,
    "title": "アイドリッシュセブン"
  },
  {
    "id": 675,
    "title": "宇宙よりも遠い場所"
  },
  {
    "id": 676,
    "title": "ダメプリ ANIME CARAVAN"
  },
  {
    "id": 677,
    "title": "ラーメン大好き小泉さん"
  },
  {
    "id": 678,
    "title": "ゆるキャン△"
  },
(略)

:yearのあとに1〜4の数字をつけるとクールごとに取得できる。こちらはタイトルに加えてURLやTwitterアカウントも取得できる。以下は http://api.moemoe.tokyo/anime/v1/master/2018/1 の例

[
  {
    "title_short2": "",
    "twitter_account": "milkyholmes",
    "public_url": "https://sp.bushiroad.com/special_tv/",
    "title_short1": "ミルキィホームズ",
    "sex": 0,
    "twitter_hash_tag": "milkyholmes",
    "id": 673,
    "sequel": 5,
    "created_at": "2018-01-07 20:29:38.0",
    "city_name": "",
    "cours_id": 17,
    "title": "探偵オペラ ミルキィホームズ アルセーヌ 華麗なる欲望",
    "city_code": 0,
    "title_short3": "",
    "updated_at": "2018-01-07 20:29:38.0"
  },
  {
    "title_short2": "",
    "twitter_account": "iD7Mng_Ogami",
    "public_url": "http://idolish7.com/aninana/",
    "title_short1": "アイドリッシュセブン",
    "sex": 1,
    "twitter_hash_tag": "アイナナ",
    "id": 674,
    "sequel": 0,
    "created_at": "2018-01-07 20:29:38.0",
    "city_name": "",
    "cours_id": 17,
    "title": "アイドリッシュセブン",
    "city_code": 0,
    "title_short3": "",
    "updated_at": "2018-01-07 20:29:38.0"
  },
  {
    "title_short2": "",
    "twitter_account": "yorimoi",
    "public_url": "http://yorimoi.com/",
    "title_short1": "宇宙よりも遠い場所",
    "sex": 0,
    "twitter_hash_tag": "よりもい",
    "id": 675,
    "sequel": 0,
    "created_at": "2018-01-07 20:29:38.0",
    "city_name": "",
    "cours_id": 17,
    "title": "宇宙よりも遠い場所",
    "city_code": 0,
    "title_short3": "",
    "updated_at": "2018-01-07 20:29:38.0"
  },
  {
    "title_short2": "",
    "twitter_account": "damepri_anime",
    "public_url": "https://damepri-anime.jp/",
    "title_short1": "ダメプリ",
    "sex": 1,
    "twitter_hash_tag": "ダメプリ",
    "id": 676,
    "sequel": 0,
    "created_at": "2018-01-07 20:29:38.0",
    "city_name": "",
    "cours_id": 17,
    "title": "ダメプリ ANIME CARAVAN",
    "city_code": 0,
    "title_short3": "",
    "updated_at": "2018-01-07 20:29:38.0"
  },
  {
    "title_short2": "小泉さん",
    "twitter_account": "ramen_koizumi",
    "public_url": "http://ramen-koizumi.com/",
    "title_short1": "ラーメン大好き小泉さん",
    "sex": 0,
    "twitter_hash_tag": "ラーメン大好き小泉さん",
    "id": 677,
    "sequel": 0,
    "created_at": "2018-01-07 20:29:38.0",
    "city_name": "",
    "cours_id": 17,
    "title": "ラーメン大好き小泉さん",
    "city_code": 0,
    "title_short3": "",
    "updated_at": "2018-01-07 20:29:38.0"
  },
  {
    "title_short2": "",
    "twitter_account": "yurucamp_anime",
    "public_url": "http://yurucamp.jp/",
    "title_short1": "ゆるキャン△",
    "sex": 0,
    "twitter_hash_tag": "ゆるキャン",
    "id": 678,
    "sequel": 0,
    "created_at": "2018-01-07 20:29:38.0",
    "city_name": "",
    "cours_id": 17,
    "title": "ゆるキャン△",
    "city_code": 0,
    "title_short3": "",
    "updated_at": "2018-01-07 20:29:38.0"
  },
Property Value Required description Sample
id Number APIで管理するアニメ作品に割り当てられているユニークなID 125
title String アニメ作品名 "冴えない彼女の育てかた"
title_short1 String - アニメ作品名の略称1 "冴えカノ"
title_short2 String - アニメ作品名の略称2
title_short3 String - アニメ作品名の略称3
public_url String アニメ作品の公式URL "http://www.saenai.tv/"
twitter_account String ツイッターアカウント "saenai_heroine"
twitter_hash_tag String ツイッターハッシュタグ "saekano"
cours_id Number coursマスターのID 5
created_at String データの作成日時 "2015-01-08 09:37:01.0"
updated_at String データの更新日時 "2015-01-08 09:37:01.0"
sex Number - 男性向け=0, 女性向け=1 0
sequel Number - 続編モノの場合は1以上の数値が入る 0

Twitterフォロワー数取得

取得したいTwitterのアカウントのスクリーンネーム(@以降のやつ)をaccountsパラメータで渡す。カンマ区切りで渡すと複数アカウントを一括で取得できる。以下は https://api.moemoe.tokyo/anime/v1/twitter/follower/status?accounts=usagi_anime,kinmosa_anime,nganime の取得例

// 20180503221210
// https://api.moemoe.tokyo/anime/v1/twitter/follower/status?accounts=usagi_anime,kinmosa_anime,nganime

{
  "kinmosa_anime": {
    "follower": 97431,
    "updated_at": 1525274645
  },
  "usagi_anime": {
    "follower": 305795,
    "updated_at": 1525275187
  },
  "nganime": {
    "follower": 138999,
    "updated_at": 1525278006
  }
}

Twitterフォロワー数推移取得

:screen_nameにはTwitterのアカウント名が入る。こちらは複数不可

http://api.moemoe.tokyo/anime/v1/twitter/follower/history/daily?account=usagi_anime&days=30 のようにdaysをつけると取得にっすが増える。が最大39日前までっぽい。デフォルト7。

// 20180503222117
// http://api.moemoe.tokyo/anime/v1/twitter/follower/history/daily?account=usagi_anime&days=10

[
  {
    "follower": 305549,
    "updated_at": 1524417182,
    "yyyy-mm-dd": "2018-04-23"
  },
  {
    "follower": 305605,
    "updated_at": 1524503582,
    "yyyy-mm-dd": "2018-04-24"
  },
  {
    "follower": 305680,
    "updated_at": 1524589982,
    "yyyy-mm-dd": "2018-04-25"
  },
  {
    "follower": 305697,
    "updated_at": 1524676382,
    "yyyy-mm-dd": "2018-04-26"
  },
  {
    "follower": 305701,
    "updated_at": 1524762782,
    "yyyy-mm-dd": "2018-04-27"
  },
  {
    "follower": 305729,
    "updated_at": 1524849183,
    "yyyy-mm-dd": "2018-04-28"
  },
  {
    "follower": 305779,
    "updated_at": 1524935583,
    "yyyy-mm-dd": "2018-04-29"
  },
  {
    "follower": 305796,
    "updated_at": 1525021982,
    "yyyy-mm-dd": "2018-04-30"
  },
  {
    "follower": 305843,
    "updated_at": 1525108382,
    "yyyy-mm-dd": "2018-05-01"
  },
  {
    "follower": 305806,
    "updated_at": 1525194782,
    "yyyy-mm-dd": "2018-05-02"
  }
]

kotlinのData Classでcustom getter/setterを実装する

結論からいうと色々カスタマイズしたいならData Classを使わずに普通のクラス作れって話

環境

  • kotlin 1.2

やりたいこと

kotlinには普通のクラスとは異なり値を格納するためだけのクラス、Dataクラスがよいうされている。変数を宣言するだけで自動でゲッターとセッターつけてくれて非常に便利なんだけど、getするときに〜の型に変換してほしいとか、setするタイミングで〜をつけてほしいとかある。

が、しかし

Data Classにgetter,setter()をカスタマイズできない。そこでもう1つ変数を用意する。

data class User(private val _name: String, val age: Int) {
    val name = "!!${_name}"
        get(): String {
            return "${field}!!"
        }
}


var u = User("taro", 30)
// u.name = !!taro!!

悪あがき感が否めないが。。。素直にデフォルトのclassでやるべきか

kotlin-Androidで文字列⇔日付の相互変換

コピペで再利用できるように

環境

本来、JavaレベルではJava SE8に追加されたtime APIが使えるのだが、Android上で使えるのAPIレベル26以上、つまりOreo以降になる。(誰もいないw

ので今回はベーシックなSimpleDateFormatを使う SimpleDateFormatの仕様はこちら

現在時刻を取得して文字列に変換

val df = SimpleDateFormat("yyyy年MM月dd日 HH:mm")
val message = df.format(Date())
Toast.makeText(this@MainActivity, message , Toast.LENGTH_SHORT).show()

文字列の日付をDate型に変換して文字列で表示

よくあるISO 8601形式をパースする

val date_str = "2018-06-16T13:00:00+09:00"
val df = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX")
val dt = df.parse(date_str)
val df2 = SimpleDateFormat("MM/dd")
val message = df2.format(dt)
Toast.makeText(this@MainActivity, message , Toast.LENGTH_SHORT).show()

例外キャッチする場合

val date_str = "2018-06-16T13:00:00+09:00"
val df = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX")
val dt = try { df.parse(date_str) } catch (t: Throwable) { null }
if (dt != null) {
    val df2 = SimpleDateFormat("MM/dd")
    val message = df2.format(dt)
    Toast.makeText(this@MainActivity, message , Toast.LENGTH_SHORT).show()

} else {
    val message = "date is invalid"
    Toast.makeText(this@MainActivity, message , Toast.LENGTH_SHORT).show()
}

Chromeが00000000とか大容量ファイルでディスクを消費している件

まじChrome先生戦犯でしょ。

発端

Macのディスク容量が結構圧迫してきたので調査していたら、Chromeがめちゃくちゃ容量食ってた

$cd ~/Library/Application\ Support/Google/Chrome/
$du -ch|tail
 16K    ./System Profile/data_reduction_proxy_leveldb
 20K    ./System Profile/Extension Rules
 20K    ./System Profile/Extension State
 20K    ./System Profile/Sync Data/LevelDB
 20K    ./System Profile/Sync Data
508K    ./System Profile
  0B    ./Webstore Downloads
  0B    ./WidevineCdm
 16G    .
 16G    total

16GBってなんやねん使いすぎでしょw

で、見てたら /Users/***/Library/Application Support/Google/Chrome/Default/File System/018/t/00の00000000というファイルが14GBも使用していた。

Chrome終了した状態で試しリネームしてChrome再起動しても問題なかったのでとりあえず消した。

なんだったんだ。。。

MySQLでバルクアップデートをする

MySQLでもbulk update ・・・的なことをしたかった話。

普通にアップデートするだけだと

UPDATE users SET yatin = 'taro' WHERE id = 1;
UPDATE users SET yatin = 'hanako' WHERE id = 2;

て書くが、1レコードごとに1クエリ走ってしまい、5万行を一括で更新するときとかだと以上に遅い。

そこでON DUPLICATE KEY UPDATE使えばいいじゃんって話になるのだが、

INSERT INTO users (id, name) 
VALUES(1,'taro'), (2, 'hanako') 
ON DUPLICATE KEY UPDATE name = VALUES(name);

IDが無かった場合はインサートされてしまうし、1つでもNOT NULLなカラムがあると指定しないとコケるので向いていない。

ってときはELT&FIELD構文が一番便利

ELT&FIELD構文

以下の例はID1,2をそれぞれtaro,hanakoにする例。複数カラムをそれぞれ更新することもできる

UPDATE users
   SET name = ELT(FIELD(id, 1, 2), 'taro', 'hanako') WHERE ID IN (1, 2)

参考リンク