hitode909の日記

以前はプログラミング日記でしたが、今は子育て日記です

HackerNewsのランダムなニュースを再生し続けるMac用スクリーンセーバー

テレワークでずっと家に居ると、リビングに置いてるテレビを見たり、Macのスクリーンセーバーが動いているのが目に入ったりする時間が増えてきたので、テレビで見れたり、Macを使ってない間にぼーっと眺められる形のコンテンツを模索したい。
WebViewを開いて、JSを実行し続ける形でHackerNewsのコンテンツをランダムに流すスクリーンセーバーを作ってみた。
github.com


やっていることは至極簡単で、ScreenSaverViewのinitでWebViewを作って、タイマーを定期的に動かす。

    override init?(frame: NSRect, isPreview: Bool) {
        super.init(frame: frame, isPreview: isPreview)
        
        self.animationTimeInterval = 999.0

        let webConfiguration = WKWebViewConfiguration()
        self.webView = WKWebView(frame: self.bounds, configuration: webConfiguration)
        self.addSubview(self.webView)
        
        self.timer = Timer.scheduledTimer(timeInterval: 10.0, target: self, selector: #selector(self.step), userInfo: nil, repeats: true)
        self.timer.fire()
    }


で、タイマーでJavaScriptのコードを実行する。これは10秒おきに実行していて、

  • HackerNewstorylinkクラスのaタグがあればランダムに選んでクリックする
  • そうでなければページスクロール
  • ページスクロールの100ミリ秒後にスクロール位置が変わっていなければページ最下までたどり着いたとみなしてHackerNewsに戻る
    @objc func step() {
        let code: String = """
            (() => {
                const TOP_URI = 'https://news.ycombinator.com/';
                const pick = (list) => list[Math.floor(Math.random() * list.length)];
                const newsLinks = document.querySelectorAll('a.storylink');
                const visitTop = () => location.href = TOP_URI;
                // visit random news
                if (location.href === TOP_URI && newsLinks.length > 0) {
                    location.href = pick(newsLinks);
                }
                // scroll articles
                else {
                    const topBefore = window.scrollY;
                    window.scrollBy(0, window.innerHeight * 0.9);
                    setTimeout(() => {
                        const topAfter = window.scrollY;
                        // detect bottom
                        if (topBefore === topAfter) {
                            console.log('visitTop');
                            visitTop();
                        }
                    }, 100);
                }
            })()
            """
        self.webView.evaluateJavaScript(code, completionHandler: nil)
    }

ということをやっている。ページ遷移すると前回実行していたJSが消えてしまうので、タイマーはJavaScript側ではなくてSwift側でやっていることと、JS側は状態を持ってなくて、こういう状況ならこれをする、というのを淡々と書いているのが特徴。

経緯

もともとは仕事でメンテナンスしているウェブサービスをランダムに巡回するために作っていて、それはなかなか便利だった。休憩して戻ってくると、自分たちがホスティングしているけど見たことないコンテンツが流れてきて、へえこんなコンテンツもあるのね、ということがあったり、偶然壊れてるページを見つけられたら人力テストとしても便利。
便利さはともかく、JSを定期的に動かすだけで好きなコンテンツを流せて汎用性が高いので、Hacker Newsをランダムに閲覧する形にコードを変えてGitHubに置いといた、という形。
JSを書き換えてビルドするだけで好きなウェブサイトを流すことができるのでいろいろ模索するときの雛形としてはそこそこ便利なのではないかと思う。
Swift入門とかmacのアプリを作るための前提知識とかは持ってないのですさまじい脆弱性がある可能性がある。プロダクションでは使わないでください。

不便な点

ビルドしてから実行するまでの手順が長くて、Finderで開き、ダブルクリックするとシステム環境設定のスクリーンセーバーが開き、置き換えますかと聞かれてはいと答えると置き換えられるけど、それだけでは更新されず、一度システム環境設定のトップに戻ってからスクリーンセーバーを再度開いてプレビューボタンを押す、という工程を毎回やっていて不便だった。