ZhangMingZhao1 / StreamerHelper

全平台主播录制+投稿 工具/服务
MIT License
1.13k stars 175 forks source link

我基于这个repo写了抖音的支持脚本,但有点问题,希望能帮助debug #152

Closed Laeglaur closed 4 months ago

Laeglaur commented 2 years ago

Hi Zhang,

我写了抖音的支持脚本,检测是否开播/找到推流地址/调用ffmpeg单独的模块都已调通,但联动起来有一些问题。。因为我没学过node.js,也不是学计算机专业的,自己有点debug不出来,希望您能帮忙看看,这样就能支持抖音平台了。

具体来说, 输入:用户主页网址 e.g. https://www.douyin.com/user/MS4wLjABAAAAQ9Hv1tjh0pIyMmqNkngMINaMF64NnUrNuWKmHp14Uqbeb1ZeGrh7uJjqeKEBM30O

检测是否开播 不知道为什么用axios不行,,所以我换成superagent了,这个实现方式是稳定的。开播后用户主页的#root > div > div.T_foQflM > div > div > div.XM26psoY > div._1mISMfK2 > div.VmWWPdeA > div._DXoni4w > a 会出现live url。未开播时则没有a子类。

superagent.get(url)
  .end((err: any, res: { text: any; }) => {
   if(err) {
      reject(err);
    }
    // cherrio模块获取页面内容
    let $ = cheerio.load(res.text);
    $("#root > div > div.T_foQflM > div > div > div.XM26psoY > div._1mISMfK2 > div.VmWWPdeA > div._DXoni4w > a").each(async (_idx: any, elem: any) => {
        const liveurl: string = $(elem).attr("href");  
        console.log(liveurl);

找到推流地址 现在抖音换成flv推流了,不再是常见的m3u8。然后好像是动态页面?用常规的axios/superagent/request等都读不到有效数据,最后用puppeteer可以读到。它的推流地址藏在#RENDER_DATA里,我写了简单正则,可以找到对应stream id。 这里应该是主要需要debug的地方,我单独运行下面代码可以稳定找到地址,但放在repo里它总是失败,调节了等待时长也无果,不知道为什么。

const puppeteer = require('puppeteer')

const getUrl = async (item) => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.setRequestInterception(true)

    await page.goto(item);

    const result = page.$$eval('#RENDER_DATA', el=>{
        try {
            //console.log(el)
            for (let i = 0; i < el.length; i++) {
                let n = el[i].textContent 
                if(n.includes('http%3A%2F%2Fpull-flv-f1.douyincdn.com%2Fthird%2Fstream-')){
                    const reg = /(?<=http%3A%2F%2Fpull-flv-f1.douyincdn.com%2Fthird%2Fstream-)(.+?)(?=flv)/;
                    const strs = n.match(reg);
                    return strs
                } else {
                    return false
                }
            }
        } catch (error) {
            return false
        }
    })

    //await browser.close();
    return result;
  }

async function final(){
    const url = 'https://live.douyin.com/170784086311'
    const recorderTask = await getUrl(url)
    console.log(recorderTask)
}

final()

/src/engine/website/douyin.ts 部分整体代码 可以用注释的部分单独测ffmpeg。

const cheerio = require('cheerio');
const superagent = require('superagent');
const puppeteer = require('puppeteer');

const getUrl = async (item: string) => {
    const browser = await puppeteer.launch(true);
    const page = await browser.newPage();
    await page.goto(item);
    const result = page.$$eval('#RENDER_DATA', (el: string | any[])=>{
        try {
            for (let i = 0; i < el.length; i++) {
                let n = el[i].textContent 
                if(n.includes('http%3A%2F%2Fpull-flv-f1.douyincdn.com%2Fthird%2Fstream-')){
                    const reg = /(?<=http%3A%2F%2Fpull-flv-f1.douyincdn.com%2Fthird%2Fstream-)(.+?)(?=flv)/;
                    const strs = n.match(reg);
                    return strs
                } else {
                    console.log('not fond')
                    return ''
                }
            }
        } catch (error) {
            console.log('error')
            return ''
        }
    })

    return result;
  }

export function main(url: string) {
    return new Promise(function (resolve, reject) {
        superagent.get(url)
        .end((err: any, res: { text: any; }) => {
        if(err) {
            reject(err);
        }
         // cherrio模块获取页面内容
        let $ = cheerio.load(res.text);
        $("#root > div > div.T_foQflM > div > div > div.XM26psoY > div._1mISMfK2 > div.VmWWPdeA > div._DXoni4w > a").each(async (_idx: any, elem: any) => {
            // > B3AsdZT9
            // https://pull-flv-l1.douyincdn.com/third/stream-110833684070268966_hd.flv
            const liveurl: string = $(elem).attr("href");  
            const streamid = await getUrl(liveurl);
            console.log(streamid)

            if(streamid == ''){
                reject("Douyin=>No match results:Maybe the roomid is error,or this room is not open!")
            }
            else{
                resolve(`http://pull-flv-f1.douyincdn.com/third/stream-${streamid[0]}flv`);
            }

            //const streamid = '110832473289785453.'
            //resolve(`http://pull-flv-f1.douyincdn.com/third/stream-${streamid}flv`);

           })
        });
    });
}

调用ffmpeg 之前是存成mp4,现在存mp4会出错,存好的视频无法打开。 建立recoder时videoExt改为‘flv’就行了。 此外还有一个问题是 src\engine\message.ts里startNumber初始值需为0,而不是-1?

 const ps = FileHound
        .create()
        .ext(this.videoExt)
        .path(join(this.savePath))
        .findSync()
        .length;
      startNumber = ps //- 1 

因为很多基础的东西我都没仔细查过,只是放假这几天看了看,若出现很弱智的问题,还请见谅Orz。但这条路应该是能行得通的。

以及,您的repo质量很好!

Best Regards, laeglaur

spitir commented 2 years ago

大佬 加油!

umuoy1 commented 4 months ago

感谢,目前已支持