経緯
妻がスマホを買い替えたので、LINEの移行を行うことになりました。安請け合いをして、適当にボタンをポチポチ……。LINEの移行に失敗し、全トークが消えてしまいました。こんな危険な作業はしっかりと手順書をつくり、実行者と確認者の2人を用意するべきではないでしょうか。
いろいろ解決策を考えてみましたが、どうにもならないようです。妻が深い深い溜息をつき、悲しそうにしていたのでなんとか復活させる方法を考えました。
LINEのトーク履歴をWEBで表示するようにできる……かな?
妻のトークは消えてしまいましたが、その相手にはトークが残っています。どうやらそれをtext形式で保存する機能もあるようです。このtextをうまいことパースして、ラインのように表示することはできないかと考えました。
以下のようなテキストを拾うことができます。(妻とまだ結婚していない時期のラインです)
2020/12/7(月)
6:10 妻 おはよ
7:01 自分 おはよう
7:01 自分 好きやで
7:11 妻 起きたん
好きよ
7:11 自分 好き
7:11 自分 またね
7:11 妻 またね
7:50 妻 二度寝からおはよ
7:50 自分 おはよう
7:50 自分 可愛いね
これをうまいことパースして、DBに登録し、あとはフロント側でうまいことCSSをつくればなんとかなるな……と思いました。
ということで成果物です。
成果物
cloneしてtalk.txtを配置し、mongodbのURIを変更すれば使えます。
どういう処理をしているのか解説していきます。
const main = async () => {
/* ここでファイルを読み込む */
const file = await readFileSync('talk.txt', 'utf-8');
/* conv関数で分割する */
const split = conv(file);
/* mongoDBに保存する */
insertLineMessage(split);
};
main();
急いでつくったので……とりあえず動け! という感じ。
const conv = (str: string): Message[] => {
/* 改行ごとに配列に入れる */
const splitStr = str.split('\n');
/* まだメッセージがつづいているかどうかのフラグ */
let isContinueMessage = false;
/* メッセージがつづいていたら入れる */
let continueMessage = '';
/* 結果をここに保存していく */
let result: Message[] = [];
/* 現在の日付を保存しておく */
let date: string;
splitStr.forEach((message) => {
/* もし日付だった場合の処理 */
if (isLineDate(message)) {
/* つづかないのでfalse */
isContinueMessage = false;
const beforeDate = date;
date = message;
/* 前回のメッセージがつづいているかどうかで判断する */
result =
continueMessage !== ''
? [...result, convertLineMessage(continueMessage, beforeDate), convertLineDate(message)]
: [...result, convertLineDate(message)];
continueMessage = '';
}
/* タブがあるかどうか。タブがあったらだいたいメッセージが新しい */
if (hasTab(message)) {
/* 今後のメッセージはつづき */
isContinueMessage = true;
result =
continueMessage !== ''
? [...result, convertLineMessage(continueMessage, date)]
: [...result];
continueMessage = message;
}
/* タブがなければ前回のメッセージのつづき */
if (!hasTab(message) && isContinueMessage) {
continueMessage = continueMessage + message + '\n';
}
});
return result;
};
こんな感じで地道に正規表現を使いつつ処理していきました。
あとはmongodbにinsertすれば準備完了。
下記のようなJSONに変換できます。
[{
"type": "date",
"date": "2020-12-07",
"name": "date",
"time": "",
"text": "2020/12/7(月)"
},{
"type": "text",
"name": "妻",
"time": "6:10",
"text": "おはよ",
"date": "2020-12-07"
},{
"type": "text",
"name": "私",
"time": "7:01",
"text": "おはよう",
"date": "2020-12-07"
},{
"type": "text",
"name": "自分",
"time": "7:01",
"text": "好きやで",
"date": "2020-12-07"
},{
"type": "text",
"name": "妻",
"time": "7:11",
"text": "起きたん好きよ\n",
"date": "2020-12-07"
},{
"type": "text",
"name": "自分",
"time": "7:11",
"text": "好き",
"date": "2020-12-07"
},{
"type": "text",
"name": "自分",
"time": "7:11",
"text": "またね",
"date": "2020-12-07"
},{
"type": "text",
"name": "妻",
"time": "7:11",
"text": "またね",
"date": "2020-12-07"
},{
"type": "text",
"name": "妻",
"time": "7:50",
"text": "二度寝からおはよ",
"date": "2020-12-07"
},{
"type": "text",
"name": "自分",
"time": "7:50",
"text": "おはよう",
"date": "2020-12-07"
},{
"type": "text",
"name": "自分",
"time": "7:50",
"text": "可愛いね",
"date": "2020-12-07"
}]
フロントエンドでどう表示するか……の部分は次回。