ツイートを動画コメント風に表示するMacアプリ「ついこめ」をリリースしました

# どんなアプリ？
- Twitterの検索結果を、ニコニコ動画の様なコメント形式で表示するアプリです。
- 勉強会等でのプレゼンテーションのとき、スライドにTwitterのコメントを流したり、動画を見るときにコメントを表示する、などに使用してみてください。

<blockquote class="twitter-tweet" data-partner="tweetdeck"><p lang="ja" dir="ltr">ツイートを動画コメント風に表示するMacアプリ「ついこめ」をリリースしました！<br>勉強会やプレゼンテーションのお供にどうぞ〜😽<br><br>App Store: <a href="https://t.co/lTbEynfVV1">https://t.co/lTbEynfVV1</a> <a href="https://t.co/bvnGTKuOyG">pic.twitter.com/bvnGTKuOyG</a></p>&mdash; IKEH@iOS_Apprentice (@ikeh1024) <a href="https://twitter.com/ikeh1024/status/1237585654151708672?ref_src=twsrc%5Etfw">March 11, 2020</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# ダウンロードはこちら

<a href="https://apps.apple.com/jp/app/%E3%81%A4%E3%81%84%E3%81%93%E3%82%81/id1501346000?mt=12"><img width="150" alt="image" src="https://i.imgur.com/xC3dovM.png"><a>

- [ついこめ - App Store](https://apps.apple.com/jp/app/%E3%81%A4%E3%81%84%E3%81%93%E3%82%81/id1501346000?mt=12)
    - 対象OSは`macOS10.14以上`です
    - 簡単な使い方を[サポートページ](https://pommdau.github.io/SupportPages/TweetComment/support_page/support_ja.html)に記載しています。
- 感想・意見・要望等がありましたら、記事へコメントやTwitterのDMまで連絡をもらえると嬉しいです！
    - https://twitter.com/ikeh1024    

# 紹介記事
- [【AAPL Ch.】Twitterの検索結果をニコニコ動画のコメント風にMacのデスクトップに表示する「ついこめ」がリリース。](https://applech2.com/archives/20200311-tweetcomment-for-mac.html)
    - 本アプリを紹介してもらいました！
- [【ifun.de】TweetComment zeigt Themen\-Tweets auf dem Mac\-Schreibtisch](https://www.ifun.de/tweetcomment-zeigt-themen-tweets-auf-dem-mac-schreibtisch-151082/?utm_source=dlvr.it&utm_medium=twitter)
    - ドイツ語のサイトで紹介されていました。（どうやって見つけてくれたんでしょうか。）
    - 英語対応したかいがありますね。
- [Mac Fan 2020年6月号の「Mac App Store 新着ソフト」](https://books.google.co.jp/books?id=uFzeDwAAQBAJ&pg=PA147&lpg=PA147&dq=%E3%81%A4%E3%81%84%E3%81%93%E3%82%81&source=bl&ots=U8CMb13rka&sig=ACfU3U2nxMdRckOnMFSSJdn-G-TjbO4Imw&hl=ja&sa=X&ved=2ahUKEwiVi9iFwsbpAhWBIqYKHT8lDlgQ6AEwBXoECBQQAQ#v=onepage&q=%E3%81%A4%E3%81%84%E3%81%93%E3%82%81&f=false)に載せていただきました。
    - [関連ツイートをニコ動のコメント風に｜MacFan](https://book.mynavi.jp/macfan/detail_summary/id=115574)
- `AppStore>ソーシャル・ネットワーキング`で8位に！（一瞬だけですが）

<img width="400" alt="image" src="https://i.imgur.com/Ra5byUN.jpg">

# 開発期間ときっかけ
- アプリのアイディアとしては、下記の記事を見てからいつか作りたいなと思っていました。
    - [\[OS X\] 透過型のTwitterクライアントを作ってみた ｜ Developers\.IO](https://dev.classmethod.jp/tool/transmission-twitter-client/)
- ただ技術的な実装方法が当時分からなかったので、しばらくアイディアとして寝かせていました。
- また昨年の12月頃から下記を参考にしながら、SwiftでのmacOSアプリ開発の学習を始めました。
    - [簡単なポモドーロタイマーを作ってみました](https://qiita.com/IKEH/items/28d9ce0c084bb802fea4)
    - [Hacking with macOS \- Build 18 Desktop Apps with Swift 5 \| Udemy](https://www.udemy.com/course/hacking-with-macos-and-swift4/)
        - 貴重なmacOS開発の講座です。
- そこで`SplitView`と`CoreAnimation`を学習して、この辺の技術を使えばできそうだな、と見通しが立った段階で作り始めました。
- 開発しない時期を挟んだため、実際の開発期間は1~1.5ヶ月程度だと思います。

# 技術的な話
## コメントの表示位置
- コメントの表示位置（y座標）を完全にランダムにすると、整合性がなく見づらくなります。
    - また往々にしてテキスト同士が重なってしまいます。
- そこで本アプリでは少しだけ工夫をしています。
- まず`画面サイズ÷テキストの高さ（1行分）`を計算し、下記のように仮想的にスペースを分割します。
    - この計算は、文字の大きさやウィンドウの大きさが変わるごとに再度行います。
- 後は仮想スペースの位置にランダムな順番にテキストを表示しています。
- また複数行のツイートの場合、テキストが上に見切れてしまう場合があるので、その際は見切れた高さ分を下に移動させています。

<img width="600" alt="image" src="https://i.imgur.com/nQFpvTL.jpg">

- ただしこれではテキストが重なる問題点は完全に解決されません。複数行のツイートの場合があるからですね。
- 本家のニコニコ動画でどうやっているのかと調べてみた所、平行四辺形として捉えて計算しているそうです。
    - [ニコニコ動画の仕組み - J-Stage](https://www.jstage.jst.go.jp/article/bplus/11/1/11_4/_pdf)
    - 具体的な実装に落とし込むのが難しそうなので、今回は見送っています。
    - ニコニコ動画を見ていると、コメントが少ない場合は上部中心に表示されるようになっていたりして、この辺のロジックは改善の余地がまだまだありそうです。

## コメントのアニメーション
### 概要
- コメントをスライドさせるためには`CoreAnimation`を使用しています。
- 開始前と開始後の状態、また時間を設定するだけでアニメーションを簡単に表現できます。
- またアニメーションの完了時に呼ばれるメソッドが用意されているので、そちらでテキストオブジェクトの開放を行っています。
    - `CAAnimationDelegate`の`animationDidStop`
- 注意点としては、`macOS 10.13`で`CoreAnimation`がうまく表示されません。

### 参考
- [Swift Mac OS Animation using Core Animation\- Part 1](http://www.knowstack.com/swift-mac-os-animation-part-1/)
    - 詳細や実装方法に関して、下記の記事が詳しかったです。
- [CABasicAnimation \- Core Animation \| Apple Developer Documentation](https://developer.apple.com/documentation/quartzcore/cabasicanimation#2776775)
    - `keyPath`に関して参考にしました。

### 実装例

![Mar-13-2020 14-15-55](https://i.imgur.com/BzkauAf.gif)

```swift
func shoeTextField(_ text: String) {
    // テキストフィールドの作成
    let textField = NSTextField(labelWithString: text)
    textField.translatesAutoresizingMaskIntoConstraints = false
    textField.sizeToFit()
    textField.wantsLayer = true  // CoreAnimationを有効にする

    // NSTextFieldの実体は見えない場所（Viewの下側）に配置している
    textField.frame.origin = NSPoint(x: view.frame.width, y: -textField.frame.height)
    view.addSubview(textField)
    
    
    // アニメーションの設定
    let movingHorizontallyAnimation = CABasicAnimation(keyPath: "position")  // positionに関してアニメーションを行う
    let yPosition = view.frame.height / 2 - textField.frame.height / 2       // 画面の中央の位置
    movingHorizontallyAnimation.fromValue      = NSPoint(x: self.view.frame.width , y: yPosition)  // 開始状態を設定
    movingHorizontallyAnimation.toValue        = NSPoint(x: -textField.frame.width, y: yPosition)  // 終了状態を設定
    movingHorizontallyAnimation.duration       = 5.0  // アニメーションの時間
    movingHorizontallyAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
    textField.layer?.add(movingHorizontallyAnimation, forKey: nil)
}
```

## Twitter APIの上限
### 概要
- Twitter APIの検索リクエストの上限は下記の通りです（15分毎の値）
    - ユーザ認証型なので、180回/15分 -> 1回/5秒ですね

![](https://i.imgur.com/Ni3gRHI.jpg)

- 正直に5秒ごとに取得を行い、ツイート時刻の差に応じて表示をしようとすると、画面に空白期間が生じてしまいます。
- そこで取得するツイートを下記のように振り分けて、画面を5秒間保たせるようにしています。
    - 例：10ツイート取得した場合、0.5秒ごとに1ツイートを表示する

### 参考
- [Rate limits — Twitter Developers](https://developer.twitter.com/en/docs/basics/rate-limits)

## 設定画面に関して
### 概要
- 設定画面は以下の弊記事のようなことを考えて作成してます。
    - [macOSアプリ用の設定ウィンドウの作成方法](https://qiita.com/IKEH/items/e11911d01a417b577353)
- また以下のようなちょっとした工夫をしています。

### サンプルのメッセージを表示する
- 設定画面を表示している際、常時サンプルのメッセージを表示するようにしています。
    - 検索結果がない場合に、設定値の変更が確認できないと不便だからです。
- 細かい所かもしれませんが、使い勝手は良くなっていると思います。

<img width="600" alt="image" src="https://i.imgur.com/I3JtAO8.jpg">

### 移動時間変更時に画面をリロードする
- 移動する速度はテキストの長さによって変化するので、設定値を変更した際に違いが分かりにくいです。
- そのためテキストの移動時間を変更した際には、特別に画面を一度きれいにして、改めてテキストを表示するようにしています。

## 使用した外部ライブラリ
- 外部ライブラリは`Carthage`で管理をしています。
    - `Swifter`が`Cocoapods`に対応していなかった（できるという記事も見ましたがGitHub上には記載なしでした）ためです。
- [kishikawakatsumi/KeychainAccess](https://github.com/kishikawakatsumi/KeychainAccess)
    - キーチェーンをUserDefaults感覚で使えるライブラリ。
    - TwitterAPI用のトークン情報を、セキュリティのためキーチェーンに保存しています。
- [mattdonnelly/Swifter](https://github.com/mattdonnelly/Swifter)
    - TwitterAPIを使用する際の認証・情報取得はこちらを介して行っています。
    - TwitterAPIの公式にて、Swiftのライブラリとして紹介されていたのでこちらを採用しました。

# 競合アプリを調べてみました
- 世の中同じアイディアを考える人は多いもので、結構な数が見つかりました。
- ただモックレベルの記事が多く、アプリとしてリリースしているものは少なかったです。
- また（旬が過ぎているのか）長期間更新されず使用できなくなっているものも少なくありません。
- 少し前にTwitterのライブラリに変更もあったことも影響しているのかもしれませんね。
    - [TwitterKitのサポートが10月末に終了するのでSwifterに乗り換えた話 \- kurotyannの覚え書き](https://keeping.hatenablog.jp/entry/2018/10/22/010748)
    - > 2018年10月31日をもってTwitterKitのサポートが終了する
- また検索に引っかかるmacOSアプリは大体`Electron`で作成されています。（ネイティブでmacOSアプリ開発している人が少なくて寂しいですね…）
- 本アプリの差別化の要素としては、画面をコメント部分とリスト部分の2つを用意している所かなと思います。

## Twitter検索型と部屋型
### 概要
- プレゼンテーションに聴衆のコメントを表示するツールは、下記の二通りに分類することが出来ます。
    - `Twitter検索型`：Twitterでの検索結果を表示する
    - `部屋型`：発表者のスライド上にコメントを送るための、専用の部屋をWEBページ上に用意して、そこで入力されたコメントを表示する

### Twitter検索型
- 利点
    - 聴衆はTwitter（浸透度が高い）に投稿すればいいので、ハードルが低いです。
    - 聴衆はTwitterに投稿するだけでメッセージを送ることができます
    	- 聴衆は勉強会に参加しているという記録が残せます
    	- 勉強会や発表内容の宣伝になります
- 欠点
    - 誰でも書き込めるので、質が悪い・もしくは不適切なツイートが流れる恐れがあります

### 部屋型
- 利点
    - その場にいる人のみが書き込めるので、コメントの質が保つことができます
    - Twitterにコメントを残さずに済みます。（Twitterにコメントを残したい人もいるだろうし、人によるかな？）
- 欠点
    - 聴衆に専用のWEBサイトにアクセスさせるのが、ややハードルが高そうです。

## 競合アプリと技術記事
- [Comment Screen](https://commentscreen.com/)
    - サービスとしての完成度が高いです。
    	- マルチプラットフォーム対応
    	- Twitter検索型+部屋型の欲張りセット
    - エモーション（いいね！風のアクション）が送れるのが良いですね。
    - Keynoteのプレゼン表示に対応（どうやっているのか知りたい！）
    - メインスレッドでアニメーションをしているのか、UI設定の更新時にテキストが止まってしまい、設定値の確認がしにくいのが惜しい。
- [TweetRain \- ツイートを画面上に弾幕表示 MOONGIFT](https://www.moongift.jp/2016/09/tweetrain-%E3%83%84%E3%82%A4%E3%83%BC%E3%83%88%E3%82%92%E7%94%BB%E9%9D%A2%E4%B8%8A%E3%81%AB%E5%BC%BE%E5%B9%95%E8%A1%A8%E7%A4%BA/)
    - 更新がなく`macOS 10.15`でログインができない状態でした。
- [jikkyo](https://rot1024.github.io/jikkyo/)
    - 更新がなく、現在は使用できない状態です。
- [twitterをニコニコ風にするツール「n2witter」 \| uinyan．com](https://uinyan.com/n2witter/)
    - こちらはWindowsアプリです。
    - Twitterで検索する限り、今でも使えるようですね。
- [会場からの質問をスライドに自動表示！『Slido for Google Slides』の使い方](https://note.com/isobe1048/n/ne4fdd12643e6)
-  [パパパコメント](http://papapac.com/)
    - 部屋型です。
- [Twitterでプレゼンを盛り上げる「Tweet Bubbles」　質問をリアルタイム表示 \- CNET Japan](https://japan.cnet.com/article/20398220/)
    - 2012年に開発終了とのこと。
- [Electronでデスクトップいっぱいに雪を降らせるアプリを作る](https://qiita.com/nyamogera/items/a2e367b44e78d04ee3a6)
    - 今回のアプリが技術的に作れそうだな…とインスピレーション与えてくれた記事です。
- [\[OS X\] 透過型のTwitterクライアントを作ってみた ｜ Developers\.IO](https://dev.classmethod.jp/tool/transmission-twitter-client/)
    - アプリの構想時に参考にしました。
    - Githubも数年間更新がないので、今は使えないかも。
    - [furuya02/PresenSwitter](https://github.com/furuya02/PresenSwitter)

# 最後に
- Swiftの学習の一環として本アプリを作成しましたが、なかなか良い出来になったと思います。
- 「プログラムを学習する際は何か作ってみるといい」というのはよく言われる話ですが、実際にその通りだなと思いました。
    - モックレベルでもいいですが、アプリレベルにしようとすると、得られる知見も大きいと思いました。
    - UXに気を遣う必要がありますし、些細な妥協もしにくいです。
    - ただし、その分の労力もかかるのでモチベーションが大切ですね。
- 感想・要望等がありましたら、記事へのコメントやTwitterまで連絡をもらえると嬉しいです！
    - https://twitter.com/ikeh1024