twitter から Misskey.io にダブルポスト (3)

 

Blogger からの更新通知(Webhook 相当?)を IFTTT で受けて、直接 Misskey.io に投稿するのでは「画像つきノート」にならないため、twitter の @bojan_net(画像つきツイート実現済み)のツイートをパクるコピーする方法を試してみたのですが……
ご覧の通り、かなり残念な仕上がりになってしまいました。

とりあえず、改善すべき点として
  • 短縮 URL(t.co)を展開する
  • 画像つきノート
の 2 つがあるのですが、IFTTT だけの実装では難しそうな感じです。ということで……
間に Google Apps Script (GAS) を挟むことにしました。GAS はサーバを手元に持つこと無しに JavaScript ライクなスクリプトを実行できる環境(という理解)なのですが、使用するのはもちろん初めてなのでさっぱり使い方がわかりません。

ただ幸いなことに、ほぼそのまま使えるスクリプトが公開されていました。
【IFTTT】TwitterからMisskeyへ自動投稿する

これに対して、以下を実現できるように改良すれば良いということになります。
  • 短縮 URL(t.co)を展開する
  • 画像つきノート

短縮 URL の展開

短縮 URL の展開についても、Googleスプレッドシート上で短縮URLを展開するGoogle Apps Script という記事が公開されていました(ありがたやありがたや)。これは expandURL という関数になっていて、短縮 URL を渡せば展開後の URL が戻って来るという代物です。

ということで、両者を合体させてみました。

function doPost(e) {
  const jsonString = e.postData.getDataAsString();
  const data = JSON.parse(jsonString);
  let tweet = data.tweet;
  //
  // ■ t.co にマッチする正規表現
  //
  const regex = /https:¥/¥/t.co¥/¥w{1,}/;
  //
  // ■ tweet 本文内の t.co をマッチする限り展開する
  //
  while(shortUrl = regex.exec(tweet)) {
    let shortUrlRegex = new RegExp(shortUrl);
    let expandedUrl = expandURL(shortUrl);
    tweet = tweet.replace(shortUrlRegex,expandedUrl);
  }
  const res = postToMisskey(tweet);
  return JSON.stringify(res);
}

ただ、これだと https://www.bojan.net/ ではなく http://www.bojan.net/ が戻ってきてしまうので(Blogger のせい)、以下の行を postToMisskey の直前に追加します。

  tweet = tweet.replace("http://www.bojan","https://www.bojan");

見ての通り、割とそのまんまな処理です。これらのロジックを追加することで、憎き t.co を撲滅して https://www.bojan.net/ のアドレスに戻すことができました。

ついでに

ふと気づいたのですが、IFTTT にはこんな trigger も用意されていました。New tweet by a specific user、つまり「特定ユーザーによる新しいツイート」を拾うこともできてしまうっぽいのですね。これは @bojan_net だけでなく、@bojan_intl のツイートも Misskey.io にコピーできてしまう、ということに……?
そして、GAS を使って Misskey.io にノートを投稿できるのと同様に、GAS を使って Bluesky にも投稿できるとのこと。Bluesky 向けのとても良くできたスクリプトが公開されていたので、それを流用したのですが、今はページごと消え失せてしまっていました……(無念)。
まぁ似たようなサイトがいくつかあるので()、気になった方は調べていただければ……。

画像つきノート

ということで、テキストだけのツイートであれば Misskey.io(と Bluesky)に複製できるようになったのですが、問題は画像つきツイートの扱いです。

画像つきノートの実装は、ツイートの中から画像の URL を引っこ抜けばいい……と思っていたのですが、そう簡単ではありませんでした。https://t.co/leZlOYLKWi を展開すると https://twitter.com/bojan_net/status/1895074207257489753/photo/1 となるのですが、この URL にアクセスしたところで https://x.com/bojan_net/status/1895074207257489753 が表示されるだけで、しかも肝心の画像 URL の所在がわからないままです。

Web ブラウザは html の内容がそのまま表示されるものですが、昨今の Web サイトはゴリゴリ Javascript を使用して html を動的に生成しています。動的に生成された html を取得するには、Javascript をレンダリングしてその結果を GAS で拾うしか無いのですが、世の中よく出来たもので、まさにこのニーズに対応したサービス(Phantomjs Cloud)が提供されていました(しかも一日 500 リクエストまでは無料!)。
IFTTT から飛んできた URL(変数 LinkToTweet に格納されたもの)を Phantomjs Cloud で展開することで、画像 URL が含まれる html を GAS に持ち帰ることができました。

具体的にはこんなコードを書いています。仕様書などを見ずに経験則で書いているので、正規表現に不足があるかもしれません。あと何故か同一の URL が複数ヒットするので、同じ URL を弾くロジックを追加しています(18 行目)。

  const LinkToTweet = data.LinkToTweet;

  //
  // ■ LinkToTweet をスクレイピング
  //
  const fileIds = new Array();
  if(TweetText.match(/https:¥/¥/(twitter|x).com¥/¥w{1,}¥/status¥/[0-9]{1,}¥/photo¥/[0-9]{1}/)) {
    console.log('scraping……');
    var response = scrape_(LinkToTweet);
    const json_response = JSON.parse(response);
    let source = json_response["content"]["data"].toString();
    const imageUrls = source.match(/https:¥/¥/pbs.twimg.com¥/media¥/[A-Za-z0-9_¥-]{1,}¥?format=(jpg|png)¥&amp¥;name=[A-Za-z0-9]{1,}/g);
    let lastUrl;

    if (imageUrls != null && 0 < imageUrls.length) {
      for (let i = 0; i < imageUrls.length && i < 8; ++i) {
        if( lastUrl != imageUrls[i] ) {
          let imageUrl = imageUrls[i];
          lastUrl = imageUrl;
          imageUrl = imageUrl.replace(/¥&amp;/g,"¥&");
          Logger.log(imageUrl);
          var response = uploadFile_(imageUrl);
          let responseJSON = JSON.parse(response.getContentText());
          let fileId = responseJSON.id;
          fileIds.push(fileId);
          console.log(fileId);
        }
      }
    }
  }
※ const imageUrls = の行が改行されちゃってますが、本来は name=[A-Za-z0-9]{1,}/g); までが同じ行です。

変数 LinkToTweet の URL を PhantomjsCloud で展開しているのですが、PhantomjsCloud での処理は Twitter APIを使わずにTwitterの画像付き投稿をDiscordに流すbotを作った話のサンプルスクリプトをそのまま(関数名を scrape から scrape_ に変えただけ)借用しました。

というわけでぇ

ここまでの処理により https://twitter.com/bojan_net/status/1895074207257489753 から https://pbs.twimg.com/media/Gkyn8pBX0AA4lc9?format=jpg&name=medium という URL を引っこ抜くことができました。

つづく……?

前の記事続きを読む

www.bojan.net
Copyright © 1995- Bojan International

0 件のコメント:

新着記事