generated at
✅ニコニコのURLからサムネイル画像を貼り付けるUserScriptを作る

開発着手前に考えていた仕様
メニューにニコニコのアイコンを追加する
クリックするとモーダルでURL入力を促される
[サムネイルURL https://www.nicovideo.jp/watch/sm37956838] が貼り付けられる


---
サムネのURLを取得する
方法1
レスポンスがXMLで帰ってくる....
方法2
https://www.nicovideo.jp/watch/sm37956838 にCLIでアクセスするとogpが設定されているのでこのURLを抽出する
こっちは想定されていそうだしURLの意味がわかりやすいのでこっちをやってみる

せっかくなのでdenoで開発をしてみる

haederのURLが入っているmetaタグは次のように取れるが、ここからURLをとるのに苦戦
nodeを console.log() してみると attributes にURLがある。これを取得したい
zsh
attributes: NamedNodeMap { property: "og:image", content: "https://img.cdn.nimg.jp/s/nicovideo/thumbnails/37231246/37231246.20071609.original/r1280x720l?key=44..." },

deno-dom-wasmで取得したNodeからURLの文字列を取得できない
このMeta nodeはElementである
ts
(doc.querySelectorAll('meta[property="og:image"]')[0].nodeType) // 1 = Element
しかしElementにあるはずのattributesを取得しようとするとNodeにattributesはないとエラーが出る
zsh
error: TS2339 [ERROR]: Property 'attributes' does not exist on type 'Node'. console.log(doc.querySelectorAll('meta[property="og:image"]')[0].attributes)
attributesはElementの要素なのでNodeをElementにしたい
問題:castしても同種のエラーが出る
zsh
error: TS2304 [ERROR]: Cannot find name 'Element'. const node = doc.querySelectorAll('meta[property="og:image"]')[0] as Element;
解決策:deno-domのElementをロードしておけばcastできる
これをimportする必要があった.ts
import { Element } from "https://deno.land/x/deno_dom/deno-dom-wasm.ts";

/watch/smXXXからサムネイルのURLを取得することができるようになった
mod.ts
import { DOMParser, Element } from "https://deno.land/x/deno_dom/deno-dom-wasm.ts"; // https://www.nicovideo.jp/watch/sm37231246 export async function getThumUrl(url: string): Promise<string> { const res = await fetch(url); const doc = new DOMParser().parseFromString(await res.text(), "text/html"); if (doc == null) { throw new Error("document not found"); } const node = doc.querySelectorAll('meta[property="og:image"]')[0] as Element; const thumbUrl = node.getAttribute("content"); if (thumbUrl == null) { throw new Error("document not found"); } console.log(thumbUrl); return thumbUrl; }
どうやって?
URLの取得はこうすればいい
1. prompt方式
2. 範囲選択の文字列から正規表現で抽出
denoのプログラムをどうUserScriptにすればいい?
/takkerをみる
やってみたらサイズが大きすぎた
minifyしたい
zsh
error: TS2322 [ERROR]: Type '"esm"' is not assignable to type '"module" | "classic" | undefined'. bundle: 'esm', ~~~~~~ at https://scrapbox.io/api/code/deno-ja/Deno_script%E3%82%92bundle_&_minify%E3%81%99%E3%82%8B/script.ts:5:3
/takker/scrapbox-bundlerを使えばいいのかな
https://scrapbox.io/motoso/%E3%83%8B%E3%82%B3%E3%83%8B%E3%82%B3%E3%81%AEURL%E3%81%8B%E3%82%89%E3%82%B5%E3%83%A0%E3%83%8D%E3%82%A4%E3%83%AB%E7%94%BB%E5%83%8F%E3%82%92%E8%B2%BC%E3%82%8A%E4%BB%98%E3%81%91%E3%82%8BUserScript
この結果をScrapboxに貼り付けようとすると、imput is too largeになってしまう

コードをScrapbox上で動かすのは諦めてAPIにすることにした
Cloud functionsにデプロイしてみる?
Denoはそのままだと対応していない
ここまで大げさにするならタイトルとコメント載っけるのをSVGを作るまでやりたい
ダッシュボードでエラーが出て進めなかった
AWSにデプロイしてみる
https://github.com/hayd/deno-lambda を使ったけど実行に失敗した
derror: Module not found "file:///var/runtime/mod.ts".
zipでダウンロードするサンプルコードが誤っている
罠すぎる基素
https://zenn.dev/kawarimidoll/scraps/44009b392ed9f2#:~:text=適当にログを出すよう書き換えてDeploy もサンプルコードの同じで動いていると書いてあるのでどこかのタイミングでは動いていたのかもしれない
修正したら動いた
なんやかんやあり完成
ブラウザのセキュリティがあるからこれをそのまま使うことはできない
takkerさんのURL開くのはどうやっているか見てみたらScrapboxのAPIを使っていた
というわけでUserScriptを作った nicovideo-thumbnail-proxy


CLI版(動作確認のために作った副産物)
使い方
zsh
deno run --allow-net https://scrapbox.io/api/code/motoso/ニコニコのURLからサムネイル画像を貼り付けるUserScript/cli.ts --url https://www.nicovideo.jp/watch/sm37587127
URLは正しい前提
cli.ts
import { parse } from "https://deno.land/std@0.136.0/flags/mod.ts"; import { DOMParser, Element } from "https://deno.land/x/deno_dom/deno-dom-wasm.ts"; async function getThumUrl(url: string): Promise<string> { const res = await fetch(url); const doc = new DOMParser().parseFromString(await res.text(), "text/html"); if (doc == null) { throw new Error("document not found"); } const node = doc.querySelectorAll('meta[property="og:image"]')[0] as Element; const title = doc.querySelectorAll('head > title')[0] as Element; console.log(title.textContent); const thumbUrl = node.getAttribute("content"); if (thumbUrl == null) { throw new Error("document not found"); } console.log(thumbUrl); return thumbUrl; } const parsedArgs = parse(Deno.args); getThumUrl(parsedArgs.url);


--   

DenoのDOMはElement classしかないらしい(2021年11月)
>So far Deno DOM only implements the Element class. .href is a property of HTMLAnchorElement, a more specific DOM element implementation, of which there are many, and I haven't got around to implementing yet. So for now you can use the getAttribute("href") method of Element.

DOMのparseはdeno-dom-wasmよりcheerioの方が便利らしい

tsconfigを追加したら大量のエラーが出るようになった
>Deno は TypeScript の設定ファイルをサポートしていますが、他と違い、設定ファイルの検出を使用は自動ではありません。Deno で TypeScript 設定ファイルを使うには、コマンドラインでパスを指定する必要があります