@broberg/网络剪辑器
舰队的一个网络剪接基地——Trail Web Clipper和Jam Clipper在此基础上更上一层楼(pic F099,克里斯蒂安的建造命令12/10 2026). 没有叉子:改进到上游.
@broberg/web-clipper/core 指纹引擎(F099.2)
import { chain, diff, idempotencyKey, verify } from "@broberg/web-clipper/core";
const units = [{ kind: "turn", role: "user", content: "Hej", position: 0 }, /* … */];
const d = await diff(knownChainFps, units); // what the destination already has, in order ([] for new)
// d.kind: "same" (nothing to send) | "append" (send d.units) | "branch" (an earlier unit changed:
// a new branch from d.forkAt with parent d.parentChainFp — the old line is never overwritten)
for (const link of d.kind === "same" ? [] : d.links) send(unit, { idempotencyKey: idempotencyKey(link) });
- A 类 单位 是一个页面,或者一个聊天回合。 其指纹为sha256 over(实物,角色,位置,内容).
- 这个 链式 一个单位的指纹包括上一个,所以任何更早的地方都会改变它之后的一切.
- 只发送新, (中文(简体) ), 不重复重发 (一能键是链纹指纹), 分支 当一个提示被编辑或重新生成时
verify()找到一个被篡改的单位. - 每次替换整个页面的目的地( Trail: 每个 URL 一个来源) 只需通过
[]并发送一切——这是不附带附件的目的地的默认.
@broberg/web-clipper/extract ——取出插头点(F099.3)
import { extractClip, type Extractor } from "@broberg/web-clipper/extract";
const chatgpt: Extractor = { id: "chatgpt", matches: (u) => u.hostname === "chatgpt.com", extract: async (doc, url) => ({ /* Clip */ }) };
const clip = await extractClip(document, new URL(location.href), [chatgpt]); // yours first, the article extractor otherwise
articleExtractor有轨电车的取出器(可读性+倒数,相同的选项和规则)解除不变;有一次测试显示它与同页的有轨电车自己的文件(f5ce8ba)的字节相同输出.- 您的提取器按您通过顺序进行测试; 第一场比赛获胜. 无任何匹配 = 文章提取器 .
- 永远是决定性的: 同样的 DOM 必须给出字节- 相同的标记下, 或者重新装入看起来像一个编辑, 指纹引擎打开一个假分支。 规则也约束了你的提取器.
- 一个没有要剪掉的页面
NothingToClipError- 从不空出.
@broberg/web-clipper/transport 目的地和发送者(F099.4)
import { sendClip, DestinationError, type Destination } from "@broberg/web-clipper/transport";
const trail: Destination = {
id: "trail", label: "Trail",
targets: async (s) => /* tenant × brain */ [],
async send(units, { target, session, clip }) {
const res = await fetch(url, { method: "POST", headers: { authorization: `Bearer ${session.accessToken}` }, body });
if (!res.ok) throw new DestinationError(res.status); // report the HTTP answer — the base decides what it means
},
};
const r = await sendClip({ destination: trail, target, clip, auth });
// r.state: "sent" | "login_required" («log ind igen») | "consent_required" | "refused" (4xx) | "unavailable" (5xx/network, retries spent)
- 只有新单位 用于
appendOnly目标( 答案)lastSeen(anchor)与链状指纹; 所有其他目的地每次都得到整个剪辑. - 同上,propoency key = 链式指纹. 电池
batchSize,默认为50)是逐一执行的,所以中断的运行恢复到停止的地方:没有两次,没有丢失. - 401 (中文(简体) ) + 一个强制会话刷新并重发;没有会话或再次401
login_required。 。 。 . 5xx/ 网络 ——退后(500毫秒,翻倍,4次尝试) ——unavailable永远不要迷惑. 其他 4xx (单位:千美元) →refused,没有重考. - 目的地为
requiresConsent一无所获直到consented: true为那个锚.
@broberg/web-clipper/auth —— BrobergID 从扩展名登录(F099.5)
import { createBidAuth } from "@broberg/web-clipper/auth";
const auth = createBidAuth({
issuer: "https://id.broberg.ai",
clientId: "trail-clipper", // this extension's PUBLIC BID client — no secret anywhere
audience: "https://app.trailmem.com", // optional: session() then returns a user TICKET for that receiver
ticketScope: "trail:clip",
});
await auth.login(); // chrome.identity.launchWebAuthFlow, PKCE (S256) + state
const r = await sendClip({ destination, target, clip, auth }); // auth IS the sender's session source
- 运行背景中的登录( 0. 4. 0) . Chrome在失去焦点时会关闭弹出器,而登录窗口则会关闭焦点——一个从弹出器中开始的登录在信使被存储之前就已死亡(BrobergID表示是,按钮仍然表示"Log ind";在Trail 12/10中被测量. 所以说:
弹出会问,背景日志输入并存储;关闭弹出会中日志一无所获,下一弹出会发现会话.// background.ts import { createBidAuth, serveLogin } from "@broberg/web-clipper/auth"; serveLogin(createBidAuth(bidOptions)); // popup.tsx — same bidOptions import { createBidAuth, popupAuth } from "@broberg/web-clipper/auth"; <ClipperPopup auth={popupAuth(createBidAuth(bidOptions))} … /> - 一个被拒绝的代码交换表示HTTP状态和BrombergID的答案的简短摘录(代码和令牌被擦除),例如.
BID refused the code (HTTP 400): http_400 redirect_uri mismatch…。 。 。 . - 需要一个
identity财务报告和审定财务报表storage权限。 托肯斯住在这里chrome.storage.local,由客户端 id 键入——两个扩展从不共享登录. session()到期前续约. 拒绝刷新 (用户的 BID 登录结束)null并清除登录 ~ 显示“ log ind igen ” . BID 未响应 →BidUnavailableError,登录保存,发送者报告unavailable,不是登录.- 与
audience: BID 令牌被交换为5分钟的用户票(BID F087.37),在有效时重新使用,当发送者在401后强制刷新时重新取回.session_ended→null; 设置拒绝(no_rule_for_audience, (中文(简体) ),scope_not_allowed页:1BidTicketRefusedError(发件人报告)refused) (中文(简体) ). - 重定向是
chrome.identity.getRedirectURL()=:https://<extension-id>.chromiumapp.org/—— BID 与字符匹配,所以扩展需要一个 FIXED ID(明显)key) (中文(简体) ).
绘制您的 OWN 弹出 : /engine (0.7.0, F099.12) (中文(简体) )
设计属于使用此软件包的扩展名,而非软件包 (所有者,13/10). /engine 是弹出的所有 DOS —— 登录、加载和记住目标、剪辑、每次谈话的同意、发送、报告—— 没有元素、 CSS 和文本:
import { createClipper } from "@broberg/web-clipper/engine"; // framework-free
import { useClipper } from "@broberg/web-clipper/ui"; // the same, as a Preact hook
const [s, clipper] = useClipper({ auth: popupAuth(createBidAuth(opts)), destination, getClip: () => clipActiveTab(CONTENT_SCRIPT_PATH), storage: extensionStorage() });
s.phase.kind // "checking" | "logged_out" (reason "login_again" | "login_failed", message) | "logging_in" | "ready"
s.targets, s.target // where it can go; the chosen one (remembered per destination)
s.run // { kind: "idle" | "clipping" } | { kind: "done", result, clip } | { kind: "error", message }
// result.sent = units sent · clip.completeness = { complete, reason } — show it when complete is false
s.consentFor // a conversation that needs «record this conversation» → clipper.clip({ consent: true })
s.notAConversation // consent needed but the page is no conversation — say so
clipper.login() · clipper.logout() · clipper.choose(id) · clipper.clip({ fields })
你的短信 你的布局 你的身高. ClipperPopup (下)是一个现成的绘制方法——可选的,并建在这个相同的引擎上,所以它的行为与你的完全一样.
扩展名 : /extension, (中文(简体) ), /content, (中文(简体) ), /vite, (中文(简体) ), /ui (单位:千美元)
// vite.config.ts — a whole clipper from the shared build
import { defineConfig } from "vite";
import { defineClipperManifest } from "@broberg/web-clipper/extension";
import { clipperViteConfig } from "@broberg/web-clipper/vite";
export default defineConfig(clipperViteConfig({
manifest: defineClipperManifest({ name: "Trail Web Clipper", version: "0.3.0", apiHosts: ["https://app.trailmem.com/*"], bidIssuer: "https://id.broberg.ai", geckoId: "[email protected]" }),
}));
// src/content.ts — import ONLY /content and your extractors here
import { runContentScript } from "@broberg/web-clipper/content";
runContentScript([myChatReader]);
// src/popup.tsx
import "@broberg/theme/css/palettes.css";
import "@broberg/web-clipper/css/clipper.css";
import { createBidAuth, popupAuth, extensionStorage } from "@broberg/web-clipper/auth";
import { clipActiveTab, CONTENT_SCRIPT_PATH } from "@broberg/web-clipper/extension";
import { ClipperPopup } from "@broberg/web-clipper/ui";
render(<ClipperPopup title="Trail" auth={popupAuth(createBidAuth({ issuer, clientId: "trail-clipper", audience, ticketScope }))}
destination={trail} getClip={() => clipActiveTab(CONTENT_SCRIPT_PATH)} storage={extensionStorage()} />, root);
- 权限 :
activeTab, (中文(简体) ),scripting, (中文(简体) ),identity, (中文(简体) ),storage、apiHosts(仅后端)和 BrobergID 从bidIssuer(需要0. 3. 0) — 它的符号端点不会发出 CORS 页眉, 所以没有它登录失败 。 没有页面主机:内容脚本被点击后注入,从未声明. - 内容脚本必须独立. 它作为经典剧本运行,所以不能
import; 如果与弹出共享模块, 构建失败( 命名共享块) . - 你自己的田园 (0.2.0,F099.8): (中文(简体) )
ClipperPopup({ fields: [{ id: "tags", label: "Emneord", placeholder: "kommasepareret" }] })- 每个字段的文本输入(clipper-field-<id>); 数值到达您send()作为ctx.fields(单位:千美元){ tags: "…" }) (中文(简体) ). 从未存储 : 新弹出开始为空 。 无fields, (中文(简体) ),ctx.fields缺席. - 聊天阅读器(0.5.0,F099.9):
runContentScript(chatReaders)(从)/extract剪辑 ChatGPT(chatgpt.com/c/…和克劳德(Eclaude.ai/chat/…)作为每转弯一个单位,主播=对话id. 他们从页面自己的数据(作为用户签名;屏幕上的线程是:clip.units,没有隐藏工具/搜索消息;其他分支进入clip.branches自0.1.0起),因为屏幕只持有~8个长线条的信息,被保存的页面没有. 如果数据无法读取, 他们会剪辑屏幕上的内容并设定clip.completeness = { complete: false, source: "dom", reason };只有全文complete: true共享的 CHATGPT 链接chatgpt.com/share/…)在页面本身中携带整个对话(不需要登录),从那里读取完整(在真实共享链接上测量的0.5.1:30转,屏幕显示13;克洛德共享链接仍然从屏幕上读取并被标记为不完整. 克洛德的文物作为档案(0.6.0,F099.10): 每一件艺术品,一转即产生或改变(claude. ai 的文物工具和文件工具create_file编号 :str_replace是一个unit.assets[]条目{ type: "file", id, name, mime, language?, content, version }——该回合的文件AS(对上一个版本适用了修改). 转动的文字得到[Artefakt: <title>]所以只有一件文物的转弯 已经不再掉下去.Asset.url现在可选。 所附人员的文件也保留(0.6.1):仅作为附件的电文保持自己的转弯([Bilag: name],将提取的文本作为文件)和上传的图像命名([Fil: name]) (中文(简体) ). 读者不明白的信息部分或无法应用的更改使剪辑complete: false出于这个原因——它从未被默默地跳过。 每个剪辑 REPLACES 内容脚本的前一个收听器(0.5.1),所以重新加载的扩展在已经打开的分页中工作而不重新加载. 仅限附件的目的地应保留不完整的聊天片段 : 它的单位是从 0 开始的可见的 TAIL 编号,所以它们的位置与整个对话不匹配,链会读作一个新的分支. 完整的剪辑总是对全线有0.n-1的位置,同线在每一个读取上都给出了字节-等同的单位. 将阅读器建在htmlToMarkdown(html)(从/extract)——与物品提取器相同的转换. - 无声跳跃(0.7.1,F099.13): a Claude 工具呼叫读者不知道 – 一个编写文件或制作图像的代码工具 – 制作剪辑
complete: false名称工具。 只有读取或搜索的工具(web_search, (中文(简体) ),web_fetch, (中文(简体) ),view被跳过。 代码工具本身的文件来自0.8.0. 缺少的(0.7.2): 一个不完整的片段说completeness.missing数字 :"files"= 每个转弯被全读,只有文件缺失——保持转弯,显示文件警告;"turns"=旋转本身不全(从屏幕上读取,或可能持有单词的部分不被理解). - 档案本身(0.8.0,F099.13): 文件中包含对话的 SHOWS 但不携带, 由内容脚本与页面自身的会话获取( 您的服务器从未登录到 claude.ai / chitchgpt.com ) , 并且以
unit.assets[]数字 :{ type: "file", id, name, mime, size, content }文本作为文本,其他任何内容(PNG、ZIP、MP4)encoding: "base64". Claude: Artifacts 面板中的每个文件(什么present_files移交; 一次以上提交的文件一次取出, 最后一次取出) 并上传图像 。 ChatGPT: 生成图像并上传(image_asset_pointer)和代码工具文件(sandbox:/mnt/data/…链接)。 转动每个文件的文本名( T)[Fil: …], (中文(简体) ),[Billede: …]。限制:每个文件25 MB,每个剪辑60 MB。 无法获取或超过限制的文件在completeness.reason与missing: "files"- 转弯还是完整的 尚未: ChatGPT 画布, 共享链接上的文件( 名称 :,missing: "files") (中文(简体) ). 0.8.1: (中文(简体) ) ChatGPT文件现在下载(下载地址是ChatGPT自己的,需要登录——0.8.0得到403);生成的图像由自己的标题命名;克洛德从什么取出完整的文件列表present_files要求交出(0.8.0只读结果,名字较少);completeness.problems[]列出每个问题和reason全部名字; 引用弹出语为 “ Alle ture er gemt —— N file mangler ” (中性,clipper-incomplete-files当只缺少文件时. 0.8.2 — DATA 缺少文件:completeness.missingFiles: { name, why, status?, tool? }[]每一个文件 片段没有携带, 从来没有第一批.why数字 :no_url• 妇女http(+ 数)status·network• 妇女no_download_url• 妇女too_large• 妇女clip_limit• 妇女unknown_tool(+ 数)tool·unapplied。绘制您网站想要的信息;reason保留为纯文本. 0.8.3 (中文(简体) ) 拒绝的批次报告sent(在它之前到达了多少个单位);文件每段可达100 MB / 300 MB (配置 :maxFileBytes, (中文(简体) ),maxClipFileBytes在阅读器上)——一个大于一个扩展消息的文件以部分方式行走,由clipActiveTab克劳德:acurrent_leaf如果剪辑线上有NEWER的谈话版本 剪辑线上写着missing: "turns"。 。 。 . - 双子座(0.12.0,F099.22):
chatReaders现在包括geminiReader(单位:千美元)gemini.google.com/app/<id>,还有/u/<n>/app/<id>(原始内容存档于2018-10-25). Gems. 每个转弯1个单元(用户行;答案为markdown),主播=对话id,屏幕阅读器标签被忽略. 它读取了SCREEN——双子座通过Google内部的RPC装入了对话,但尚未被测量——所以片段说:complete: false, source: "dom", missing: "turns":长篇对话只保留了自己的一部分在屏幕上. 和屏幕读取的一样. - 复杂度(0.13.0,F099.22):
chatReaders现在包括perplexityReader(单位:千美元)perplexity.ai/search/<slug>) (中文(简体) ). 每个回合一个单位——问题来自[data-message-bubble],答案为:[data-renderer]——锚 = 线粒体. 就像双子座一样 它现在读了SCREENcomplete: false, source: "dom", missing: "turns":线程数据调用已知(GET /rest/thread/),持有接应文本的块尚未被测量. - 微软365副驾驶(0.14.0,F099.22):
chatReaders现在包括copilotReader(单位:千美元)copilot.cloud.microsoft/chat/conversation/<id>) (中文(简体) ). 每转弯一个单位.fai-UserMessage编号 :.fai-CopilotMessage__content(回答为下划线);可访问标题、名称和工具栏被删除。 斯莱恩读到,complete: false, source: "dom", missing: "turns"——副驾驶的列表是虚拟化的(只有靠近取景口的转弯存在),其数据调用没有被看到. - 嵌入式登录(0.15.0,F099.24):
auth.embedded()在从createBidAuth(和popupAuth通过)——对BID的F084.166合同v1:没有窗口,一个6位数的代码通过邮件登录INSIDE弹出后,如果账户有1个因素(如果有1个)totp应用程序代码,或sms之后sendSms()) (中文(简体) ). 无头状态机器——state(), (中文(简体) ),subscribe(), (中文(简体) ),resume(), (中文(简体) ),start(email), (中文(简体) ),verify(code), (中文(简体) ),sendSms(), (中文(简体) ),verifySecondFactor(method, code), (中文(简体) ),resend(), (中文(简体) ),restart()与step: "email" | "code" | "second_factor" | "signed_in", (中文(简体) ),busy,以及error作为数据(invalid_code {attemptsLeft}, (中文(简体) ),expired, (中文(简体) ),locked {retryAfter}, (中文(简体) ),too_many_requests {retryAfter}, (中文(简体) ),not_embedded, (中文(简体) ),invalid_request, (中文(简体) ),unavailable) (中文(简体) ). 你画出屏幕。 结束于存储的 SME 会话login()(授权代码在 /oauth2/token 上与 PKCE 验证器和您的第一个注册方向交换). 当Chrome关闭弹出时 当用户读取他们的邮件时 呼叫resume()然后他们又回到了代码阶下.expired财务报告和审定财务报表locked结束流量( 回转至)email(三);not_embedded表示不允许客户端——退到login()。扩展名中从未处理过密码。 尚未活出:BID在所有者批准其模型后会建立终点. - 密码登录(0.17.0,F099.25):
auth.embedded().passkeyStart()——面对BID的F084.166合同v2,没有邮件代码的外形标识/指纹. 国家去step: "passkey"与frameUrl: 显示<iframe src={frameUrl} allow="publickey-credentials-get">(~360x64) — BID的帧绘制出按钮,因为水龙头必须发生在它内部. 引擎会自己聆听帧的答案(只从发行商的出处,只从它的出处)flow_id,仅限type: "bid-embedded-passkey"),完成流量并交换与邮件代码完全一样的代码signed_in,同一届会议.cancelled使步骤没有出错(框的按钮再次准备好);not_found编号 :failed设定error: {kind: "passkey", reason}在台阶上,和start(email)仍然在那里工作(“Andre muligheder”下的邮件编码)。 A 类frame_urlbID的原产地被拒绝。 流出于封闭的弹出:resume()带回阶下再听. 过messages改为createBidAuth只有框架张贴 某处弹出自己的窗口.EmbeddedLoginForm不绘制此步骤, 您的屏幕会显示 . - 从数据(0.25.0,F099.22): 双子座读取器现在按照页面的方式加载对话——
POST /_/BardChatUi/data/batchexecute?rpcids=hNvQHb含有页本身的会话值(SNlM0e编号 :cfb2h编号 :FdrFJe——每转弯读取一个单位,最古老的第一. 答案是用主人的谈话(20/10)来衡量的;请求体没有被捕获,因此它跟随公开的f.req格式——如果Google拒绝,屏幕阅读器仍然会被剪辑,标记source:"dom"与缘由. 每通电话有100个转弯;填补它的对话名称可能更长.createGeminiReader({ fetch? })。 。 。 . - 从数据(0.24.0,F099.22): 深渊阅读器现在读到整个谈话
GET /api/v0/chat/history_messages?chat_session_id=<id>用DeepSeek自己的无记名符号(localStorage.userToken, (中文(简体) ),{value}JSON)——以业主谈话20/10测量出形状. 当前行从chat_session.current_message_id上楼parent_id树;其他的叶子(一个被编辑的问题,一个再生成的答案)作为分枝而来. 文本从REQUEST编号 :RESPONSE片段; 思维片段被忽略,任何其他片段类型都是完整的。 仅chat_session_id发送——页面的缓存参数使DeepSeek回答一个空列表。 没有签名或拒绝回答 = 屏幕阅读器,标记source:"dom"与缘由.createDeepSeekReader({ fetch?, token? })。 。 。 . - 数据中的复杂度(0.23.0,F099.22): 困惑读取器现在读取整个线程
GET /rest/thread/<slug>(该调用页面制作,形状测量在主人线19/10上):每转弯一个单位——问题来自query_str,从ask_text块的标记下——顺序,标题从线条;has_next_page名称完整。 查询参数值是我们的(样本只保留名称);如果模糊性拒绝,屏幕阅读器仍会被剪辑,标记source:"dom"与缘由.createPerplexityReader(o?)现在拿{ fetch }和其他数据阅读器一样. - 注解读取器(0.22.0,F099.22):
notebooklmReader编号 :createNotebookLMReader()内chatReaders—— 说notebook.google.com财务报告和审定财务报表notebooklm.google.com/notebook/<id>,读自《瑞典刑法》:chat-message是一个转弯(问题.from-user-container输入.to-user-container从结构块,倒塌的思维链和被忽略的动作按钮,引用标记为[n]笔记封面的标题 诚实complete:false:数据通过批量执行而来,还没有样本抓住页面要求的内容,笔记本的来源也不包括在内. - 深度阅读器(0.21.0,F099.22):
deepseekReader编号 :createDeepSeekReader()内chatReaders—聊天. depseek.com (中文(简体) )/a/chat/s/<id>,读自SCREEN(.ds-message; 答案.ds-markdown诚实complete:false, source:"dom", missing:"turns": DeepSeek只保留取景口附近的转弯,其数据调用需要拥有者样本没有携带的无记名标志,因此数据阅读器等待一个被测量的形状. - 页面夹中的背景图像(0.2.0,F099.27): 与
createArticleExtractor({ images: true }),将相片设定为 CSS 内置背景(style="background-image:url(…)"页面主要区域中的滑行者、英雄、牌网(main编号 :[role=main],则article,否则,身体减去头/导航/脚)现在也作为图像资产,通过相同的盖子,并列为在页面单元的 END 中(可读性从文本中去掉)。 渐变、 svg 、 隐藏元素和页眉/ 导航/ 脚被忽略; 一个 URL 已被使用<img>来一次 一个占位符src="data:,"一个<img>不再隐藏它srcset。只有内出行样式——样式表的背景不读取. 输出变化 : 有这种背景的页面现在携带更多的资产和额外资产线条. - Le Chat阅读器(0.19.0,F099.22):
lechatReader编号 :createLeChatReader()内chatReaders- 聊天. mistral.ai (英语)/chat/<id>财务报告和审定财务报表/work/<id>,从DATA读取(该页发送的同为tRPC批次:chat.byId,message.all,canva.all页:1content或文本块(工具调用被忽略), Le Chat 的画布作为制作它们的答案上的文件. 未猜测, 名称在completeness取而代之的是:经编辑的信件的旧版本(最新版本在线),又一页(nextCursor页:1 没有屏幕回落——样本只显示答案'容器. - Passkey (0.18.0, F099.26) 首发即时屏幕:
EmbeddedLoginForm这样ClipperPopup与embeddedLogin——现在在BID批准模拟 v2:BID的帧(BID的帧)后打开密码embedded-login-passkey-frame)),"安德烈·穆利赫德"(英语:embedded-login-other-options+ 带有 Log in med adgangsnøgle的邮件编码 (embedded-login-back-passkey) (中文(简体) ). 客户端 BID 不提供密码( 密码/ 启动拒绝: 403/ 404 或 年长的 BID 的 400 )error: {kind: "passkey", reason: "not_enabled"}从引擎和经典的邮件屏幕上——从不倒回窗口. 行为改变 页:1embeddedLogin弹出:第一个屏幕是密码. 上面的 README 线约EmbeddedLoginForm不绘制密码步骤被取代 . - 嵌入式登录屏幕(0.16.0,F099.24):
EmbeddedLoginForm财务报告和审定财务报表CodeInput内/ui绘图auth.embedded()在BID的模拟01a1409a——邮件——6-box代码(Paste或一次性代码自动填入第一个框填充全部6个)——第二个系数——签入后,加上“Vent lidt”(锁入/太多,有BID的分数)和“Ingen forbindelse”(加上“Prøv igen”)。 每个控制器都带有embedded-login-*data-testid(模拟器自己的).ClipperPopup通过时在 INSID 中记录弹出embeddedLogin(0.16.1:选入——0.16.0在BID为终点服务之前自行打开;跳过0.16.0;如果BID回答not_embedded或404 它自己掉回了旧窗口按钮。 一个绘制引擎的方法——如果你的弹出看起来不同,就自己画. 实例/网络剪辑器上的镜头验证?state=embedded(页面合同-v1 BID). - YouTube视频(Jam F002.35):
youtubeReader(从)/extract——在取出文章前列出. 打开youtube.com/watch, (中文(简体) ),youtu.be/<id>, (中文(简体) ),/shorts/<id>财务报告和审定财务报表/live/<id>(另见:m.财务报告和审定财务报表music.片段是一类"video"与unit.video = { provider: "youtube", videoId, url, title, channel?, start?, thumbnailUrl, format? }。视频id来自URL,从不来自页面:在网页导航YouTube之后<meta>标记仍然可以描述之前的视频,所以它们只有在给这段视频取名id时才被使用.start整个秒从t=编号 :start=(单位:千美元)83, (中文(简体) ),83s, (中文(简体) ),1m23s, (中文(简体) ),1h2m3s),且不在单位内容中,因此在另一个时刻被剪辑的同名视频是"同",而不是分行.thumbnailUrl实值i.ytimg.com/vi/<id>/hqdefault.jpg,从身份证上建立起来的——什么也没有拿来. YouTube主页,频道和搜索仍然去到文章摘录. - 网页图像(0.11.0,F099.23):
createArticleExtractor({ images: true, maxImages, maxImageBytes, maxImageFileBytes?, minImageSize? })从/extract- 把它放在提取器列表中(它与每一页都匹配). 页面单位得到assets对于文章的内容图像({ type: "image", url, alt, name, mime, size, width?, height?, encoding: "base64", content }; svg 以文本的形式出现,在页面中以自己的会话获取,所以登录后的图像也会来.url确切的地址 在减记——在您存储的文件中标注该引用 。 离开 :role=presentation, (中文(简体) ),aria-hidden, svg 图标(#fragment),且其大小(取自标记或取自其PNG/GIF/JPEG/WebP标题)在下方的任何图像minImageSize(64个px). 盖子是需要通过(所有者15/10:每Jam org;未设定为每段50个图像/100 MB). 盖上的图像或无法获取的图像在completeness.missingFiles(单位:千美元)clip_limit编号 :too_large编号 :http编号 :network),与complete: false, missing: "files"——文字完整.articleExtractor本身没有变化(只有文本). - 每个分支(0.0.0,F099.21): 对话是一棵树(经编辑的提示,“再次”).
clip.units仍然是屏幕上的线程;clip.branches?: Unit[][]保持每条其它行 从根到叶的整条线 都有自己的0.n-1位置 与主线共用的拉伸是相同的单位,因此它印出相同的和对话的行叉. 当没有树枝的时候(弹出可以说"148ture" ^ 2 sidegrene",来自clip.branches.length) (中文(简体) ).sendClip将主线 First 和以前一样发送到appendOnly目的地——每条边线作为One发送其WALE路径ctx.side = { index, of, from }(单位:千美元)from=该批次的首发位置;一长行仍分批进行. 将它与你持有的东西相对应:共享的长度,新的单位挂在您共享的最后一个链接上. 您已完整持有的一行边线被跳过; 执行可选heldKeys(anchor, target, session)(你为锚所持的每条链子——整棵树) 所以一个回扣知道,或者每个侧线 被怨恨每个片段(无害,键入,但数入)sent) (中文(简体) ). 一个不是附件的目的地 只有主线发送一个, 分支打开ctx.clip.branches。在多行显示的文件会被取出一次;一个克洛德文物的版本跟随自己的行. - 大文件流直接到您的存储( 0. 9. 0, F099. 20) : 设定
streamOverBytes在读取器上(Jam: 25 MB). 上面的文件不放入剪辑中;它以{ type: "file", name, mime, size, transfer: "stream", streamRef }。然后,在扩展中:获得partsNeeded(asset.size, partSize)您服务器上预先签名的部分地址( E)@broberg/media0.6.0 (中文(简体) )multipart.create+ 键presignPart),电话streamAsset(asset, { partUrls, partSize })从/extension页面用自己的会话读取文件, PUT 将它部分地( 一次在内存中的一部分) —— 在您的服务器上完成multipart.complete(etags)(或abort如果它扔了的话。 5个小米B,但最后一个除外。 水桶的CORS必须允许PUT从 https://claude.ai (英语) 财务报告和审定财务报表 https://chatgpt.com (中文(中国大陆) ) 并揭露ETag; 没有可见的 ETag 的部件失败了, 信件会这么说 . - 1高(0.6.2): 弹出在每一个州都保持同样的高度(日志为 + 剪辑 → 剪辑 → 结果). 设置在您的扩展 CSS:
.bwc-popup { --bwc-popup-height: 480px }(默认为 420px). - 从不沉默(0.5.0): 一个不完整的剪辑显示
clipper-incomplete原因; 在未显示对话的页面上获得同意的目的地clipper-not-a-conversation说多少个单位去了.ClipperPopup({ text: { noTargets: "…" } })替换弹出式文本. - 弹出 (序言,
@broberg/theme标记, 无本地控件 : 登录, 选择目标( 海关列表框, 键盘包含, 每个目的地记住) , 剪辑, 以及一个状态线, 分别告诉“ log ind igen” , “ kunne ikke nå frem” 和“ afvist” 。 每个互动要素都有:clipper-*数据测试. examples/web-clipper是一个完整的扩展( e)pnpm --filter web-clipper-example build→dist/,装入已卸出)加上同样的弹出作为Lens的一页(preview, : 5200) (中文(简体) ).
接下来是第一次发布(F099.7),然后是Trail的剪辑机和上面的Jam原型.