✅ニコニコのURLからサムネイル画像を貼り付けるUserScriptを作る
開発着手前に考えていた仕様
メニューにニコニコのアイコンを追加する
クリックするとモーダルでURL入力を促される
[サムネイルURL https://www.nicovideo.jp/watch/sm37956838]
が貼り付けられる
---
サムネのURLを取得する
方法1
レスポンスがXMLで帰ってくる....
方法2
こっちは想定されていそうだし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はないとエラーが出る
zsherror: 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しても同種のエラーが出る
zsherror: TS2304 [ERROR]: Cannot find name 'Element'.
const node = doc.querySelectorAll('meta[property="og:image"]')[0] as Element;
解決策:deno-domのElementをロードしておけばcastできる
/watch/smXXXからサムネイルのURLを取得することができるようになった
mod.tsimport {
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にすればいい?
やってみたらサイズが大きすぎた
minifyしたい
zsherror: 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
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にデプロイしてみる
derror: Module not found "file:///var/runtime/mod.ts".
zipでダウンロードするサンプルコードが誤っている
罠すぎる
修正したら動いた
なんやかんやあり完成
ブラウザのセキュリティがあるからこれをそのまま使うことはできない
takkerさんのURL開くのはどうやっているか見てみたらScrapboxのAPIを使っていた
CLI版(動作確認のために作った副産物)
使い方
zshdeno run --allow-net https://scrapbox.io/api/code/motoso/ニコニコのURLからサムネイル画像を貼り付けるUserScript/cli.ts --url https://www.nicovideo.jp/watch/sm37587127
URLは正しい前提
cli.tsimport { 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);
--
>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.
tsconfigを追加したら大量のエラーが出るようになった
>Deno は TypeScript の設定ファイルをサポートしていますが、他と違い、設定ファイルの検出を使用は自動ではありません。Deno で TypeScript 設定ファイルを使うには、コマンドラインでパスを指定する必要があります