Skip to content

Conversation

cyfung1031
Copy link
Contributor

@cyfung1031 cyfung1031 commented Oct 10, 2025

概述

有时候, GreasyFork的脚本名字因为更改了,如果我用链结去安装,因为它的名字对不上,以为是新安装
GreasyFork的腳本有 @updateURL 可以检查是不是同一个脚本

变更内容

截图

@cyfung1031 cyfung1031 changed the title findByUpdateURL (小改动)防止脚本安装链结因脚本名字改了而被误判为安装而非更新 Oct 10, 2025
return { subscribe, oldSubscribe: old };
}

const findByUpdateURL = async (dao: ScriptDAO, name: string, namespace: string, checkUrl: string) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

为什么总是使用const而不是function呢?
这种操作数据的方法应该放在ScriptDAO中

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

添加一个简单的单测吧

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个写法即使压缩后也比较短吧。里面又没有用 this.
也明确地指明这是 ESM模组 写法,不会有this
打包不会出现一样结果。因为 function 可以 new, 箭头不是 Function Class 不能 new . 打包工具不会帮你互换。压缩后长度会较长
export function 是老写法吧。ESM应该配合 箭头写法
当然你不喜欢也是可以用老写法的

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这种操作数据的方法应该放在ScriptDAO中

我不想 scripts.ts 引入 fetchScriptBody 和 parseMetadata
會影響 tree shaking

old = await dao.findByNameAndNamespace(script.name, script.namespace);
}
const checkUrl = script.checkUpdateUrl || script.downloadUrl;
if (!old && checkUrl && script.name && script.namespace) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

script.name && script.namespace 肯定存在

if (!old && (!uuid || override)) {
old = await dao.findByNameAndNamespace(script.name, script.namespace);
}
const checkUrl = script.checkUpdateUrl || script.downloadUrl;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

用checkUpdateUrl即可,checkUpdateUrl肯定存在

return false;
});
const ret = ret_ as Script | null;
const retCheckUrl = ret?.checkUpdateUrl || ret?.downloadUrl;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checkUpdateUrl 优先于 downloadUrl 肯定存在

Comment on lines 156 to 164
// 根据 checkUpdateUrl 网址对比找出最有可能的脚本
// GreasyFork 的话,脚本名字改变了后,path也会改变,但ID不变
for (let l = Math.min(search.length, current.length); c < l; c++) {
if (current[c] !== search[c]) break;
}
if (c > count) {
count = c;
ret = value;
}
Copy link
Member

@CodFrm CodFrm Oct 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个处理逻辑感觉不是很合适,哪怕针对性的处理呢

例如,我安装了一个盗版脚本,同名不同id,也会判定到(因为最后一截name对应上了),也会因为前面一截 update.greasyfork.org/scripts 判定成功,那么几乎每一个脚本都会识别到,然后去走 fetchScriptBody、parseMetadata 的逻辑

Copy link
Contributor Author

@cyfung1031 cyfung1031 Oct 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

greasyfork 脚本有加入 @downloadURL. 可以用这个对比是不是现在的安装连结
要檢查完整 xxx.user.js 而不是 xxx.user.js

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个逻辑几乎必定会返回一个ret,他们的前缀都是:
https://update.greasyfork.org/scripts/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  if (!old && (!uuid || override)) {
    old = await dao.findByNameAndNamespace(script.name, script.namespace);
  }

盗版脚本问题,这个也一样吧。只要是同名同namespace 就视作一样

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个逻辑几乎必定会返回一个ret,他们的前缀都是: https://update.greasyfork.org/scripts/

scripts后有id
只不过代码没写得那么死

Copy link
Member

@CodFrm CodFrm Oct 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我的想法是,直接按照一定的规则处理,例如是greasyfork的话,就直接按照greasyfork的规则去解析,然后判断id是否相等,可以做一个配置列表,匹配出唯一键,例如:greasyfork/scriptcat的就是id,github就是仓库名/路径之类

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我又补充了一个单元测试,连https前缀一样,也都会匹配一个脚本出来,这不合理吧

它只是找一个合理的脚本,还要查 name 和 namespace
原理就是跟 old = await dao.findByNameAndNamespace(script.name, script.namespace); 一样呀

我的想法是,直接按照一定的规则处理,例如是greasyfork的话,就直接按照greasyfork的规则去解析,然后判断id是否相等,可以做一个配置列表,匹配出唯一键,例如:greasyfork/scriptcat的就是id,github就是仓库名/路径之类

有必要这么搞吗?
我不明白用这个方法才到 old = await dao.findByNameAndNamespace(script.name, script.namespace); 相同的有何问题

Copy link
Member

@CodFrm CodFrm Oct 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

但是这里是匹配到了一次后,又要重新使用fetchScriptBody去下载一次脚本,进行对比,多了一些网络请求

findByNameAndNamespace是只找已经安装好了的脚本,且更新逻辑才会使用findByNameAndNamespace,区别还是挺大的

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QQ_1760291147350

主要是我认为这个匹配范围太广了,大部分情况,根本匹配不到正确的脚本,然后多一次网络请求

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我的想法是,直接按照一定的规则处理,例如是greasyfork的话,就直接按照greasyfork的规则去解析,然后判断id是否相等,可以做一个配置列表,匹配出唯一键,例如:greasyfork/scriptcat的就是id,github就是仓库名/路径之类

我考虑看看

Comment on lines 168 to 176
const code = await fetchScriptBody(retCheckUrl);
const metadata = code ? parseMetadata(code) : null;
if (metadata && metadata.name![0] === script.name && (metadata.namespace?.[0] || "") === script.namespace) {
old = ret;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const code = await fetchScriptBody(retCheckUrl);
const metadata = code ? parseMetadata(code) : null;
if (metadata && metadata.name![0] === script.name && (metadata.namespace?.[0] || "") === script.namespace) {
old = ret;
}
const codeTest = await fetchScriptBody(retCheckUrl);
const metadataTest = codeTest ? parseMetadata(codeTest) : null;
if (
metadataTest &&
metadataTest.name![0] === script.name &&
(metadataTest.namespace?.[0] || "") === script.namespace
) {
const metadataTestMeta = { ...metadataTest, updateurl: undefined, downloadurl: undefined }; // meta.js 沒 @updateURL 和 @downloadURL
const metadataInstallMeta = { ...metadata, updateurl: undefined, downloadurl: undefined }; // user.js -> meta.js
if (JSON.stringify(metadataInstallMeta) === JSON.stringify(metadataTestMeta)) {
old = ret;
}
}

Copy link
Member

@CodFrm CodFrm Oct 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如果有更新的话,metadata变动的几率还是挺大的,按照name+namespace来判定即可

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这是从旧脚本的checkurl 找checkurl最新版的meta
它会跟要安装的user.js 的 meta 一模一样

Copy link
Member

@CodFrm CodFrm Oct 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我大概明白你意思了,旧脚本的checkurl读取到的信息应该也会是最新的,也可以,严格点也好

@cyfung1031 cyfung1031 force-pushed the pr-install-script-with-matched-urll branch from 7f9e055 to 458ab0b Compare October 12, 2025 18:01
@cyfung1031 cyfung1031 marked this pull request as draft October 13, 2025 01:25
@cyfung1031 cyfung1031 marked this pull request as ready for review October 14, 2025 23:25
@cyfung1031 cyfung1031 force-pushed the pr-install-script-with-matched-urll branch 2 times, most recently from d249644 to d35db53 Compare October 15, 2025 13:19
@cyfung1031 cyfung1031 force-pushed the pr-install-script-with-matched-urll branch from d35db53 to 9c122ab Compare October 18, 2025 04:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants