-
Notifications
You must be signed in to change notification settings - Fork 106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
关于youtube的广告拦截问题 #74
Comments
以下是大模型重写后的js脚本,但是本项目目前对js对支持还非常初级,还需要改进后才能用 (() => {
const youtube = D.getInstance("YouTube");
class YouTubeHandler {
constructor(messageType, handlerName) {
this.handlerName = handlerName;
this.messageType = messageType;
this.arguments = this.decodeArguments();
youtube.isDebug = Boolean(this.arguments.debug);
youtube.debug(this.handlerName);
const config = youtube.getJSON("YouTubeAdvertiseInfo");
youtube.debug(`currentVersion: ${this.version}`);
youtube.debug(`storedVersion: ${config?.version}`);
if (config?.version === this.version) Object.assign(this, config);
}
decodeArguments() {
const defaultArgs = {
lyricLang: "zh-Hans",
captionLang: "zh-Hans",
blockUpload: true,
blockImmersive: true,
debug: false
};
return youtube.decodeParams(defaultArgs);
}
fromBinary(data) {
if (data instanceof Uint8Array) {
this.message = this.messageType.fromBinary(data);
youtube.debug(`raw: ${Math.floor(data.length / 1024)} kb`);
return this;
} else {
youtube.log("YouTube cannot get binaryBody");
youtube.exit();
return this;
}
}
async modify() {
const result = this.pure();
return result instanceof Promise ? await result : result;
}
toBinary() {
return this.message.toBinary();
}
listUnknownFields(message) {
return message instanceof E ? message.getType().runtime.bin.listUnknownFields(message) : [];
}
saveConfig() {
if (this.needSave) {
youtube.debug("Update Config");
const config = {
version: this.version,
whiteNo: this.whiteNo,
blackNo: this.blackNo,
whiteEml: this.whiteEml,
blackEml: this.blackEml
};
youtube.debug(config);
youtube.setJSON(config, "YouTubeAdvertiseInfo");
}
}
finish() {
this.saveConfig();
if (this.needProcess) {
youtube.timeStart("toBinary");
const binaryData = this.toBinary();
youtube.timeEnd("toBinary");
youtube.debug(`modify: ${Math.floor(binaryData.length / 1024)} kb`);
youtube.done({ bodyBytes: binaryData });
}
youtube.debug("use $done({})");
youtube.exit();
}
iterateObject(obj, targetKey, callback) {
const stack = typeof obj === "object" ? [obj] : [];
while (stack.length) {
const current = stack.pop();
const keys = Object.keys(current);
for (const key of keys) {
if (key === targetKey) {
callback(current, stack);
} else if (typeof current[key] === "object") {
stack.push(current[key]);
}
}
}
}
isAdvertise(message) {
const field = this.listUnknownFields(message)[0];
return field ? this.handleFieldNumber(field) : this.handleFieldEml(message);
}
handleFieldNumber(field) {
const fieldNumber = field.no;
if (this.whiteNo.includes(fieldNumber)) return false;
if (this.blackNo.includes(fieldNumber)) return true;
const isAd = this.checkBufferForAd(field);
if (isAd) this.blackNo.push(fieldNumber);
else this.whiteNo.push(fieldNumber);
this.needSave = true;
return isAd;
}
handleFieldEml(message) {
let isAd = false;
let eml = "";
this.iterateObject(message, "renderInfo", (obj, stack) => {
eml = obj.renderInfo.layoutRender.eml.split("|")[0];
if (this.whiteEml.includes(eml)) isAd = false;
else if (this.blackEml.includes(eml) || /shorts(?!_pivot_item)/.test(eml)) isAd = true;
else {
const videoContent = obj?.videoInfo?.videoContext?.videoContent;
if (videoContent) {
isAd = this.checkUnknownField(videoContent);
if (isAd) this.blackEml.push(eml);
else this.whiteEml.push(eml);
this.needSave = true;
}
}
stack.length = 0;
});
return isAd;
}
checkBufferForAd(field) {
return !field || field.data.length < 1000 ? false : this.decoder.decode(field.data).includes("pagead");
}
checkUnknownField(message) {
return message ? this.listUnknownFields(message)?.some(field => this.checkBufferForAd(field)) ?? false : false;
}
isShorts(message) {
let isShorts = false;
this.iterateObject(message, "eml", (obj, stack) => {
isShorts = /shorts(?!_pivot_item)/.test(obj.eml);
stack.length = 0;
});
return isShorts;
}
}
class BrowseHandler extends YouTubeHandler {
constructor(messageType = Mt, handlerName = "Browse") {
super(messageType, handlerName);
}
async pure() {
this.iterateObject(this.message, "sectionListSupportedRenderers", section => {
for (let i = section.sectionListSupportedRenderers.length - 1; i >= 0; i--) {
this.removeCommonAd(section, i);
this.removeShorts(section, i);
}
});
await this.translate();
return this;
}
removeCommonAd(section, index) {
const items = section.sectionListSupportedRenderers[index]?.itemSectionRenderer?.richItemContent;
for (let i = items?.length - 1; i >= 0; i--) {
if (this.isAdvertise(items[i])) {
items.splice(i, 1);
this.needProcess = true;
}
}
}
removeShorts(section, index) {
const shelf = section.sectionListSupportedRenderers[index]?.shelfRenderer;
if (this.isShorts(shelf)) {
section.sectionListSupportedRenderers.splice(index, 1);
this.needProcess = true;
}
}
getBrowseId() {
let browseId = "";
this.iterateObject(this.message?.responseContext, "key", (obj, stack) => {
if (obj.key === "browse_id") {
browseId = obj.value;
stack.length = 0;
}
});
return browseId;
}
async translate() {
const lang = this.arguments.lyricLang?.trim();
if (!(this.handlerName === "Browse" && this.getBrowseId().startsWith("MPLYt")) || lang === "off") return;
let text = "";
let target;
let hasContent = false;
this.iterateObject(this.message, "timedLyricsContent", (obj, stack) => {
target = obj.timedLyricsContent;
text = obj.timedLyricsContent.runs.map(run => run.text).join("\n");
hasContent = true;
stack.length = 0;
});
if (!hasContent) {
this.iterateObject(this.message, "description", (obj, stack) => {
target = obj.description.runs[0];
text = obj.description.runs[0].text;
stack.length = 0;
hasContent = true;
});
}
if (!hasContent) return;
const langCode = lang.split("-")[0];
const url = Yt(text, lang);
const response = await youtube.fetch({ method: "GET", url });
if (response.status === 200 && response.body) {
const data = JSON.parse(response.body);
const translatedText = data[0].map(line => line[0]).join("\r\n");
target.text = translatedText;
this.iterateObject(this.message, "footer", (obj, stack) => {
obj.footer.runs[0].text += " & Translated by Google";
stack.length = 0;
});
this.needProcess = true;
}
}
}
const handlerMap = new Map([
["browse", BrowseHandler]
]);
function getHandler(url) {
for (const [key, HandlerClass] of handlerMap.entries()) {
if (url.includes(key)) return new HandlerClass();
}
return null;
}
async function main() {
const handler = getHandler(youtube.request.url);
if (handler) {
const data = youtube.response.bodyBytes;
youtube.timeStart("fromBinary");
handler.fromBinary(data);
youtube.timeEnd("fromBinary");
youtube.timeStart("modify");
await handler.modify();
youtube.timeEnd("modify");
handler.finish();
} else {
youtube.msg("YouTube Enhance", "脚本需要更新", "外部资源 -> 全部更新");
youtube.exit();
}
}
main().catch(err => {
youtube.log(err.toString());
}).finally(() => {
youtube.exit();
});
})(); |
感谢您的回复,希望后续有所更新,新年快乐 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
尊敬的开发者您好
我将statsh的复写设置打算放入服务器上的mitm中,规则如下
拦截工作可以进行,但是画中画(后台播放)没法实现
我参考了文档,没有发现可以插入js的效果,是否可以考虑增加实现?
谢谢,以上
The text was updated successfully, but these errors were encountered: