/*
* @File     : danmuSpider.js
* @Author   : jade
* @Date     : 2024/3/13 13:39
* @Email    : jadehh@1ive.com
* @Software : Samples
* @Desc     :
*/

import {_, load, Uri} from "./cat.js";
import * as Utils from "./utils.js";
import {JadeLogging} from "./log.js";
import {VodDetail, VodShort} from "./vod.js";
import {parseXML} from "./bilibili_ASS_Danmaku_Downloader.js";

class DanmuSpider {
    constructor() {
        this.siteUrl = "https://search.youku.com"
        this.reconnectTimes = 0
        this.maxReconnectTimes = 5
        this.jadeLog = new JadeLogging(this.getAppName(), "DEBUG")
    }

    getAppName() {
        return "弹幕"
    }

    getHeader() {
        return {"User-Agent": Utils.CHROME, "Referer": this.siteUrl + "/"};
    }

    async reconnnect(reqUrl, params, headers, redirect_url, return_cookie, buffer) {
        await this.jadeLog.error("请求失败,请检查url:" + reqUrl + ",两秒后重试")
        Utils.sleep(2)
        if (this.reconnectTimes < this.maxReconnectTimes) {
            this.reconnectTimes = this.reconnectTimes + 1
            return await this.fetch(reqUrl, params, headers, redirect_url, return_cookie, buffer)
        } else {
            await this.jadeLog.error("请求失败,重连失败")
            return null
        }
    }

    async getResponse(reqUrl, params, headers, redirect_url, return_cookie, buffer, response) {
        {
            if (response.headers["location"] !== undefined) {
                if (redirect_url) {
                    await this.jadeLog.debug(`返回重定向连接:${response.headers["location"]}`)
                    return response.headers["location"]
                } else {
                    return this.fetch(response.headers["location"], params, headers, redirect_url, return_cookie, buffer)
                }
            } else if (response.content.length > 0) {
                this.reconnectTimes = 0
                if (return_cookie) {
                    return {"cookie": response.headers["set-cookie"], "content": response.content}
                } else {
                    return response.content
                }
            } else if (buffer === 1) {
                this.reconnectTimes = 0
                return response.content
            } else {
                await this.jadeLog.error(`请求失败,请求url为:${reqUrl},回复内容为:${JSON.stringify(response)}`)
                return await this.reconnnect(reqUrl, params, headers, redirect_url, return_cookie, buffer)
            }
        }
    }


    async fetch(reqUrl, params, headers, redirect_url = false, return_cookie = false, buffer = 0) {
        let data = Utils.objectToStr(params)
        let url = reqUrl
        if (!_.isEmpty(data)) {
            url = reqUrl + "?" + data
        }
        let uri = new Uri(url);
        let response;
        response = await req(uri.toString(), {method: "get", headers: headers, buffer: buffer, data: null})
        if (response.code === 201 || response.code === 200 || response.code === 302 || response.code === 301 || return_cookie) {
            return await this.getResponse(reqUrl, params, headers, redirect_url, return_cookie, buffer, response)
        } else {
            await this.jadeLog.error(`请求失败,失败原因为:状态码出错,请求url为:${uri},回复内容为:${JSON.stringify(response)}`)
            return await this.reconnnect(reqUrl, params, headers, redirect_url, return_cookie, buffer)
        }
    }

    async getHtml(url = this.siteUrl, headers = this.getHeader()) {
        let html = await this.fetch(url, null, headers)
        if (!_.isEmpty(html)) {
            return load(html)
        } else {
            await this.jadeLog.error(`html获取失败`, true)
        }
    }

    async parseVodShortListFromJson(obj, vodDetail) {
        for (const componentObj of obj["pageComponentList"]) {
            if (componentObj["commonData"] !== undefined) {
                let searchVodDetail = new VodDetail()
                let commonData = componentObj["commonData"]
                searchVodDetail.type_name = commonData["feature"]
                if (commonData["notice"] !== undefined) {
                    searchVodDetail.vod_actor = commonData["notice"].replaceAll("演员：", "").replaceAll(" ", "")
                }
                if (commonData["director"] !== undefined) {
                    searchVodDetail.vod_director = commonData["director"].replaceAll("导演：", "").replaceAll(" ", "")
                }
                if (vodDetail.type_name === "电影") {
                    searchVodDetail.vod_id = commonData["leftButtonDTO"]["action"]["value"]
                } else {
                    searchVodDetail.vod_id = commonData["showId"]
                }
                searchVodDetail.vod_name = commonData["titleDTO"]["displayName"]
                if ( searchVodDetail.vod_name === vodDetail.vod_name || searchVodDetail.type_name.indexOf(vodDetail.vod_year) > -1 || searchVodDetail.type_name.indexOf(vodDetail.type_name) > -1   || searchVodDetail.vod_director === vodDetail.vod_director) {
                    await this.jadeLog.debug(`匹配视频网站成功,名称为:${searchVodDetail.vod_name},类型为:${searchVodDetail.type_name},导演为:${searchVodDetail.vod_director}`, true)
                    return searchVodDetail
                }
            }
        }
        await this.jadeLog.warning("没有匹配到弹幕网站")
        return null
    }

    async parseVodUrlFromJsonByEpisodeId(obj, episodeId) {
        for (const serises of obj["serisesList"]) {
            if (Utils.isNumeric(episodeId["episodeId"])) {
                if (parseInt(episodeId["episodeId"]).toString() === serises["displayName"]) {
                    return serises["action"]["value"]
                }
            }
        }
        await this.jadeLog.error("没有找到匹配的集数")
        return ""
    }

    async downloadDanmu(url) {
        // 如果没有找到弹幕的话，容易导致卡在这一步，从而导致结果加载不出来
        let response = await req(url,{headers:this.getHeader()})
        if (response.code === 200){
            let xml = parseXML(JSON.parse(response.content))
            let params = {"do": "set", "key": "danmu", "value": xml}
            await req("http://127.0.0.1:9978/cache", {method: "post", data: params, postType: "form-data"});
            return "http://127.0.0.1:9978/cache?do=get&key=danmu"
        }
        else{
            this.jadeLog.error(`弹幕请求失败,返回结果为:${JSON.stringify(response)}`)
            return ""
        }
    }

    async search(vodDetail, episodeId) {
        let params = {"pg": "1", "keyword": vodDetail.vod_name}
        let searchObj = JSON.parse(await this.fetch(this.siteUrl + "/api/search", params, this.getHeader()))
        let searchDetail = await this.parseVodShortListFromJson(searchObj, vodDetail)
        if (!_.isEmpty(searchDetail)){
            return await this.getVideoUrl(searchDetail.vod_id, episodeId)
        }else{
            return ""
        }
    }

    async getVideoUrl(showId, episodeId) {
        let url = "";
        if (!_.isEmpty(showId)) {
            if (showId.startsWith("http")) {
                url = showId
            } else {
                let params = {"appScene": "show_episode", "showIds": showId}
                let matchObj = JSON.parse(await this.fetch(this.siteUrl + "/api/search", params, this.getHeader()))
                url = await this.parseVodUrlFromJsonByEpisodeId(matchObj, episodeId)
            }
            if (!_.isEmpty(url)) {
                await this.jadeLog.debug(`弹幕视频播放连接为:${url}`)
                return await this.downloadDanmu("https://dmku.thefilehosting.com/?ac=dm&url=" + url)
            }
        }
        return url

    }


    async getDammu(voddetail, episodeId) {
        return await this.search(voddetail, episodeId)
    }
}

export {DanmuSpider}