From 40dab66fe9747d69a4c4b35297e9f6b29a1b65c2 Mon Sep 17 00:00:00 2001 From: takker99 <37929109+takker99@users.noreply.github.com> Date: Tue, 26 Jul 2022 08:08:13 +0900 Subject: [PATCH 1/2] =?UTF-8?q?:bug:=20Youtube=E3=81=AE=E3=82=B5=E3=83=A0?= =?UTF-8?q?=E3=83=8D=E3=82=A4=E3=83=AB=E3=82=92=E3=83=9A=E3=83=BC=E3=82=B8?= =?UTF-8?q?=E3=82=AB=E3=83=BC=E3=83=89=E3=81=AE=E3=82=B5=E3=83=A0=E3=83=8D?= =?UTF-8?q?=E3=82=A4=E3=83=AB=E3=81=AB=E3=81=A7=E3=81=8D=E3=81=A6=E3=81=84?= =?UTF-8?q?=E3=81=AA=E3=81=8B=E3=81=A3=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parseYoutube.ts | 62 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 parseYoutube.ts diff --git a/parseYoutube.ts b/parseYoutube.ts new file mode 100644 index 0000000..4586e8e --- /dev/null +++ b/parseYoutube.ts @@ -0,0 +1,62 @@ +// ported from https://github.com/takker99/ScrapBubble/blob/0.4.0/Page.tsx#L662 + +export interface YoutubeProps { + params: URLSearchParams; + videoId: string; +} + +const youtubeRegExp = + /https?:\/\/(?:www\.|)youtube\.com\/watch\?((?:[^\s]+&|)v=([a-zA-Z\d_-]+)(?:&[^\s]+|))/; +const youtubeShortRegExp = + /https?:\/\/youtu\.be\/([a-zA-Z\d_-]+)(?:\?([^\s]{0,100})|)/; +const youtubeListRegExp = + /https?:\/\/(?:www\.|)youtube\.com\/playlist\?((?:[^\s]+&|)list=([a-zA-Z\d_-]+)(?:&[^\s]+|))/; + +/** YoutubeのURLを解析してVideo IDなどを取り出す + * + * @param url YoutubeのURL + * @return 解析結果 YoutubeのURLでなかったときは`undefined`を返す + */ +export const parseYoutube = (url: string): YoutubeProps | undefined => { + { + const matches = url.match(youtubeRegExp); + if (matches) { + const [, params, videoId] = matches; + const _params = new URLSearchParams(params); + _params.delete("v"); + _params.append("autoplay", "0"); + return { + videoId, + params: _params, + }; + } + } + { + const matches = url.match(youtubeShortRegExp); + if (matches) { + const [, videoId] = matches; + return { + videoId, + params: new URLSearchParams("autoplay=0"), + }; + } + } + { + const matches = url.match(youtubeListRegExp); + if (matches) { + const [, params, listId] = matches; + + const _params = new URLSearchParams(params); + const videoId = _params.get("v"); + if (!videoId) return; + _params.delete("v"); + _params.append("autoplay", "0"); + _params.append("list", listId); + return { + videoId, + params: _params, + }; + } + } + return undefined; +}; From 2895b43ff7c0f401c3b1b31a9724121d192adf52 Mon Sep 17 00:00:00 2001 From: takker99 <37929109+takker99@users.noreply.github.com> Date: Tue, 26 Jul 2022 08:09:40 +0900 Subject: [PATCH 2/2] =?UTF-8?q?:recycle:=20makeChanges=E3=82=92generator?= =?UTF-8?q?=E3=81=AB=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/makeChanges.ts | 42 ++++++++++++++++++++------------ browser/websocket/patch.ts | 4 ++- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/browser/websocket/makeChanges.ts b/browser/websocket/makeChanges.ts index 0b12cf8..392d2af 100644 --- a/browser/websocket/makeChanges.ts +++ b/browser/websocket/makeChanges.ts @@ -10,32 +10,35 @@ import { import type { Change } from "../../deps/socket.ts"; import type { HeadData } from "./pull.ts"; import { toTitleLc } from "../../title.ts"; +import { parseYoutube } from "../../parseYoutube.ts"; export interface Init { userId: string; head: HeadData; } -export const makeChanges = ( +export function* makeChanges( left: Pick[], right: string[], { userId, head }: Init, -): Change[] => { +): Generator { // 改行文字が入るのを防ぐ const right_ = right.flatMap((text) => text.split("\n")); - // 本文の差分 - const changes: Change[] = [...diffToChanges(left, right_, { userId })]; + // 本文の差分を先に返す + for (const change of diffToChanges(left, right_, { userId })) { + yield change; + } // titleの差分を入れる // 空ページの場合もタイトル変更commitを入れる if (left[0].text !== right_[0] || !head.persistent) { - changes.push({ title: right_[0] }); + yield { title: right_[0] }; } // descriptionsの差分を入れる const leftDescriptions = left.slice(1, 6).map((line) => line.text); const rightDescriptions = right_.slice(1, 6); if (leftDescriptions.join("") !== rightDescriptions.join("")) { - changes.push({ descriptions: rightDescriptions }); + yield { descriptions: rightDescriptions }; } // リンクと画像の差分を入れる @@ -44,14 +47,12 @@ export const makeChanges = ( head.links.length !== links.length || !head.links.every((link) => links.includes(link)) ) { - changes.push({ links }); + yield { links }; } if (head.image !== image) { - changes.push({ image }); + yield { image }; } - - return changes; -}; +} /** テキストに含まれる全てのリンクと最初の画像を探す */ const findLinksAndImage = (text: string): [string[], string | null] => { @@ -86,11 +87,20 @@ const findLinksAndImage = (text: string): [string[], string | null] => { links.push(node.href); return; case "link": - if (node.pathType !== "relative") return; - if (linksLc.get(toTitleLc(node.href))) return; - linksLc.set(toTitleLc(node.href), true); - links.push(node.href); - return; + switch (node.pathType) { + case "relative": + if (linksLc.get(toTitleLc(node.href))) return; + linksLc.set(toTitleLc(node.href), true); + links.push(node.href); + return; + case "absolute": { + const props = parseYoutube(node.href); + if (!props) return; + return `https://i.ytimg.com/vi/${props.videoId}/mqdefault.jpg`; + } + default: + return; + } case "image": case "strongImage": { image ??= node.src.endsWith("/thumb/1000") diff --git a/browser/websocket/patch.ts b/browser/websocket/patch.ts index 941a947..ac0c2d8 100644 --- a/browser/websocket/patch.ts +++ b/browser/websocket/patch.ts @@ -65,7 +65,9 @@ export const patch = async ( }); } - const changes = makeChanges(head.lines, newLines, { userId, head }); + const changes = [ + ...makeChanges(head.lines, newLines, { userId, head }), + ]; await pushCommit(request, changes, { parentId: head.commitId, projectId,