LifeActor / ykdl

a video downloader focus on China mainland video sites.(一款专注于中国大陆视频网站的视频下载器。)
https://github.com/LifeActor/ykdl
Other
1.44k stars 285 forks source link

jsengine.py 无法和 node 在一起工作 #376

Closed wwqgtxx closed 5 years ago

wwqgtxx commented 5 years ago

jsengine.pyinjected_script中使用了print,但是该内置函数在node中为未定义

wwqgtxx commented 5 years ago

试了一下,用console.log可能兼容性更好吧

coslyk commented 5 years ago

但是JavaScriptCore就没有console.log看来还是要根据不同的解析器注入不同代码

SeaHOH commented 5 years ago

反正都要分别注入,那么顺便恢复 _exec_with_pipe ?

wwqgtxx commented 5 years ago

接着 #378 的问题,就算把print改掉,依然会报Error: Cannot find module './core'的错,应该是return eval("{code}"); })()");这个转换的问题,我试过把crypto-js-md5.min.js中的内容一行一行的让node运行就没毛病

SeaHOH commented 5 years ago

改了下 crypto-js-md5.min.js,原来是由两个文件直接拼接的,现在去除了 require。 @wwqgtxx 这样能正常运行了吧。

wwqgtxx commented 5 years ago

还是有别的问题TypeError: Cannot read property 'lib' of undefined 另外我觉得这种方法还是治标不治本

wwqgtxx commented 5 years ago

办法倒是找到了,需要在injected_script中再插入一句exports = undefined;,应该是要关闭node的模块化才能解决这个问题

Justsoos commented 5 years ago

@SeaHOH @coslyk 你们用的什么环境?看你改的欢天喜地的都没报错… 我用nodejs报错情况与 @wwqgtxx 一致。

coslyk commented 5 years ago

@SeaHOH @coslyk 你们用的什么环境?看你改的欢天喜地的都没报错… 我用nodejs报错情况与 @wwqgtxx 一致。

我的环境是LinuxMint 19.1,NodeJS v18.10.0,测试一切正常,无法复现你们的问题,有点诡异-_- Win10自带的Chakra,MacOS自带的JavascriptCore和Gnome自带的gjs都可以正常跑

coslyk commented 5 years ago

办法倒是找到了,需要在injected_script中再插入一句exports = undefined;,应该是要关闭node的模块化才能解决这个问题

直接加在injected_script的头部?

coslyk commented 5 years ago

不过我用Python2跑ykdl,就出现编码问题, @SeaHOH 还是要再处理下~

Traceback (most recent call last):
  File "/usr/lib/python2.7/runpy.py", line 174, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "/usr/lib/python2.7/runpy.py", line 72, in _run_code
    exec code in run_globals
  File "/media/liuyikun/SHARE/Develop/ykdl/cykdl/__main__.py", line 195, in <module>
    main()
  File "/media/liuyikun/SHARE/Develop/ykdl/cykdl/__main__.py", line 173, in main
    info = parser(u)
  File "ykdl/extractor.py", line 24, in parser
    info = self.prepare()
  File "ykdl/extractors/douyu/live.py", line 56, in prepare
    info.title = '{} - {}'.format(title, artist)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-7: ordinal not in range(128)
SeaHOH commented 5 years ago

使用了 require.js 提供的模块功能,禁用它才能正常运行,具体原因不懂。 很多模块开头都会这样写:

(function (root, factory) {
    if (typeof exports === "object") {
        // CommonJS
        module.exports = exports = factory();
    }
    else if (typeof define === "function" && define.amd) {
        // AMD
        define([], factory);
    }
    else {
        // Global (browser)
        root.modulename = factory();
    }
}(this, function () {
    code...
})
wwqgtxx commented 5 years ago

实际上是因为node.js的require是基于文件路径的,在你调用require("./core")的时候他就在你的同层目录下找core.js或者core/index.js,而实际上这个文件并不存在,所以就报错了。而如果把exports给注释掉,就会把core的内容释放到globals中,后面在调用的时候也不会去require而是直接去globals中找,这样就能正常工作了

coslyk commented 5 years ago

实际上是因为node.js的require是基于文件路径的,在你调用require("./core")的时候他就在你的同层目录下找core.js或者core/index.js,而实际上这个文件并不存在,所以就报错了。而如果把exports给注释掉,就会把core的内容释放到globals中,后面在调用的时候也不会去require而是直接去globals中找,这样就能正常工作了

懂了,我发现我nodejs能跑是因为我没有安装完整的Node环境,所以没有模块功能,试着用nodejs跑了下typeof exports返回的也是undefined

coslyk commented 5 years ago

这样改可不可以? https://github.com/zhangn1985/ykdl/pull/380/commits/6202da9299065200383703a2515b098fa29b8544

wwqgtxx commented 5 years ago

@SeaHOH @coslyk 你们用的什么环境?看你改的欢天喜地的都没报错… 我用nodejs报错情况与 @wwqgtxx 一致。

我的环境是LinuxMint 19.1,NodeJS v18.10.0,测试一切正常,无法复现你们的问题,有点诡异-_- Win10自带的Chakra,MacOS自带的JavascriptCore和Gnome自带的gjs都可以正常跑

突然问个问题,nodejs现在的最新版本也才到11.10.1,你的版本是怎么到18.10.0的表示很好奇

coslyk commented 5 years ago

@SeaHOH @coslyk 你们用的什么环境?看你改的欢天喜地的都没报错… 我用nodejs报错情况与 @wwqgtxx 一致。

我的环境是LinuxMint 19.1,NodeJS v18.10.0,测试一切正常,无法复现你们的问题,有点诡异-_- Win10自带的Chakra,MacOS自带的JavascriptCore和Gnome自带的gjs都可以正常跑

突然问个问题,nodejs现在的最新版本也才到11.10.1,你的版本是怎么到18.10.0的表示很好奇

8.10.0 手残了~

wwqgtxx commented 5 years ago

这样改可不可以? 6202da9

试了一下,现在应该是正常了

wwqgtxx commented 5 years ago

实际上是因为node.js的require是基于文件路径的,在你调用require("./core")的时候他就在你的同层目录下找core.js或者core/index.js,而实际上这个文件并不存在,所以就报错了。而如果把exports给注释掉,就会把core的内容释放到globals中,后面在调用的时候也不会去require而是直接去globals中找,这样就能正常工作了

懂了,我发现我nodejs能跑是因为我没有安装完整的Node环境,所以没有模块功能,试着用nodejs跑了下typeof exports返回的也是undefined

这里其实你直接用node的rhel跑typeof exports的确应该是undefined,那是因为这个是运行在一个VM中的https://nodejs.org/api/repl.html,但是jsengine.py中是把东西输出到一个临时文件的,这时候exports就不是未定义了

SeaHOH commented 5 years ago

又看了下,require.js 需要浏览器环境。

/*jslint regexp: true, nomen: true, sloppy: true */
/*global window, navigator, document, importScripts, setTimeout, opera */
wwqgtxx commented 5 years ago

又看了下,require.js 需要浏览器环境。

/*jslint regexp: true, nomen: true, sloppy: true */
/*global window, navigator, document, importScripts, setTimeout, opera */

node的require是个内置对象,并不是用require.js实现的

SeaHOH commented 5 years ago

我用 ChakraCore 运行 require.js 也是失败的,没法成功加载。 总之大家都用不了。。。

wwqgtxx commented 5 years ago

我用 ChakraCore 运行 require.js 也是失败的,没法成功加载。 总之大家都用不了。。。

反正在JavaScript的世界中require()并不是只有require.js实现了,我记得webpack也实现了自己的requirenode自己也有一份实现,这只不过是CommonJs规范罢了,而require.js是一种遵循了CMD规范CommonJs规范模块加载器,且只能在浏览器中用。(没错,JS的世界就是这么蛋疼,然而最后还有ES6 Module规范这个官方标准。。。)

Justsoos commented 5 years ago

@coslyk 你这样改过,反而又不能用了,我在安卓termux,node v11.10.0。 只能这样写:

injected_script = r'''
  var exports = undefined;
(function(program, execJS) { execJS(program) })(
function() {
    return eval(#{encoded_source});
},
function(program) {
  var output;
  try {
    result = program();
    var print = (this.print === undefined) ? (function(msg){console.log(msg);}) : this.print;
    print("");
    if (typeof result == 'undefined' && result !== null) {
    print('["ok"]');

这个适配看来要做很多

coslyk commented 5 years ago

@Justsoos 已改,感谢你的帮助。

JS真的好蛋疼啊 : (

wwqgtxx commented 5 years ago

@coslyk 话说你改在哪个分支上了,我在master上没看到你的commit呀

coslyk commented 5 years ago

@wwqgtxx 在PR里面:https://github.com/zhangn1985/ykdl/pull/380 没问题了再合并

SeaHOH commented 5 years ago

还可以继续精简,把 execJS(program) 去掉,直接 result = eval(#{encoded_source});。 JS 真的蛋疼,来来回回的绕。。。

coslyk commented 5 years ago

还可以继续精简,把 execJS(program) 去掉,直接 result = eval(#{encoded_source});。 JS 真的蛋疼,来来回回的绕。。。

这种写法还是有理由的,主要是为了隔离,避免function(program){...}中定义的局部变量干扰eval(...)的部分

wwqgtxx commented 5 years ago

所以我自己用了一种比较简单的办法处理这个问题 https://github.com/wwqgtxx/ykdl/commit/f9e75a8b8f20fd73b48afad9d8301f7831ab466c 当然这么做的缺点就是会引入外部依赖

SeaHOH commented 5 years ago

其实我前天就直接改了 js 文件。 55c2cc43b718fb12fdd8447662ba9f2ffa38db91

wwqgtxx commented 5 years ago

@SaeHOH 问题是斗鱼返回的js代码js_enc中还有用到了require的地方,所以依然会出错

SeaHOH commented 5 years ago

@SaeHOH 问题是斗鱼返回的js代码js_enc中还有用到了require的地方,所以依然会出错

没有发现,具体那个流程会用到? ub98484234 的解码流程中没有用到吧。

wwqgtxx commented 5 years ago

ub9848234中肯定要加载以前定义的modules呀,所以要先require要不然再去globals中找

SeaHOH commented 5 years ago

并没有,我早就看过了,解码后也没有。

wwqgtxx commented 5 years ago

我之前试过一次横竖是会出错的,然而并没有注意看到底是哪一行代码的错

SeaHOH commented 5 years ago

ub98484234 ua92b39430e99976

function sf(xx0, xx1, xx2) {
    var cb = xx0 + xx1 + xx2 + "220120190303";
    var rb = CryptoJS.MD5(cb).toString();
    var re = [];
    for (var i = 0; i < rb.length / 8; i++) re[i] = (parseInt(rb.substr(i * 8, 2), 16) & 0xff) | ((parseInt(rb.substr(i * 8 + 2, 2), 16) << 8) & 0xff00) | ((parseInt(rb.substr(i * 8 + 4, 2), 16) << 24) >>> 8) | (parseInt(rb.substr(i * 8 + 6, 2), 16) << 24);
    var k2 = [0x531014d9, 0x57c57f32, 0x5e4e00, 0x32357a4c];
    for (var I = 0; I < 2; I++) {
        var v0 = re[I * 2],
            v1 = re[I * 2 + 1],
            sum = 0,
            i = 0;
        var delta = 0x9e3779b9;
        for (i = 0; i < 32; i++) {
            sum += delta;
            v0 += ((v1 << 4) + k2[0]) ^ (v1 + sum) ^ ((v1 >>> 5) + k2[1]);
            v1 += ((v0 << 4) + k2[2]) ^ (v0 + sum) ^ ((v0 >>> 5) + k2[3]);
        }
        re[I * 2] = v0;
        re[I * 2 + 1] = v1;
    }
    re[0] = (re[0] >>> (k2[0] % 16)) | (re[0] << (32 - (k2[0] % 16)));
    re[0] ^= k2[2];
    re[0] ^= k2[0];
    re[0] = (re[0] >>> (k2[2] % 16)) | (re[0] << (32 - (k2[2] % 16)));
    re[0] -= k2[2];
    re[1] ^= k2[1];
    re[1] = (re[1] >>> (k2[3] % 16)) | (re[1] << (32 - (k2[3] % 16)));
    re[1] ^= k2[3];
    re[1] = (re[1] << (k2[3] % 16)) | (re[1] >>> (32 - (k2[3] % 16)));
    re[2] = (re[2] << (k2[0] % 16)) | (re[2] >>> (32 - (k2[0] % 16)));
    re[2] += k2[2];
    re[2] ^= k2[2];
    re[3] = (re[3] << (k2[1] % 16)) | (re[3] >>> (32 - (k2[1] % 16)));
    re[3] = (re[3] << (k2[3] % 16)) | (re[3] >>> (32 - (k2[3] % 16)));
    re[3] = (re[3] << (k2[3] % 16)) | (re[3] >>> (32 - (k2[3] % 16)));
    re[3] += k2[3];
    re[0] ^= k2[0];
    re[0] += k2[2];
    re[0] ^= k2[2];
    re[0] ^= k2[2];
    re[1] ^= k2[1];
    re[1] += k2[3];
    re[1] ^= k2[3];
    re[1] = (re[1] << (k2[3] % 16)) | (re[1] >>> (32 - (k2[3] % 16)));
    re[2] += k2[0];
    re[2] += k2[2];
    re[2] += k2[2];
    re[3] = (re[3] >>> (k2[1] % 16)) | (re[3] << (32 - (k2[1] % 16)));
    re[3] += k2[3];
    re[3] += k2[1];
    re[3] = (re[3] << (k2[3] % 16)) | (re[3] >>> (32 - (k2[3] % 16)));
    {
        var hc = '0123456789abcdef'.split('');
        for (var i = 0; i < re.length; i++) {
            var j = 0,
            s = '';
            for (; j < 4; j++) s += hc[(re[i] >> (j * 8 + 4)) & 15] + hc[(re[i] >> (j * 8)) & 15];
            re[i] = s;
        }
        re = re.join('');
    }
    var rt="v=220120190303"+"&did="+xx1+"&tt="+xx2+"&sign="+re;
    return rt;
}
SeaHOH commented 5 years ago

这么久没问题,关掉。