<template>
	<div>
		<el-container style="height: 100vh;">
			<el-header height="45px" style="background-color: #fafafa; padding: 0 10px;">
				<soft-header ref="headerRef" @update-soft="updateSoft()" @login-url="loginUrl" @clear-cache="clearCache"></soft-header>
			</el-header>
							
			<el-main ref="el-main" style="background-color: #fafafa;">
				<template>
					<div style="padding: 10px 20px 0 20px; height: 100%;">
						
						<el-row type="flex" align="middle" justify="space-between">
							<div>
								<span>链接平台：</span>
								<el-radio-group v-model="menuIndex" size="mini" style="margin-right: 20px;">
									<!-- <el-radio-button label="3" size="mini">天猫</el-radio-button> -->
								    <el-radio-button label="4" size="mini">淘宝/天猫</el-radio-button>
								    <el-radio-button label="1" size="mini">1688</el-radio-button>
								    <el-radio-button label="2" size="mini">京东</el-radio-button>
								    <el-radio-button label="5" size="mini">小红书</el-radio-button>
								    <el-radio-button label="10" size="mini">其他</el-radio-button>
								</el-radio-group>
							</div>
							
							
							<!-- 阿里巴巴账号 -->
							<template v-if="menuIndex == '1'">
								<div>
									<el-tag type="info" size="mini" v-if="alibabaStatus == 1">未检测</el-tag>
									<el-tag type="success" size="mini" v-if="alibabaStatus == 2">阿里巴巴账号已登录</el-tag>
									<el-link type="danger" style="text-decoration: underline;" v-if="alibabaStatus == 3" :underline="false" @click="loginUrl('https://www.1688.com')">未登录，点击登录阿里巴巴账号</el-link>
									<el-button size="mini" type="warning" :loading="checkLoading" style="margin-left: 10px;" :disabled='alibabaStatus == 2' @click="checkAlibabaLogin">检测登录状态</el-button>
								</div>
							</template>
							
							<!-- 天猫/淘宝 -->
							<template v-if="menuIndex == '3' || menuIndex == '4'">
								<div>
									<el-tag type="info" size="mini" v-if="tbStatus == 1">未检测</el-tag>
									<el-tag type="success" size="mini" v-if="tbStatus == 2">{{menuIndex == '3' ? '天猫' : '淘宝'}}账号已登录</el-tag>
									<el-link type="danger" style="text-decoration: underline;" v-if="tbStatus == 3" :underline="false" @click="loginUrl('https://login.taobao.com')">未登录，点击登录<span>{{menuIndex == '3' ? '天猫' : '淘宝'}}</span>账号</el-link>
									<el-button size="mini" type="warning" :loading="checkLoading" style="margin-left: 10px;" :disabled='tbStatus == 2' @click="checkLogin">检测登录状态</el-button>
								</div>
							</template>
							
							<!-- 京东账号 -->
							<template v-if="menuIndex == '2'">
								<div>
									<el-tag type="info" size="mini" v-if="jdStatus == 1">未检测</el-tag>
									<el-tag type="success" size="mini" v-if="jdStatus == 2">京东账号已登录</el-tag>
									<el-link type="danger" style="text-decoration: underline;" v-if="jdStatus == 3" :underline="false" @click="loginUrl('https://passport.jd.com/new/login.aspx')">未登录，点击登录京东账号</el-link>
									<el-button size="mini" type="warning" :loading="checkLoading" style="margin-left: 10px;" :disabled='jdStatus == 2' @click="checkJdLogin">检测登录状态</el-button>
								</div>
							</template>
							
							<!-- 小红书 -->
							<template v-if="menuIndex == '5'">
								<div>
									<el-tag type="info" size="mini" v-if="redStatus == 1">未检测</el-tag>
									<el-tag type="success" size="mini" v-if="redStatus == 2">小红书账号已登录</el-tag>
									<el-link type="danger" style="text-decoration: underline;" v-if="redStatus == 3" :underline="false" @click="loginUrl('https://www.xiaohongshu.com')">未登录，点击登录小红书账号</el-link>
									<el-button size="mini" type="warning" :loading="checkLoading" style="margin-left: 10px;" :disabled='redStatus == 2' @click="checkRedLogin">检测登录状态</el-button>
								</div>
							</template>
							
							<!-- 其他 -->
							<template v-if="menuIndex == '10'">
									<el-link type="danger" :underline="false" style="font-size: 12px;font-weight: 600;">其他平台仅提供试用，非会员功能</el-link>
							</template>
						</el-row>
						
						<el-row style="margin: 10px 0;">
							提取模式：
							<el-radio-group v-model="exeType">
								<el-radio :label="1">后台运行</el-radio>
								<el-radio :label="2">前台显示</el-radio>
							</el-radio-group>
						</el-row>
						
						<el-row>
							<span class="set-title">保存目录：</span>
							<el-input :title="downloadDir" ref="upload-input" size="mini" @focus="pickPath" placeholder="请选择输出目录" v-model="downloadDir" readonly style="width:300px;" prefix-icon="el-icon-folder"></el-input>
							<el-popover placement="bottom" popper-class="popper-open" trigger="hover" content="打开保存目录">
								<i class="el-icon-folder-opened" slot="reference" style="padding-left: 5px; cursor: pointer; font-size: 22px; vertical-align: middle;" @click="openFolder()"></i>
							</el-popover>
						</el-row>
						
						<div style="margin-top: 10px;">
							<el-input id="aaa" type="textarea" :rows="3" placeholder="请输入需要提取的网址" v-model="formatUrl"></el-input>
							
							<div class="content-top" style="padding: 10px 0; text-align: center; display: inherit;">
								<el-button size="small" type="danger" @click="addLinks()" :loading="addLoading">开始提取</el-button>
								<el-button size="small" type="danger" @click="pauseLinks()">停止提取</el-button>
								<el-button size="small" type="danger" @click="clearList()">清除结果</el-button>
								<el-button size="small" type="danger" @click="exportLinks()">合并导出全部</el-button>
							</div>
						</div>
											
						<div class="table-scroll" style="height: calc(100% - 290px); overflow: hidden;">
							<el-row type="flex" justify="space-between">
								<div>
									<h4 style="display: inline-block;">
										提取结果：
									</h4>
								</div>
							</el-row>
							<div style="display: flex; flex-wrap: nowrap;justify-content: space-between;height: calc(100% - 60px);">
								<vxe-table style="width: 100%;" ref="xTable" show-overflow class="img-table" max-height="100%" empty-text="没有更多数据了！" :loading="tabLoading" :row-config="{isHover: true}"
									:loading-config="{icon: 'vxe-icon-indicator roll', text: '加载中...'}" :data="this[listStr+'List']" :scroll-y="{enabled: true}">
									<vxe-column field="title" title="名称"></vxe-column>
									<vxe-column field="page" title="页数">
										<template #default="{ row }">
											第{{row.currentPage}}页，共{{row.totalPage}}页
										</template>
									</vxe-column>
									<vxe-column field="filesize" title="条数" width="100">
										<template #default="{ row }">
											<span v-if="row.urls">{{row.urls.length}}</span>
										</template>
									</vxe-column>
									<vxe-column field="status" title="状态" width="150">
										<template #default="{ row }">
											<template v-if="row.status == '1'">
												<i class="el-icon-info" style="font-size: 16px; color: #999;"></i>
												<span>待操作</span>
											</template>
											<template v-if="row.status == '2'">
												<i class="el-icon-success" style="font-size: 16px; color: #19be6b;"></i>
												<span>导出成功</span>
											</template>
										</template>
									</vxe-column>
									<vxe-column title="操作" width="150">
										<template #default="{ row, rowIndex }">
											<el-button :loading="row.loading" type="danger" size="mini" plain @click="exportPageLinks(row)">导出</el-button>
										</template>
									</vxe-column>
								</vxe-table>
							
							</div>

						</div>
					</div>
				</template>
		
			</el-main>
			
			<el-footer height="48px">
				<!-- 更新 -->
				<soft-update ref="updateRef" :showDowload="dowloadModel" :dowloadFinish="finishModel"></soft-update>
			</el-footer>
		</el-container>
	</div>
</template>

<script>
	import os from 'os'
	import fs from 'fs'
	import request from 'request'
	import path from 'path';
	import xlsx from 'node-xlsx';
	import softUpdate from './update.vue';
	import softHeader from './header.vue';
	import electronApi from '@/utils/electronApi';
	import pjson from '/package.json'
	// import puppeteer from 'puppeteer'
	import puppeteer from 'puppeteer-extra'
	const axios = require('axios');
	const StealthPlugin = require('puppeteer-extra-plugin-stealth');
	const { ipcRenderer } = require('electron');
	const listNameArr = ['alibaba','jd','tmall','tb','red','aliguoji','acaigou','amazon', 'pdd' ,'common','goofish','dy'];

	let separator = '';
	if (os.platform == 'linux') {
		separator = '/'
	} else {
		separator = '\\'
	}
	export default {
		name: 'landing-page',
		components: {
			softUpdate,
			softHeader
		},
		data() {
			return {
				menuIndex: '4',
				exeType: 1,
				
				usageTimes: 3,
				tipsModal: false,
				tipsDesc: "暂无下载权限，请开通VIP会员使用",
				
				formatUrl: '',
				tabLoading: false,
				productName: pjson.softInfo.softName,
				imgUrl: this.$api.imgUrl,
				downloadDir: os.userInfo().homedir + separator + "Downloads",
				dowloadModel: false,
				finishModel: false,
				loading: false,
				
				tbList: [], //淘宝数据
				tmallList: [],
				alibabaList: [], 
				jdList: [],
				redList: [],
				commonList: [],
				
				execNum: 100, //限制
				checkLoading: false, //点击检测登录状态
				tbStatus: 1, // 1、未检测 2、已经登录 3、未登录 
				jdStatus: 1, // 1、未检测 2、已经登录 3、未登录 
				redStatus: 1, //同上
				alibabaStatus: 1, //同上上
				
				/** 浏览器名称 **/
				alibabaBrowser: null,
				tbBrowser: null,
				jdBrowser: null,
				commonBrowser: null,
				redBrowser: null,
				loginBrowser: null, // 登录用的浏览器实例
				pauseFlag: true, //暂停中止标志
				addLoading: false,
				
				videoBrowser: null,
				parseLoading: false,
				mergeLoading: false


			};
		},
		computed: {
			listStr: function(){
				let index = Number(this.menuIndex) - 1;
				return listNameArr[index];
			}
		},
		async mounted() {
			this.$refs.updateRef.updateSoft(true);

			let homedir = os.userInfo().homedir;
			if (fs.existsSync(homedir + separator + "Desktop")) {
				this.downloadDir = homedir + separator + "Desktop"
			} else {
				this.downloadDir = homedir + separator + "Downloads"
			}
			
			let dir = this.$utils.getStorage('downloadDir');
			if(dir && fs.existsSync(dir)){
				this.downloadDir = dir;
			}
			if (!fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName)) {
				fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName);
			}
			if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture')) {
				fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture');
			}
			
			if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture-jd')) {
				fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture-jd');
			}
			
			if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture-local')) {
				fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture-local');
			}

			// 打开浏览器
			const {
				shell
			} = require('electron');
			const links = document.querySelectorAll('a[href]');
			links.forEach(link => {
				link.addEventListener('click', e => {
					const url = link.getAttribute('href');
					e.preventDefault();
					shell.openExternal(url);
				});
			});
			
			// 判断系统版本 低于10使用兼容模式
			if(os.release() && os.release().indexOf('.') > -1){
				let systemVersion = Number(os.release().split('.')[0]);
				if(systemVersion < 10){ // 低于win10，软件打开时候浏览器设置为兼容版
					this.$utils.setStorage('versionType', 1);
				}else{
					this.$utils.setStorage('versionType', 2);
				}
			}
			
			// 初始化开发者设置
			this.$utils.setStorage('waitUntil', 'networkidle2');
			
			document.getElementById('aaa').addEventListener('contextmenu', e => {
				e.preventDefault();
				// 发送事件到主进程，附带元素类型信息
				ipcRenderer.send('show-context-menu', 'input');
			});
			
		},
		methods: {
			// 实时获取页面滚动加载时间
			initMs(){
				let pageMs = this.$utils.getStorage('pageMs');
				if(pageMs){
					return Number(pageMs);
				}else{
					return 600;
				}
			},
			// 实时获取开发者设置
			initDevelop(){
				let develop = {
					headless: true,
					waitUntil: 'networkidle2'
				};
				let n1 = this.exeType;
				let n2 = this.$utils.getStorage('waitUntil');
				if(n1){
					if(n1 == 1){
						develop.headless = true;
					}else if(n1 == 2){
						develop.headless = false;
					}
				}
				if(n2){
					develop.waitUntil = n2;
				}
				
				return develop;
			},
			// 实时获取浏览器路径
			initPath(){
				let chromeType = this.$utils.getStorage('chromeType');
				let chromePath = puppeteer.executablePath().replace('win32-1', 'win64-1');
				if(chromeType == 1){ // 电脑自带浏览器
					chromePath = this.$utils.getStorage('chromePath');
				}else{
					chromePath = puppeteer.executablePath().replace('win32-1', 'win64-1');
					let versionType = this.$utils.getStorage('versionType');
					if(versionType && versionType == 1){
						chromePath = chromePath.replace('chrome-win', 'chrome7');
					}
				}
				return chromePath;
			},
			// 实时获取浏览器数据缓存
			initDataDir(tag){
				let chromeType = this.$utils.getStorage('chromeType');
				let userDataDir = os.tmpdir() + separator + 'chrome-data-capture';
				if(chromeType == 1){ // 电脑自带浏览器
					userDataDir = os.tmpdir() + separator + 'chrome-data-capture-local';
				}else{
					userDataDir = os.tmpdir() + separator + 'chrome-data-capture';
					if(tag == 'jd'){
						userDataDir = os.tmpdir() + separator + 'chrome-data-capture-jd';
					}
				}
				return userDataDir;
			},
			// 任务下载间隔时间
			initGap(){
				let gap = this.$utils.getStorage('gap');
				if(gap){
					return Number(gap);
				}else{
					return 1;
				}
			},
			// 通用的延迟函数
			async delay(t) {
				let s = this.initGap();
				if(t){
					s = t;
				}
				if(s > 0){
					return new Promise(resolve => setTimeout(resolve, Number(s)*1000));
				}else{
					return null;
				}
			},
			checkAuthority(){
				let authority = this.$refs.headerRef.authority;
				this.$refs.imgRef.authority = authority;
			},
			// 选择目录
			pickPath() {
				this.$refs['upload-input'].blur();
				electronApi.call('pickDir', []).then((path) => {
					if (path) {
						this.downloadDir = path;
						this.$utils.setStorage('downloadDir', path);
					}
				});
			},
			// 打开自定义下载目录
			openFolder() {
				let path = this.downloadDir;
				if (fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName)) {
					path = this.downloadDir + separator + pjson.softInfo.softName;
				} else {
					fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName);
					path = this.downloadDir + separator + pjson.softInfo.softName;
				}
				electronApi.call('showItemInfolder', [path + '\\tty.tty'])
			},
			openVip() {
				this.tipsModal = false;
				this.$refs.headerRef.openVip();
			},
			updateSoft() {
				this.$refs.updateRef.updateSoft();
			},
			// 清除缓存的后续操作
			async clearCache(){
				if(this.loginBrowser){
					await this.loginBrowser.close();
					this.loginBrowser = null;
				}
				
				if(this.videoBrowser){
					await this.videoBrowser.close();
					this.videoBrowser = null;
				}
			},
			// 清除结果
			clearList(){
				let index = Number(this.menuIndex) - 1;
				this[listNameArr[index]+'List'] = [];
			},
			//停止提取
			async pauseLinks(){
				this.addLoading = false;
				let index = Number(this.menuIndex) - 1;
				let browserName = listNameArr[index] + 'Browser';
				if(index == '2'){ // 天猫和淘宝共用一个
					browserName = 'tbBrowser';
				}
				if(this[browserName]){ //关闭浏览器
					await this[browserName].close();
					this[browserName] = null;
				}
			},
			//导出全部链接
			exportLinks(){
				let allRows = {
					title: '淘宝商品链接汇总',
					urls: [],
					loading: false,
					status: '1'
				};
				switch(this.menuIndex){
					case '1': // 阿里巴巴
						allRows.title = '阿里巴巴商品链接汇总';
						break;
					case '2': // 京东
						allRows.title = '京东商品链接汇总';
						break;
					case '3': // 天猫
					case '4': // 淘宝
						let allUrls = [];
						for(let i = 0; i < this.tbList.length; i++){
							allUrls = allUrls.concat(this.tbList[i].urls);
						}
						allRows.urls = allUrls;
						break;
					case '5': // 小红书
						allRows.title = '小红书笔记链接汇总';
						break;
					case '10': // 普通网址
						allRows.title = '网页链接汇总';
						break;
				}
				
				this.exportPageLinks(allRows);
			},
			// 导出单页链接
			exportPageLinks(row){
				row.loading = true;
				let filename = row.title + '-' + this.$utils.formatFileTime() +'.xlsx';
				let sheet1 = [['序号','商品ID','商品标题','商品链接','价格','销量','店铺名称','店铺地址','首图地址']];
				if(this.menuIndex == '4'){
					sheet1 = [['序号','商品ID','商品标题','商品链接','价格','销量','店铺名称','店铺地址','首图地址','商品短链接']];
				}else if(this.menuIndex == '5'){
					sheet1 = [['序号','笔记标题','笔记链接','用户名','点赞量','发布时间','首图地址']];
				}else if(this.menuIndex == '10'){
					sheet1 = [['序号','标题','链接']];
				}
				for(let i = 0; i < row.urls.length; i++){
					let item = row.urls[i];
					let info = [i+1, item.id, item.title, item.href, item.price, item.realSales, item.shopNameText, item.shopUrl, item.mainPic];
					if(this.menuIndex == '4'){
						info = [i+1, item.id, item.title, item.href, item.price, item.realSales, item.shopNameText, item.shopUrl, item.mainPic, 'https://detail.tmall.com/item.htm?id='+item.id];
					}else if(this.menuIndex == '5'){
						info = [i+1, item.title, item.href, item.name, item.realSales, item.time, item.mainPic];
					}else if(this.menuIndex == '10'){
						info = [i+1, item.title, item.href];
					}
					
					sheet1.push(info);
				}
				
				let buffer = xlsx.build([
					{
						name: 'sheet1',
						data: sheet1
					}
				]);
				
				if (!fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName)) {
					fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName);
				}
				fs.writeFileSync(this.downloadDir + separator + pjson.softInfo.softName + separator + filename, buffer, {'flag':'w'});
				row.loading = false;
				row.status = '2';
				this.$message({message: '文件导出成功！', type: 'success'});
				electronApi.call('showItemInfolder',[this.downloadDir + separator + pjson.softInfo.softName + separator + filename]);
			},
			//提取链接
			async addLinks(){
				this.addLoading = true;
				setTimeout(() => {
					this.addLoading = false;
				}, 30000);
				if(this.loginBrowser){
					await this.loginBrowser.close();
					this.loginBrowser = null;
				}
				
				let index = Number(this.menuIndex) - 1;
					
				if(this.menuIndex == '1'){ // 阿里巴巴
					if(this.alibabaStatus == 1 || this.alibabaStatus == 3){  // 未检测登录状态/或提示未登录状态，开始检测
						await this.checkAlibabaLogin().then((data) => {
							if(data != 2){  // 未登录
								this.alibabaStatus = 3;
								this.loginVisible = true;
							}
						}).catch(err => {
							this.alibabaStatus = 3;
						});
						if(this.alibabaStatus == 3){
							this.loading = false;
							return false;
						}
					}
				}
				
				if(this.menuIndex == '2'){ // 京东
					if(this.jdStatus == 1 || this.jdStatus == 3){  // 未检测登录状态/或提示未登录状态，开始检测
						await this.checkJdLogin().then((data) => {
							if(data != 2){  // 未登录
								this.jdStatus = 3;
								this.loginVisible = true;
							}
						}).catch(err => {
							this.jdStatus = 3;
						});
						if(this.jdStatus == 3){
							this.loading = false;
							return false;
						}
					}
				}
				
				if(this.menuIndex == '3' || this.menuIndex == '4'){ // 天猫/淘宝
					if(this.tbStatus == 1 || this.tbStatus == 3){  // 未检测登录状态/或提示未登录状态，开始检测
						await this.checkLogin().then((data) => {
							if(data != 2){ // 未登录
								this.tbStatus = 3;
								this.loginVisible = true;
							}
						}).catch(err => {
							this.tbStatus = 3;
						});
					}
					if(this.tbStatus == 3){
						this.loading = false;
						return false;
					}
				}
				
				if(this.menuIndex == '5'){ // 小红书
					if(this.redStatus == 1 || this.redStatus == 3){  // 未检测登录状态/或提示未登录状态，开始检测
						await this.checkRedLogin().then((data) => {
							if(data != 2){  // 未登录
								this.redStatus = 3;
								this.loginVisible = true;
							}
						}).catch(err => {
							this.redStatus = 3;
						});
						if(this.redStatus == 3){
							this.loading = false;
							return false;
						}
					}
				}
				
				let userDataDir = this.initDataDir();
				if(this.menuIndex == '2'){
					userDataDir = this.initDataDir('jd');
				}
				// 运行不同平台的浏览器
				puppeteer.use(StealthPlugin());
				let browserName = listNameArr[index] + 'Browser';
				if(index == '2'){ // 天猫和淘宝共用一个
					browserName = 'tbBrowser';
				}
				
				let headless = true;
				headless = this.initDevelop().headless;
				let redSize = '';
				if(['3','4','5'].indexOf(this.menuIndex) > -1){
					redSize = '--window-size=1920,800'; //给浏览器一个初始大小，在无头模式下，页面会自适用缩放
				}
				
				try{
					this[browserName] = await puppeteer.launch({
						headless: headless,
						executablePath: this.initPath(),
						userDataDir: userDataDir, 
						args: [
							'--start-maximized',
							'--no-sandbox',
							'--disable-setuid-sandbox',
							'--disable-blink-features=AutomationControlled',
							redSize
						]
					});
					
					switch(this.menuIndex){
						case '1': // 阿里巴巴
							this.alibabaScanUrl(this.formatUrl);
							break;
						case '2': // 京东
							this.jdScanUrl(this.formatUrl);
							break;
						case '3': // 天猫
						case '4': // 淘宝
							this.tbScanUrl(this.formatUrl);
							break;
						case '5': // 小红书
							this.redScanUrl(this.formatUrl);
							break;
						case '10': // 普通网址
							this.commonScanUrl(this.formatUrl);
							break;
					}
				}catch(e){
					console.log(e, '测试');
				}
				
				
			},
			
			// 天猫/淘宝扫描网址
			tbScanUrl(url){
				(async () => {
					try{
						let authority = this.$refs.headerRef.authority.isAuthority;
						let page = await this.tbBrowser.newPage();
						
						let responseVideo = [];
						let waitUntil = 'networkidle2';
						waitUntil = this.initDevelop().waitUntil;
						await page.goto(url, {waitUntil : waitUntil});
						
						let searchTitle = await page.title() || '淘宝商品搜索';
						if(searchTitle){
							searchTitle = searchTitle.substring(0, 50);
							if(this.containsAnyChar(searchTitle)){  //判断是否含有特殊字符
								searchTitle = searchTitle.replace(/[\\/:*?"<>|#%&\s]/g, "");
							}
						}
						let outObj = {};
						let pageHandle = await page.$$('[class^=next-pagination-display]');
						let currentPage = 1;
						let totalPage = 1;
						if(pageHandle && pageHandle.length > 0){
							let pageValue = await page.$eval('[class^=next-pagination-display]', el => el.innerText);
							currentPage = pageValue.replace('\n', '').split('/')[0] || 1;
							totalPage = pageValue.replace('\n', '').split('/')[1] || 1;
						}
						
						for(let i = Number(currentPage); i < Number(totalPage)+1; i++){
							let pValue = i + 1;
							let pageHandle = await page.$$('.next-pagination-jump-input input');
							if(pageHandle && pageHandle.length > 0){ // 页码多，可以点击跳转制定页码
								await page.type('.next-pagination-jump-input input', pValue.toString());
							}
							
							let itemTitle = searchTitle + '-' + i;
							const imgInfo = await page.evaluate((authority, execNum, itemTitle) => {
								let outObj = {
									title: itemTitle,
									currentPage: 1,
									totalPage: 1,
									urls: [],
									status: '1',
									loading: false
								};
								let total = document.querySelector('[class^=next-pagination-display]');
								if(total){
									outObj.currentPage = total.innerText.replace('\n', '').split('/')[0];
									outObj.totalPage = total.innerText.replace('\n', '').split('/')[1];
								}
								
								//主图
								let arr1 = document.querySelectorAll('a[id*=item_id]');
								for(let i=0; i< arr1.length; i++){
									let href = arr1[i].href;
									let id = arr1[i].id.replace('item_id_', '');
									let title = arr1[i].querySelector('[class^=title]') ? arr1[i].querySelector('[class^=title]').innerText : '淘宝商品'+new Date().getTime();
									let priceInt = arr1[i].querySelector('[class^=priceInt]') ? arr1[i].querySelector('[class^=priceInt]').innerText : 0;
									let priceFloat = arr1[i].querySelector('[class^=priceFloat]') ? arr1[i].querySelector('[class^=priceFloat]').innerText : '';
									let price = priceInt + priceFloat;
									let realSales = arr1[i].querySelector('[class^=realSales]') ? arr1[i].querySelector('[class^=realSales]').innerText : '';
									let shopNameText = arr1[i].querySelector('[class^=shopNameText]') ? arr1[i].querySelector('[class^=shopNameText]').innerText : '';
									let shopUrl = arr1[i].querySelector('a[class^=shopName]') ? arr1[i].querySelector('a[class^=shopName]').href : '';
									let mainPic = arr1[i].querySelector('img[class^=mainImg]') ? arr1[i].querySelector('img[class^=mainImg]').src : '';
									
									let info = {
										id: id,
										title: title,
										href: href,
										price: price,
										realSales: realSales,
										shopNameText: shopNameText,
										shopUrl: shopUrl,
										mainPic: mainPic
									}
									outObj.urls.push(info);
								}
								
								//page.$$('.next-pagination-jump-input input');
								// let skuHandle = document.querySelector('.next-pagination-jump-go');
								// if(skuHandle){
								// 	skuHandle.click({force: true});
								// }
								
								let nextHandle = document.querySelector('button[class*=next-next]');
								if(nextHandle){
									nextHandle.click({force: true});
								}
								return outObj;
							}, authority, this.execNum, itemTitle);
							
							this.tbList.push(imgInfo);
							await this.delay(5);
						}
						
						await this.tbBrowser.close();
						this.addLoading = false;
					
					}catch(e){
						this.addLoading = false;
						this.showError(e);
					}
				})();
			},
			
			// 阿里巴巴扫描网址
			alibabaScanUrl(url){
				(async () => {
					try{
						let authority = this.$refs.headerRef.authority.isAuthority;
						let page = await this.alibabaBrowser.newPage();
						
						let responseVideo = [];
						let waitUntil = 'networkidle2';
						waitUntil = this.initDevelop().waitUntil;
						await page.goto(url, {waitUntil : waitUntil});
						
						let searchTitle = await page.title() || '阿里巴巴商品搜索';
						if(searchTitle){
							searchTitle = searchTitle.substring(0, 50);
							if(this.containsAnyChar(searchTitle)){  //判断是否含有特殊字符
								searchTitle = searchTitle.replace(/[\\/:*?"<>|#%&\s]/g, "");
							}
						}
						
						//找页码信息
						let outObj = {};
						let pageHandle = await page.$$('[class^=pagination-container] span');
						let currentPage = 1;
						let totalPage = 1;
						if(pageHandle && pageHandle.length > 0){
							totalPage = await page.$eval('[class^=pagination-container] span', el => el.innerText);
							currentPage = await page.$eval('[class^=pagination-container] .fui-current', el => el.innerText);
						}
						
						for(let i = Number(currentPage); i < Number(totalPage)+1; i++){
							await new Promise(resolve => setTimeout(resolve, 1500)).then(async() => {
								await page.evaluate(() => {
									window.scrollTo({
										top: 10000, 
										behavior: "smooth" 
									});
								});
							});
							
							await new Promise(resolve => setTimeout(resolve, 5000)).then(async() => {
								let itemTitle = searchTitle + '-' + i;
								const imgInfo = await page.evaluate((authority, execNum, itemTitle) => {
									let outObj = {
										title: itemTitle,
										currentPage: 1,
										totalPage: 1,
										urls: [],
										status: '1',
										loading: false
									};
									let total = document.querySelector('[class^=pagination-container] span');
									if(total){
										outObj.currentPage = document.querySelector('[class^=pagination-container] .fui-current').innerText || 1;
										outObj.totalPage = total.innerText || 1;
									}
									// 广告链接
									// document.querySelectorAll('[class*=space-common-offerlist] a[class*=pc-ad]');
									// 正常
									let arr1 = document.querySelectorAll('[class*=space-common-offerlist] a[class*=search-offer-item]');
									for(let i=0; i< arr1.length; i++){
										let href = arr1[i].href;
										let idData =  arr1[i].dataset.renderkey || '';
										let length = idData.split('_').length - 1;
										let id = idData.split('_')[length];
										let title = arr1[i].querySelector('[class^=title-text]') ? arr1[i].querySelector('[class^=title-text]').innerText : '阿里巴巴商品'+new Date().getTime();
										let priceText = arr1[i].querySelector('[class^=price-item]') ? arr1[i].querySelector('[class^=price-item]').innerText : '';
										let price = priceText.replace('¥', '').replaceAll('\n', '');
										let realDom = arr1[i].querySelector('.offer-price-row .offer-desc-item');
										let realSales = realDom ? realDom.innerText : '';
										let shopNameText = arr1[i].querySelector('[class^=offer-shop-row]') ? arr1[i].querySelector('[class^=offer-shop-row]').innerText : '';
										let shopUrl = arr1[i].querySelector('[class^=offer-shop-row] a') ? arr1[i].querySelector('[class^=offer-shop-row] a').href : '';
										let mainPic = arr1[i].querySelector('img[class^=main-img]') ? arr1[i].querySelector('img[class^=main-img]').src : '';
										
										let info = {
											id: id,
											title: title,
											href: href,
											price: price,
											realSales: realSales,
											shopNameText: shopNameText,
											shopUrl: shopUrl,
											mainPic: mainPic
										}
										outObj.urls.push(info);
									}
									let nextHandle = document.querySelector('.pagination-container .fui-next');
									if(nextHandle){
										nextHandle.click({force: true});
									}
									return outObj;
								}, authority, this.execNum, itemTitle);
								this.alibabaList.push(imgInfo);
							});
							
						}
						
						await this.alibabaBrowser.close();
						this.addLoading = false;
							
						
					}catch(e){
						this.addLoading = false;
						this.showError(e);
					}
				})();
			},
			
			// 京东扫描网址
			jdScanUrl(url){
				(async () => {
					try{
						let authority = this.$refs.headerRef.authority.isAuthority;
						let page = await this.jdBrowser.newPage();
						
						let responseVideo = [];
						let waitUntil = 'networkidle2';
						waitUntil = this.initDevelop().waitUntil;
						await page.goto(url, {waitUntil : waitUntil});
						
						let searchTitle = await page.title() || '京东商品搜索';
						if(searchTitle){
							searchTitle = searchTitle.substring(0, 50);
							if(this.containsAnyChar(searchTitle)){  //判断是否含有特殊字符
								searchTitle = searchTitle.replace(/[\\/:*?"<>|#%&\s]/g, "");
							}
						}
						
						//找页码信息
						let outObj = {};
						let pageHandle = await page.$$('[class*=quick-result]');
						let currentPage = 1;
						let totalPage = 1;
						if(pageHandle && pageHandle.length > 0){
							let pageContent = await page.$eval('[class*=quick-result]', el => el.innerText);
							pageContent = pageContent.replace('\n', '').replace('\n', '');
							currentPage =pageContent.split('/')[0];
							totalPage = pageContent.split('/')[1];
						}else{
							let pageHandle = await page.$$('[class*=pagination_center]');
							if(pageHandle && pageHandle.length > 0){
								currentPage = await page.$eval('[class*=pagination_center] [class*=active]', el => el.innerText);
								let totalInfo = await page.$eval('[class*=pagination_total]', el => el.innerText);
								totalPage = totalInfo.replace('共', '').replace('页', '');
							}
						}
						
						for(let i = Number(currentPage); i < Number(totalPage)+1; i++){
							await new Promise(resolve => setTimeout(resolve, 1500)).then(async() => {
								await page.evaluate(() => {
									window.scrollTo({
										top: 8000, 
										behavior: "smooth" 
									});
								});
							});
							
							await new Promise(resolve => setTimeout(resolve, 5000)).then(async() => {
								let itemTitle = searchTitle + '-' + i;
								const imgInfo = await page.evaluate((authority, execNum, itemTitle) => {
									let outObj = {
										title: itemTitle,
										currentPage: 1,
										totalPage: 1,
										urls: [],
										status: '1',
										loading: false
									};
									
									let total = document.querySelector('[class*=quick-result]');
									if(total){
										let pageContent = total.innerText.replace('\n', '').replace('\n', '');
										outObj.currentPage =pageContent.split('/')[0] || 1;
										outObj.totalPage = pageContent.split('/')[1] || 1;
									}else{
										let currentDom = document.querySelector('[class*=pagination_center] [class*=active]');
										if(currentDom){
											outObj.currentPage = currentDom.innerText;
										}
										let totalInfo = document.querySelector('[class*=pagination_total]');
										if(totalInfo){
											utObj.totalPage = totalInfo.innerText.replace('共', '').replace('页', '');
										}
									}
									// 正常
									let arr1 = document.querySelectorAll('[class*=goodsContainer]>div');
									for(let i=0; i< arr1.length; i++){
										let sku = arr1[i].dataset.sku || '';
										let title = arr1[i].querySelector('[class*=goods_title]') ? arr1[i].querySelector('[class*=goods_title]').innerText : '京东商品'+new Date().getTime();
										let priceText = arr1[i].querySelector('[class*=price]') ? arr1[i].querySelector('[class*=price]').innerText : '';
										let price = priceText.replace('¥', '').replaceAll('\n', '');
										let realDom = arr1[i].querySelector('[class*=goods_volume]');
										let realSales = realDom ? realDom.innerText : '';
										let shopNameText = arr1[i].querySelector('[class*=shopFloor]') ? arr1[i].querySelector('[class*=shopFloor]').innerText : '';
										let shopUrl = arr1[i].querySelector('[class*=shopFloor] a') ? arr1[i].querySelector('[class*=shopFloor] a').href : '';
										let mainPic = arr1[i].querySelector('img') ? arr1[i].querySelector('img').src : '';
										
										let info = {
											title: title,
											id: sku,
											href: "https://item.jd.com/" + sku + ".html",
											price: price,
											realSales: realSales,
											shopNameText: shopNameText,
											shopUrl: shopUrl,
											mainPic: mainPic
										}
										outObj.urls.push(info);
									}
									let nextHandle = document.querySelectorAll('[class*=quick-result] [class*=quick-num]');
									if(nextHandle && nextHandle.length > 0){
										nextHandle[1].click({force: true});
									}else{
										nextHandle = document.querySelector('[class*=pagination_center] [class*=pagination_next]');
										if(nextHandle && nextHandle.length > 0){
											nextHandle.click({force: true});
										}
									}
									return outObj;
								}, authority, this.execNum, itemTitle);
								this.jdList.push(imgInfo);
							});
							
						}
						
						await this.jdBrowser.close();
						this.addLoading = false;
							
						
					}catch(e){
						this.addLoading = false;
						this.showError(e);
					}
				})();
			},
			
			// 小红书扫描网址
			redScanUrl(url){
				(async () => {
					try{
						let authority = this.$refs.headerRef.authority.isAuthority;
						let page = await this.redBrowser.newPage();
						
						let responseVideo = [];
						let waitUntil = 'networkidle2';
						waitUntil = this.initDevelop().waitUntil;
						await page.goto(url, {waitUntil : waitUntil});
						
						let searchTitle = await page.title() || '小红书笔记';
						if(searchTitle){
							searchTitle = searchTitle.substring(0, 50);
							if(this.containsAnyChar(searchTitle)){  //判断是否含有特殊字符
								searchTitle = searchTitle.replace(/[\\/:*?"<>|#%&\s]/g, "");
							}
						}
						
						let pageInfo = await page.evaluate(() => {
							let cHeight = document.documentElement.clientHeight;
							let scrollHeight = document.body.scrollHeight;
							return {'scrollHeight': scrollHeight, 'cHeight': cHeight}
						});
						
						let scrollHeight = pageInfo.scrollHeight;
						let cHeight = pageInfo.cHeight;
						let num = Math.ceil(scrollHeight / cHeight);
						let start = -1;
						let scrollTime = this.initMs();
						let scrollInt = setInterval(async() => {
							if(this.redBrowser && !this.redBrowser.isConnected()){
								clearInterval(scrollInt);
								await this.redBrowser.close();
								this.redBrowser = null;
							}
							start ++;
							let outInfo = await page.evaluate((start, searchTitle, url) => {
								let scrollHeight = document.body.scrollHeight;
								let cHeight = document.documentElement.clientHeight;
								
								let outObj = {
									url: url,
									title: searchTitle,
									currentPage: 1,
									totalPage: 1,
									urls: [],
									status: '1',
									loading: false,
									scrollHeight: scrollHeight
								};
								let arr1 = document.querySelectorAll('[class=feeds-container]>section');
								for(let i=0; i< arr1.length; i++){
									let index = arr1[i].dataset.index || '';
									let href = arr1[i].querySelector('a[class*=cover]') ? arr1[i].querySelector('a[class*=cover]').href : '';
									let title = arr1[i].querySelector('[class*=title]') ? arr1[i].querySelector('[class*=title]').innerText : "";
									let realSales = arr1[i].querySelector('[class*=count]') ? arr1[i].querySelector('[class*=count]').innerText : 0;
									let mainPic = arr1[i].querySelector('img') ? arr1[i].querySelector('img').src : '';
									let name = arr1[i].querySelector('[class^=name]') ? arr1[i].querySelector('[class^=name]').innerText : "";
									let time = arr1[i].querySelector('[class^=time]') ? arr1[i].querySelector('[class^=time]').innerText : "";
									
									let info = {
										title: title,
										id: index,
										href: href,
										realSales: realSales,
										mainPic: mainPic,
										name: name,
										time: time
									}
									if(href || title || name){
										outObj.urls.push(info);
									}
								}
								
								window.scrollTo({
									top: cHeight * start, 
									behavior: "smooth" 
								});
								return outObj;
							}, start, searchTitle, url);
							
							if(this.redList.length == 0){
								this.redList.push(outInfo);
							}else{
								let flag = true;
								for(let i = 0; i < this.redList.length; i++){
									if(outInfo.url == this.redList[i].url){
										flag = false;
										let temp = this.redList[i].urls;
										temp = temp.concat(outInfo.urls);
										let list = temp.filter((item, index) => temp.findIndex(i => i.id === item.id) === index)
										this.redList[i].urls = list;
									}
								}
								
								if(flag){
									this.redList.push(outInfo);
								}
							}
							
							if(outInfo.scrollHeight > 0){
								num = Math.ceil(outInfo.scrollHeight / cHeight);
							}else{
								num = 0;
							}
							
							if(start > num || start > 500){ // 防止页面过长，滚动200次自动停止
								clearInterval(scrollInt);
								await this.redBrowser.close();
								this.redBrowser = null;
								this.addLoading = false;
							}
						}, scrollTime);
					}catch(e){
						this.addLoading = false;
						this.showError(e);
					}
				})();
			},
			
			
			// 普通扫描网址
			commonScanUrl(url){
				(async () => {
					try{
						let authority = this.$refs.headerRef.authority.isAuthority;
						let page = await this.commonBrowser.newPage();
						
						let responseVideo = [];
						let waitUntil = 'networkidle2';
						waitUntil = this.initDevelop().waitUntil;
						await page.goto(url, {waitUntil : waitUntil});
						
						let searchTitle = await page.title() || '网址链接';
						if(searchTitle){
							searchTitle = searchTitle.substring(0, 50);
							if(this.containsAnyChar(searchTitle)){  //判断是否含有特殊字符
								searchTitle = searchTitle.replace(/[\\/:*?"<>|#%&\s]/g, "");
							}
						}
						
						let pageInfo = await page.evaluate(() => {
							let cHeight = document.documentElement.clientHeight;
							let scrollHeight = document.body.scrollHeight;
							return {'scrollHeight': scrollHeight, 'cHeight': cHeight}
						});
						
						let scrollHeight = pageInfo.scrollHeight;
						let cHeight = pageInfo.cHeight;
						let num = Math.ceil(scrollHeight / cHeight);
						let start = -1;
						let scrollTime = this.initMs();
						let scrollInt = setInterval(async() => {
							if(this.commonBrowser && !this.commonBrowser.isConnected()){
								clearInterval(scrollInt);
								await this.commonBrowser.close();
								this.commonBrowser = null;
							}
							start ++;
							let scrollHeight2 = await page.evaluate((start) => {
								let scrollHeight = document.body.scrollHeight;
								let cHeight = document.documentElement.clientHeight;
								
								window.scrollTo({
									top: cHeight * start, 
									behavior: "smooth" 
								});
								return scrollHeight;
							}, start);
							if(scrollHeight2 > 0){
								num = Math.ceil(scrollHeight2 / cHeight);
							}else{
								num = 0;
							}
							
							if(start > num || start > 200){ // 防止页面过长，滚动200次自动停止
								clearInterval(scrollInt);
								
								let outInfo2 = await page.evaluate((searchTitle, url) => {
									let outObj = {
										url: url,
										title: searchTitle,
										currentPage: 1,
										totalPage: 1,
										urls: [],
										status: '1',
										loading: false
									};
									let arr1 = document.querySelectorAll('a[href^=http]');
									let arr2 = document.querySelectorAll('a[href^="/"]');
									for(let i=0; i< arr1.length; i++){
										let href = arr1[i].href;
										let title = arr1[i].innerText;
										
										let info = {
											title: title,
											href: href
										}
										outObj.urls.push(info);
									}
									for(let j=0; j< arr2.length; j++){
										let href = arr2[j].href;
										let title = arr2[j].innerText;
										
										let info = {
											title: title,
											href: href
										}
										outObj.urls.push(info);
									}
									
									return outObj;
								}, searchTitle, url);
								
								this.commonList.push(outInfo2);
								await this.commonBrowser.close();
								this.addLoading = false;
							}
						}, scrollTime);
					}catch(e){
						this.addLoading = false;
						this.showError(e);
					}
				})();
			},
			
			// 检查天猫淘宝登录状态
			checkLogin(){
				this.checkLoading = true;
				this.tbStatus = 1;
				return new Promise((resolve, reject) => {
					(async () => {
						try{
							if(this.loginBrowser){
								await this.loginBrowser.close();
								this.loginBrowser = null;
							}
							this.loginBrowser = await puppeteer.launch({
								executablePath: this.initPath(),
								args: ['--window-size=1280,800'],
								userDataDir: this.initDataDir() 
							});
							const page = await this.loginBrowser.newPage();
							await page.setViewport({ width: 1280, height: 800 });
							let testUrl = 'https://www.taobao.com';
							await page.goto(testUrl, {waitUntil : 'networkidle2'});
							
							let loginInfo = await page.evaluate(() => {
								let navTags = document.querySelector('.site-nav-sign a');
								let userTags = document.querySelector('.site-nav-user a');
								
								if(navTags && navTags.innerHTML.indexOf('登录') > -1){
									return false;
								}else if(userTags){
									return true;
								}else{
									return false;
								}
							});
							
							if(loginInfo){
								this.tbStatus = 2;
							}else{
								this.tbStatus = 3;
							}
							
							resolve(this.tbStatus);
							this.checkLoading = false;
							await this.loginBrowser.close();
							this.loginBrowser = null;
						}catch(e){
							this.checkLoading = false;
							reject(3);
							this.showError(e);
						}
					})();
				});
				
			},
			// 检查阿里巴巴登录状态
			checkAlibabaLogin(){
				this.checkLoading = true;
				this.alibabaStatus = 1;
				return new Promise((resolve, reject) => {
					(async () => {
						try{
							if(this.loginBrowser){
								await this.loginBrowser.close();
								this.loginBrowser = null;
							}
							this.loginBrowser = await puppeteer.launch({
								executablePath: this.initPath(),
								args: ['--window-size=1280,800'],
								userDataDir: this.initDataDir()
							});
							const page = await this.loginBrowser.newPage();
							await page.setViewport({ width: 1280, height: 800 });
							let testUrl = 'https://www.1688.com';
							await page.goto(testUrl, {waitUntil : 'networkidle2'});
			
							const cookies = await page.cookies();
							let loginDiv = await page.$('div[class^=userNotLogin-]');
							const loginEle = await page.$('div[class^=loginAvatar-]');
							let loginText = '';
							if (loginEle) {
								loginText = await page.evaluate(el => el.innerText, loginEle);
							}
							const loginCookie = cookies.find(cookie => 
								cookie.name === '__cn_logon__'
							);
							let logonValue = '';
							if(loginCookie){
								logonValue = loginCookie.value;
							}
							if(loginDiv || loginText == '登录' || logonValue == 'false' || logonValue == false){
								this.alibabaStatus = 3; //未登录
							}else{
								this.alibabaStatus = 2;
							}
							
							resolve(this.alibabaStatus);
							this.checkLoading = false;
							await this.loginBrowser.close();
							this.loginBrowser = null;
						}catch(e){
							this.checkLoading = false;
							reject(3);
							this.showError(e);
						}
					})();
				});	
			},
			// 检查京东登录状态
			checkJdLogin(){
				this.checkLoading = true;
				this.jdStatus = 1;
				return new Promise((resolve, reject) => {
					(async () => {
						try{
							if(this.loginBrowser){
								await this.loginBrowser.close();
								this.loginBrowser = null;
							}
							this.loginBrowser = await puppeteer.launch({
								executablePath: this.initPath(),
								userDataDir: this.initDataDir('jd'),
								args: [
									'--start-maximized',
									'--no-sandbox',
									'--disable-setuid-sandbox',
									'--disable-blink-features=AutomationControlled',
									'--window-size=1280,800'
								]
							});
							const page = await this.loginBrowser.newPage();
							await page.setViewport({ width: 1280, height: 800 });
							let testUrl = 'https://www.jd.com';
							await page.goto(testUrl, {waitUntil : 'networkidle2'});
							
							let loginInfo = await page.evaluate(() => {
								let navTags = document.querySelector('.link-login');
								let userTags = document.querySelector('.nickname');
								let userTags2 = document.querySelector('.nick'); //企业账号
								
								let userInfo2 = document.querySelector('.login_info'); //页面右侧的登录信息
								let userTags3 = false;
								if(userInfo2 && userInfo2.innerText.indexOf('退出') > -1){
									userTags3 = true;
								}
								
								if(navTags && navTags.innerHTML.indexOf('请登录') > -1 && !userTags3){
									return false;
								}else if(userTags || userTags2 || userTags3){
									return true;
								}else{
									return false;
								}
							});
							
							if(loginInfo){
								this.jdStatus = 2;
							}else{
								this.jdStatus = 3;
							}
							
							resolve(this.jdStatus);
							this.checkLoading = false;
							await this.loginBrowser.close();
							this.loginBrowser = null;
						}catch(e){
							this.checkLoading = false;
							reject(3);
							this.showError(e);
						}
					})();
				});
			},
			// 检查小红书登录状态
			checkRedLogin(){
				this.checkLoading = true;
				this.redStatus = 1;
				return new Promise((resolve, reject) => {
					(async () => {
						try{
							if(this.loginBrowser){
								await this.loginBrowser.close();
								this.loginBrowser = null;
							}
							puppeteer.use(StealthPlugin());
							this.loginBrowser = await puppeteer.launch({
								executablePath: this.initPath(),
								userDataDir: this.initDataDir(),
								args: [
									'--start-maximized',
									'--no-sandbox',
									'--disable-setuid-sandbox',
									'--disable-blink-features=AutomationControlled',
									'--window-size=1280,800'
								],
							});
							const page = await this.loginBrowser.newPage();
							await page.setViewport({ width: 1280, height: 800 });
							let testUrl = "https://www.xiaohongshu.com";
							await page.goto(testUrl, {waitUntil : 'networkidle2'});
							
							let loginBtn = await page.$$('#login-btn');
							let loginContainer = await page.$$('.login-container');
							if(loginContainer.length > 0 || loginBtn.length > 0){
								this.redStatus = 3; //未登录
							}else{
								this.redStatus = 2;
							}
							
							resolve(this.redStatus);
							this.checkLoading = false;
							await this.loginBrowser.close();
							this.loginBrowser = null;
						}catch(e){
							this.checkLoading = false;
							reject(3);
							this.showError(e);
						}
					})();
				});
			},
			
			
			// 去登录
			loginUrl(url){
				(async () => {
					if(this.loginBrowser){
						await this.loginBrowser.close();
						this.loginBrowser = null;
					}
					try{
						if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture')) {
							fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture');
						}
						if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture-jd')) {
							fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture-jd');
						}
						if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture-local')) {
							fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture-local');
						}
						
						let userDataDir = this.initDataDir();
						if(url.indexOf('.jd.com/') > -1){
							userDataDir = this.initDataDir('jd');
						}
						
						puppeteer.use(StealthPlugin());
						this.loginBrowser = await puppeteer.launch({
							headless: false,
							executablePath: this.initPath(),
							args: ['--window-size=1280,800'],
							userDataDir: userDataDir, 
						});
						const page = await this.loginBrowser.newPage();
						await page.setViewport({ width: 1280, height: 800 });
						
						await page.evaluateOnNewDocument(() => {
						    const newProto = navigator.__proto__;
							delete newProto.webdriver;
							navigator.__proto__ = newProto;
							
							window.navigator.chrome = {
								runtime: {}
							};
						});
						await page.goto(url, {waitUntil : 'networkidle2'});
					}catch(e){
						this.showError(e);
					}
				})();
			},
	
			// 开始解析
			async startParsing(){
				if(this.formatUrl.trim()){
					let formatUrl = this.formatUrl.trim();
					if(formatUrl.indexOf('http://') > -1){
						formatUrl = formatUrl.replace('http://', 'https://');
					}
					
					if(formatUrl.indexOf('https://') == -1){
						this.$message.error('错了哦，请输入正确的视频地址(https://开头)');
						return false;
					}
					let arr = formatUrl.split('https://');
					formatUrl = 'https://' + arr[1];
					this.downloadUrl = formatUrl;
					
					const regex = /https:\/\/.*?.douyin.com/;
					const res = regex.exec(formatUrl);
					this.bUrl = true;
					if(res && res.length > 0){ //抖音视频解析，使用puputter
						this.selectIndex = -1;
						this.videoList = [];
						let reg2 = /[?&]modal_id=(\w+)/;
						let res2 = reg2.exec(formatUrl);
						if(res2){
							let modal_id = res2[1];
							formatUrl = res[0] + '/video/'+modal_id;
							this.downloadUrl = formatUrl;
						}
						this.douyinParsing(formatUrl);
						return false;
					}
					
					this.parseLoading = true;
					this.tabLoading = true;
					this.selectIndex = -1;
					this.videoList = [];
					let userAgent = [];
					let setingAgent = '';
					if(formatUrl.indexOf('weibo.com/') > -1 && setingAgent){
						userAgent = [
							'--add-header',
							'User-Agent:'+setingAgent,
							'--add-header',
							"Referer:https://weibo.com/"
						];
					}
					let params = [
						'--no-playlist',
						'--dump-json',
						...userAgent,
						formatUrl
					];
					electronApi.spawnExec(['dlp.exe', ...params]).then(res => {
						this.parseLoading = false;
						this.tabLoading = false;
						let info = res.stdout ? res.stdout.toString() : '{formats: []}';
						this.videoInfo = JSON.parse(info);
						this.videoList = this.videoInfo.formats || [];
						const bregex = /https:\/\/.*?.bilibili.com/;
						const bres = bregex.exec(formatUrl);
						if(bres && bres.length > 0){ //b站的视频
							this.bUrl = false;
						}else{
							this.bUrl = true;
						}
						this.biliAudioList = [];
						this.biliAudioIndex = -1;
						this.biliVideoList = [];
						this.biliVideoIndex = -1;
						this.videoList.map(item => {
							item.title = this.videoInfo.title,
							item.status = '1';
							if(!this.bUrl){ // b站的视频
								if(item.resolution.indexOf('audio') > -1 || item.audio_ext != 'none'){
									this.biliAudioList.push(item);
								}else{
									this.biliVideoList.push(item);
								}
							}
						})
					}).catch(err =>{
						this.parseLoading = false;
						this.tabLoading = false;
						// console.log('err1',err.stderr.toString());
						let errStr = err.stderr.toString();
						this.bUrl = true;
						if(errStr.indexOf('Unsupported URL') > -1){
							this.videoParsing(formatUrl);
							return false;
						}else if(formatUrl.indexOf('xiaohongshu.com/') > -1 && errStr.indexOf('No video formats') > -1){
							this.$notify.error({
								title: '设置中登录小红书账号下载！',
								message: errStr
							});
							this.videoParsing(formatUrl);
							return false;
						}else{
							this.$notify.error({
								title: '网址解析失败！',
								message: errStr
							});
						}
					})
				}
			},
			// 复制链接地址
			copyText(text){
				navigator.clipboard.writeText(text).then(() => {
					this.$message({message: '视频下载链接已成功复制到剪贴板', type: 'success'});
				}).catch(err => {
					this.$message.error('无法复制文本', err.toString());
				});
			},
			// 点击复制
			copy(index){
				this.commonUrl = '';
				this.thunderUrl = [];
				let tag = this.videoList[index].tag;
				let urlList = this.videoList[index].urlList;
				let title =  this.videoList[index].title;
				let text = urlList[0];
				if(urlList.length <= 0){
					this.$message.error('无法复制下载地址');
					return false;
				}
				if(tag == 'douyin'){
					this.dyModal = true;
					this.dyIndex = index;
					
					urlList.map(uitem => {
						if(uitem.startsWith('https://www.douyin.com/')){
							this.commonUrl = uitem;
						}
						if(!title){
							title = '抖音视频';
						}
						// console.log(`AA`+uitem +`&filename=`+title+`.mp4ZZ`);
						let urlBuffer = Buffer.from(`AA`+uitem +`&filename=`+title+`.mp4ZZ`).toString('base64');
						this.thunderUrl.push('thunder://'+urlBuffer);
					})
				}else{
					this.copyText(text);
				}
			},
			
			// 解析抖音视频
			async douyinParsing(url){
				if(this.loginBrowser){
					await this.loginBrowser.close();
					this.loginBrowser = null;
				}
				if(this.videoBrowser){
					await this.videoBrowser.close();
					this.videoBrowser = null;
				}
				if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture-video')) {
					fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture-video');
				}
				
				this.parseLoading = true;
				this.tabLoading = true;
				
				setTimeout(()=> {
					this.parseLoading = false;
					this.tabLoading = false;
				}, 20000)
				
				let userDataDir = os.tmpdir() + separator + 'chrome-data-capture-video';
				// 运行不同平台的浏览器
				puppeteer.use(StealthPlugin());
				let headless = true;
				headless = this.initDevelop().headless;
				this.videoBrowser = await puppeteer.launch({
					headless: headless,
					executablePath: this.initPath(),
					userDataDir: userDataDir, 
					args: [
						'--start-maximized',
						'--no-sandbox',
						'--disable-setuid-sandbox',
						'--disable-blink-features=AutomationControlled',
					]
				});
				
				await new Promise((resolve,reject) =>{
					(async () => {
						try{
							let authority = this.$refs.headerRef.authority.isAuthority;
							const page = await this.videoBrowser.newPage();
							
							let responseVideo = [];
							let responseUrl = [];
							let responseObj = {};
							let vtitle = '视频';
							page.on('response', async(response) => {
								// 检查响应的 MIME 类型是否以 'video/' 开头
								if (response.headers()['content-type'] && response.headers()['content-type'].startsWith('video/')) {
									if(responseVideo.indexOf(response.url()) < 0 && !response.url().startsWith('blob:https://')){
										responseVideo.push(response.url());
										vtitle = await page.title();
										if(vtitle){
											vtitle = vtitle.substring(0, 50);
											if(this.containsAnyChar(vtitle)){  //判断是否含有特殊字符
												vtitle = vtitle.replace(/[\\/:*?"<>|#%&\s]/g, "");
											}
										}
									}
								}
								if (response.headers()['content-type'] && response.headers()['content-type'].startsWith('application/json')) {
									if(response.url().indexOf('/aweme/detail/') > -1){
										if(responseUrl.indexOf(response.url()) < 0){
											responseUrl.push(response.url());
										}else{
											return false;
										}
										
										let jsonText = await response.text();
										if(jsonText && typeof jsonText == 'string'){
											responseObj = JSON.parse(jsonText);
										}
									}
								}
								
							});
							let waitUntil = 'networkidle2';
							waitUntil = this.initDevelop().waitUntil;
							await page.goto(url, {waitUntil : waitUntil});
							await page.waitForTimeout(1000);
							await this.videoBrowser.close();
							
							if(responseObj['aweme_detail']){ // 返回的接口数据中有aweme_detail参数 才会解析接口数据
								let arr = ['aweme_detail']; //'video' ,'play_addr', 'url_list', '2'];
								for(let i = 0; i < arr.length; i++){
									responseObj = responseObj[arr[i]];
								}
								
								if(responseObj && responseObj.preview_title){
									responseObj.preview_title = responseObj.preview_title.substring(0, 50);
									if(this.containsAnyChar(responseObj.preview_title)){  //判断是否含有特殊字符
										responseObj.preview_title = responseObj.preview_title.replace(/[\\/:*?"<>|#%&\s]/g, "");
									}
								}
								if(responseObj && responseObj.video && responseObj.video.play_addr){
									let vinfo = {
										title: responseObj.preview_title,
										tag: 'douyin',
										format_id: 'default',
										ext: 'mp4',
										resolution: responseObj.video.play_addr.width + 'x' + responseObj.video.play_addr.height,
										fps: '-',
										filesize: responseObj.video.play_addr.data_size, 
										vcodec: '-',
										acodec: '-',
										urlList: responseObj.video.play_addr.url_list,
										status: '1',
										loading: false
									}
									this.videoList.push(vinfo);
								}
								if(responseObj && responseObj.video && responseObj.video.play_addr_265){
									let vinfo = {
										title: responseObj.preview_title,
										tag: 'douyin',
										format_id: 'play_addr_265',
										ext: 'mp4',
										resolution: responseObj.video.play_addr_265.width + 'x' + responseObj.video.play_addr_265.height,
										fps: '-',
										filesize: responseObj.video.play_addr_265.data_size,
										vcodec: '-',
										acodec: '-',
										urlList: responseObj.video.play_addr_265.url_list,
										status: '1',
										loading: false
									}
									this.videoList.push(vinfo);
								}
								if(responseObj && responseObj.video && responseObj.video.play_addr_h264){
									let vinfo = {
										title: responseObj.preview_title,
										tag: 'douyin',
										format_id: 'play_addr_h264',
										ext: 'mp4',
										resolution: responseObj.video.play_addr_h264.width + 'x' + responseObj.video.play_addr_h264.height,
										fps: '-',
										filesize: responseObj.video.play_addr_h264.data_size,
										vcodec: '-',
										acodec: '-',
										urlList: responseObj.video.play_addr_h264.url_list,
										status: '1',
										loading: false
									}
									this.videoList.push(vinfo);
								}
							}else if(responseVideo.length > 0){ //网页解析到视频地址
								let vinfo = {
									title: vtitle,
									tag: 'douyin',
									format_id: 'video',
									ext: 'mp4',
									resolution: '-',
									fps: '-',
									filesize: '',
									vcodec: '-',
									acodec: '-',
									urlList: responseVideo,
									status: '1',
									loading: false
								}
								this.videoList.push(vinfo);
							}
							
							
							
							this.parseLoading = false;
							this.tabLoading = false;
						}catch(e){
							this.parseLoading = false;
							this.tabLoading = false;
							reject(e);
							this.showError(e);
						}
					})();
				});
				
			},
			
			// 下载网址链接的图片
			async downloadImage(imageUrl, outputPath, urlInfo) {
				let _this = this;
				let received_bytes = 0;
				let total_bytes = 0;
				try {
					let req = request({
					    method: 'GET', uri: imageUrl, strictSSL: false
					});
					let out = fs.createWriteStream(outputPath);
					req.pipe(out);
					
					return new Promise((resolve, reject) => { 
						req.on('response', (data) => {
							total_bytes = parseInt(data.headers['content-length']);
							const status = data.statusCode;
							if(this.menuIndex != '1'){
								if (status < 200 || status >= 300) {
									this.$notify.error({
										title: '网络资源访问异常！- 1',
										message: imageUrl.slice(0,50)
									});
								}else if(isNaN(total_bytes)){
									this.$notify.error({
										title: '网络资源访问异常！- 2',
										message: imageUrl.slice(0,50)
									});
								}else{
									// console.log('下载中...')
								}
							}
							
							if(status == 403 || isNaN(total_bytes)){
								fs.unlinkSync(outputPath);
								urlInfo.status = '4';
							}
							
						});

						req.on('data', (chunk) => {
						    received_bytes += chunk.length;
							if(urlInfo.filesize){
								let size = Number(urlInfo.filesize);
								let percent = Number(received_bytes / size * 100);
								urlInfo.percent = percent.toFixed(2);
								if(percent > 100){
									urlInfo.percent = 100;
								}
								this.$forceUpdate();
							}
						});
						
						req.on('end', ()=> {
							urlInfo.status = '3';
							//console.log('下载完成', outputPath)
							resolve(true);
						});
					});
			    } catch (error) {  
					urlInfo.status = '4';
			        console.error(imageUrl, `Failed to download image: ${error.message}`);  
			        throw error;  
			    }  
			},
			
			// 获取页面标题 - 生成对应的文件夹
			async getTitle(page, urlInfo){
				// 已页面标题作为新建文件夹,保留前50个字
				let title = await page.title();
				if(title){
					title = title.substring(0, 50);
					if(this.containsAnyChar(title)){  //判断是否含有特殊字符
						title = title.replace(/[\\/:*?"<>|#%&\s]/g, "");
					}
					if (fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName + separator + title)) {
						urlInfo.newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + title;
					} else {
						fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName + separator + title);
						urlInfo.newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + title;
					}
				}
			},
			
			// 下载base64位的图片
			async downloadBaseImage(base64String, outputPath, urlInfo) {
				const buffer = Buffer.from(base64String, 'base64');
				const writeStream = fs.createWriteStream(outputPath);
				writeStream.write(buffer);  
				writeStream.end();
				writeStream.on('finish', () => {
					urlInfo.num += 1;
				});
				// 监听错误事件  
				writeStream.on('error', (err) => {  
					console.error('base64位写入文件时出错:', err);  
				});
			},
			
			// 错误提示
			showError(e){
				let str = '';
				if(e.toString().indexOf('ERR_NAME_NOT_RESOLVE') > -1){
					str = '无法解析该网址，请查看网址是否正确！-1';
				}else if(e.toString().indexOf('Cannot navigate to invalid URL') > -1){
					str = '无效的网址，请查看网址格式是否正确！-2';
				}else if(e.toString().indexOf('ERR_CONNECTION_TIMED_OUT') > -1){
					str = '链接请求超时，请查看网络状态！-3';
				}else if(e.toString().indexOf('TimeoutError') > -1){
					str = '链接请求超时，请查看网络状态！-4';
				}else if(e.toString().indexOf('operation not permitted') > -1){
					str = '权限受限，请以管理员权限运行软件！-5';
				}else if(e.toString().indexOf('browser has disconnected') > -1){
					str = '内置浏览器已关闭！-6';
				}else if(e.toString().indexOf('Failed to launch the browser') > -1){
					str = '请先关闭内置浏览器！-7';
				}else{
					str = e.toString();
					//console.log(e);
				}
				this.loading = false;
				this.$notify.error({
					title: '提示',
					message: str
				});
			},
			
			// 是否包含特殊字符
			containsAnyChar(str) {
				let charsArray = ['\\', '/', ':', '*', '?', '"', '<', '>', '|', '#', '%' ,'&', ' ', '\t', '\n'];
			    for (let i = 0; i < charsArray.length; i++) {
			        if (str.includes(charsArray[i])) {  
			            return true;
			        }  
			    }  
			    return false; 
			},
			
			// 随机生成字符
			randomString(length) {  
			    let result  = '';  
			    const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';  
			    const charactersLength = characters.length;  
			    for (let i = 0; i < length; i++ ) {
			       result += characters.charAt(Math.floor(Math.random() * charactersLength));  
			    }  
			    return result;  
			},
			
			//
			formatSeconds(value) {
				var secondTime = parseInt(value); // 秒
				var minuteTime = 0; // 分
				var hourTime = 0; // 小时
				if (secondTime >= 60) {
					minuteTime = parseInt(secondTime / 60);
					secondTime = parseInt(secondTime % 60);
					if (minuteTime >= 60) {
						hourTime = parseInt(minuteTime / 60);
						minuteTime = parseInt(minuteTime % 60);
					}
				}
			
				var result ="" +(parseInt(secondTime) < 10? "0" + parseInt(secondTime): parseInt(secondTime));
				result ="" + (parseInt(minuteTime) < 10? "0" + parseInt(minuteTime) : parseInt(minuteTime)) + ":" + result;
				result ="" + (parseInt(hourTime) < 10 ? "0" + parseInt(hourTime): parseInt(hourTime)) +":" + result;
				return result;
			},
			
			// 视频时间转为秒
			getSs(rawDuration){
				const $ar = rawDuration.split(":");
				let $duration = parseFloat($ar[2]);
				if ($ar[1]) $duration += parseInt($ar[1]) * 60;
				if ($ar[0]) $duration += parseInt($ar[0]) * 60 * 60;
				
				return $duration;
			},
			
		}
	};
</script>

<style lang="scss">
	@import "../assets/css/fontx/iconfont.css";
	@import "../assets/css/home.scss";

	.ivu-input-number-controls-outside-btn i {
		font-weight: 800;
	}

	.update-point {
		display: inline-block;
		width: 8px;
		height: 8px;
		border-radius: 8px;
		background: #ff0000;
		top: 14px;
		position: absolute;
		left: -13px;
	}

	.menu-item {
		padding: 8px 0;
		font-size: 14px;

		.iconfont {
			font-size: 32px;
		}

		&:hover,
		&.active {
			color: #ed4014;
		}
	}

	.ivu-progress-show-info .ivu-progress-outer {
		padding-right: 40px !important;
		margin-right: -40px !important;
	}

	.tips {
		text-align: center;
		padding: 10px 0;
		color: #ed4014;
		font-size: 12px;
	}

	.handle-desc {
		display: inline-block;
		width: calc(100% - 100px);
		overflow: hidden;
	}

	.ivu-menu-submenu-title {
		font-weight: 600;
	}

	.ivu-menu .ivu-menu-item {
		line-height: 1;
	}

	// new-el
	.el-menu {
		border-right: none !important;
	}

	.cmenu-item {
		padding: 0 20px 20px;
		margin-bottom: 15px;

		.cmenu-title {
			font-size: 18px;
			font-weight: 600;
			padding-bottom: 20px;
		}

		.citem-nav {
			text-align: center;
			border-radius: 10px;
			min-height: 110px;
			padding: 15px 0;
			background-color: #fff;
			font-size: 15px;
			cursor: pointer;

			&.bg-linear1 {
				color: #fff;
				font-size: 20px;
				background: linear-gradient(to right bottom, #2A56CA, #5795F4);
			}

			&.bg-linear2 {
				color: #fff;
				font-size: 20px;
				background: linear-gradient(to right top, #147FBB, #5EB3E3);
			}

			&.bg-linear3 {
				color: #fff;
				font-size: 20px;
				background: linear-gradient(to right bottom, #2F9E8A, #56CDB1);
			}

			&:hover {
				margin-top: -5px;
				box-shadow: 3px 3px 6px #ccc, -3px -3px 6px #ccc;
			}

			.citem-img {
				width: 50px;
				margin-bottom: 10px;
			}
		}
	}
	
	.popper-open{
		text-align: center !important;
		padding: 10px !important;
		background: #303133 !important;
		color: #fff !important;
		min-width: 120px !important;
		opacity: 0.8;
	}
	
	.popper-open[x-placement^=bottom] .popper__arrow::after{
		border-bottom-color: #303133 !important;
	}
	
	textarea.el-textarea__inner{
		height: 100% !important;
		font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;
	}
	
	.set-item{
		margin-right: 15px;
		
		.set-title{
			font-size: 13px;
		}
	}
	
	.outarea{
		height: 100%;
		border: 1px solid #DCDFE6;
		background-color: #4851a415; 
		padding: 15px;
		font-size: 20px;
		overflow: hidden auto;
	}
	
	.outtext{
		height: 100%;
		font-size: 20px;
		overflow: hidden auto;
		
		textarea{
			background-color: #4851a415; 
		}
	}
	
	.pin-tips{
		font-size: 14px;
		position: absolute;
		bottom: 10px;
		color: #ff0000;
		left: 0;
		right: 0;
		margin: auto;
		text-align: center;
	}
	
	.outarea.red-border{
		border: 1px solid #F56C6C;
	}
	
	.outtext.red-border textarea{
		border: 1px solid #F56C6C;
	}
	
	h3{
		margin: 0;
	}
	
	.m-image{
		width: 20px;
		margin-right: 5px;
	}
	
	.dialog-footer-center{
		text-align: center;
	}
	
	.visible-tips-style{
		font-size: 18px; 
		color: #f73131; 
		font-weight: 600; 
		padding: 30px 40px 0;
	}
	
	.no-select{
		user-select: none; 
	}
	
	.tips-flex{
		display: flex;
		flex-wrap: nowrap;
		justify-content: space-around;
		align-items: center;
		
		.el-icon-s-opportunity{
			font-size: 50px;
			color: #f73131;
			margin-right: 10px;
		}
		
		.m-title{
			flex: 1;
			color: #f73131;
		}
	}
	
	.c-titles{
		background: -webkit-linear-gradient(left, #FF993F, #FFCE7C 25%, #FF9682 50%, #8e430d 75%, #FF993F);
		color: transparent;
		-webkit-background-clip: text;
		background-size: 200% 100%;
		animation: mask-ani 6s infinite linear;
		font-size: 30px;
		font-weight: 600;
		line-height: 1.5;
	}
	
	@-webkit-keyframes mask-ani {
	    0% {
	        background-position: 0 0;
	    }
	
	    50% {
	        background-position: 100% 0;
	    }
	
	    100% {
	        background-position: 200% 0;
	    }
	}
	
	.soft-icon{
		margin: 0 3px;
	}
	
	.el-upload-list{
		display: none;
	}
	
</style>