qiushang 1 hónapja
szülő
commit
4f80172bc6

BIN
build/icons/256x256.png


BIN
build/icons/icon.icns


BIN
build/icons/icon.ico


BIN
build/icons/icon1.ico


BIN
nsis/logo.ico


BIN
nsis/skin/icon.ico


+ 1 - 1
package.json

@@ -9,7 +9,7 @@
 		"description": "这里是软件描述文档",
 		"downloadName": "XYLinks",
 		"softMid": "EkoFCqqaUJXy",
-		"softName": "星优视频解析下载器",
+		"softName": "星优链接复制器",
 		"copyright": "苏州星优办公软件有限公司",
 		"popupAdvId": "45",
 		"linkId": "46",

BIN
src/renderer/assets/image/icon.png


+ 43 - 50
src/renderer/components/header.vue

@@ -126,7 +126,7 @@
 		</el-dialog>
 		
 		<!-- 软件设置 -->
-		<el-dialog title="软件设置" :visible.sync="settingModal" width="400px">
+		<el-dialog title="软件设置" :visible.sync="settingModal" width="400px" :close-on-click-modal="false">
 			<div>
 				<el-divider content-position="left">
 					账号登录
@@ -141,22 +141,24 @@
 					<el-button size="mini" @click="toLogin('red')" :loading="redLoading">小红书</el-button>
 				</el-row>
 				<el-divider content-position="left">
-					浏览器选择 
-					<el-popover placement="bottom" popper-class="popper-open" trigger="hover" content="用户可使用本地电脑的谷歌/Edge浏览器或软件内置的浏览器">
+					浏览器启动地址 
+					<el-popover placement="bottom" popper-class="popper-open" trigger="hover" content="仅支持谷歌浏览器/和基于Chromium的Microsoft Edge浏览器">
 						<i class="el-icon-info" slot="reference" style="margin-left: 10px; color: #F56C6C;"></i>
 					</el-popover>
 				</el-divider>
-				<el-row style="text-align: center;">
+				<!-- <el-row style="text-align: center;">
 					<el-radio-group v-model="chromeType">
-					    <el-radio :label="1">电脑浏览器</el-radio>
-					    <el-radio :label="2">内置浏览器</el-radio>
+					    <el-radio :label="1">本地电脑浏览器</el-radio>
+					    <el-radio :label="2">软件内置浏览器</el-radio>
 					</el-radio-group>
+				</el-row> -->
+				<el-row style="text-align: center; margin-top: 10px;">
+					<el-input size="small" v-model="chromePath" placeholder="请输入本地Chrome/Edge浏览器启动地址" clearable></el-input>
+					<div>
+						<el-link @click="chromeHelp('https://www.xingyousoft.com/news/detail/Z80IPpNVNNC1')" type="danger" style="text-decoration: underline; font-size: 12px;" :underline="false">查看如何输入地址</el-link>
+					</div>
 				</el-row>
-				<el-row style="text-align: center; margin-top: 10px;" v-if="chromeType == 1">
-					<el-input size="small" v-model="chromePath" placeholder="请输入本地Chrome/Edge浏览器启动地址" style="width: 75%;" clearable></el-input>
-					<el-link @click="chromeHelp('https://www.xingyousoft.com/news/detail/Z80IPpNVNNC1')" type="danger" style="text-decoration: underline; font-size: 12px;" :underline="false">查看如何输入</el-link>
-				</el-row>
-				<el-divider content-position="left">
+				<!-- <el-divider content-position="left">
 					内置浏览器版本
 					<el-popover placement="bottom" popper-class="popper-open" trigger="hover" content="win10以下版本(不含win10),请使用兼容版本的浏览器">
 						<i class="el-icon-info" slot="reference" style="margin-left: 10px; color: #F56C6C;"></i>
@@ -167,36 +169,16 @@
 					    <el-radio :label="1">兼容版本</el-radio>
 					    <el-radio :label="2">最新版本</el-radio>
 					</el-radio-group>
-				</el-row>
+				</el-row> -->
 				<el-divider content-position="left">
-					任务间隔时间
-					<el-popover placement="bottom" popper-class="popper-open" trigger="hover" content="默认为1秒,加大下载间隔时间减少访问频率,降低风控风险">
+					分页间隔时间
+					<el-popover placement="bottom" popper-class="popper-open" trigger="hover" content="默认为5秒,加大下载间隔时间减少访问频率,降低风控风险">
 						<i class="el-icon-info" slot="reference" style="margin-left: 10px; color: #F56C6C;"></i>
 					</el-popover>
 				</el-divider>
 				<el-row style="text-align: center;">
 					<el-input-number v-model="gap" :min="1" :max="60" label="间隔时间" size="mini" style="margin-right: 5px;"></el-input-number>秒
 				</el-row>
-				<el-divider content-position="left">
-					页面滚动速度
-					<el-popover placement="bottom" popper-class="popper-open" trigger="hover" content="默认600ms,本地网路访问速度快可选择短时间,时间越长处理任务的时间也越长">
-						<i class="el-icon-info" slot="reference" style="margin-left: 10px; color: #F56C6C;"></i>
-					</el-popover>
-				</el-divider>
-				<el-row style="text-align: center;">
-					<el-select v-model="pageMs" placeholder="请选择时间" size="mini" style="width: 100px; margin-right: 5px;">
-						<el-option :value="300"></el-option>
-						<el-option :value="400"></el-option>
-						<el-option :value="500"></el-option>
-						<el-option :value="600"></el-option>
-						<el-option :value="700"></el-option>
-						<el-option :value="800"></el-option>
-						<el-option :value="900"></el-option>
-						<el-option :value="1000"></el-option>
-						<el-option :value="1200"></el-option>
-						<el-option :value="1400"></el-option>
-					</el-select>毫秒
-				</el-row>
 				<el-divider content-position="left">清理缓存</el-divider>
 				<el-row style="text-align: center;">
 					<el-button size="small" type="primary" @click="clearCache()" :loading="cacheLoading">点击清除软件缓存</el-button>
@@ -218,16 +200,7 @@
 		<el-dialog title="开发者模式" :visible.sync="developerModal" width="400px" :close-on-click-modal="false" :close-on-press-escape="false">
 			<div>
 				<p style="text-align: center; color: #F56C6C;">开发者参数设置,软件退出后会重置</p>
-				<p style="text-align: center; color: #F56C6C;">(无头模式:true|网络连接:networkidle2)</p>
-				<el-divider content-position="left">
-					无头模式
-				</el-divider>
-				<el-row style="text-align: center;">
-					<el-radio-group v-model="headless">
-					    <el-radio :label="1">true</el-radio>
-					    <el-radio :label="2">false</el-radio>
-					</el-radio-group>
-				</el-row>
+				<p style="text-align: center; color: #F56C6C;">(网络连接:networkidle2)</p>
 				<el-divider content-position="left">网络连接</el-divider>
 				<el-row style="text-align: center;">
 					<el-radio-group v-model="waitUntil">
@@ -288,7 +261,7 @@
 				versionType: 2,
 				chromeType: 2,
 				chromePath: '',
-				gap: 1,
+				gap: 5,
 				pageMs: 600,
 				//
 				productName: pjson.softInfo.softName,
@@ -357,6 +330,16 @@
 				this.userInfo = this.$utils.getStorage('userInfo');
 			}
 			
+			if(!this.$utils.getStorage('chromeType')){
+				for(let i = 0; i<this.edgePath.length; i++){
+					if (fs.existsSync(this.edgePath[i])) {
+						this.$utils.setStorage('chromeType', 1);
+						this.$utils.setStorage('chromePath', this.edgePath[i]);
+						break;
+					}
+				}
+			}
+			
 			window.addEventListener('message', e => {
 				if (e.origin === 'https://www.xingyousoft.com') {
 					if(e.data.userInfo){ // 返回用户信息
@@ -411,6 +394,14 @@
 			})
 		},
 		methods: {
+			// 打开浏览器
+			chromeHelp(url){
+				// 打开浏览器
+				const {
+					shell
+				} = require('electron');
+				shell.openExternal(url);
+			},
 			// 清空缓存
 			clearCache(){
 				this.$confirm('此操作将清除软件缓存, 后续账号需要重新登录,是否继续?', '提示', {
@@ -421,9 +412,13 @@
 					this.cacheLoading = true;
 					let closeFlag = true;
 					setTimeout(() => {
-						let path = os.tmpdir() + '\\' + 'chrome-data-capture-video';
+						let path1 = os.tmpdir() + '\\' + 'chrome-data-capture';
+						let path2 = os.tmpdir() + '\\' + 'chrome-data-capture-jd';
+						let path3 = os.tmpdir() + '\\' + 'chrome-data-capture-local';
 						try{
-							this.deleteFolder(path, false);
+							this.deleteFolder(path1, false);
+							this.deleteFolder(path2, false);
+							this.deleteFolder(path3, false);
 						}catch(e){
 							this.cacheLoading = false;
 							if(e.toString().indexOf('operation not permitted') > -1){
@@ -476,8 +471,6 @@
 					url = 'https://login.taobao.com';
 				}else if(type == 'red'){
 					url = 'https://www.xiaohongshu.com';
-				}else if(type == 'pdd'){
-					url = 'https://mobile.yangkeduo.com/personal.html';
 				}
 				this[type + 'Loading'] = true;
 				setTimeout(() => {
@@ -529,7 +522,7 @@
 			saveSetting(){
 				this.saveLoading = true;
 				if(this.chromeType == 1){ // 用户选择电脑本地的浏览器使用
-					let chromePath = this.chromePath.replace(/"/g, "");
+					let chromePath = this.chromePath.replace(/^["']|["']$/g, '');
 					if(!chromePath.endsWith('.exe') || /[\u4e00-\u9fff]/.test(chromePath)){ //判断文件路径结尾而且不包含中文
 						this.$notify({
 							title: '提示',

+ 0 - 1312
src/renderer/components/home-s.vue

@@ -1,1312 +0,0 @@
-<template>
-	<div>
-		<el-container style="height: 100vh;">
-			<!-- #333744 -->
-			<el-aside width="180px" style="user-select: none; border-right: 1px solid #fafafa; background-color: #333744; overflow-x: hidden;">
-				<p class="soft-name" style="-webkit-app-region: drag; color: #fff;">
-					<img src="../assets/image/icon.png" class="soft-icon" />
-					<span style="letter-spacing: 1px;">{{productName}}</span>
-				</p>
-				
-				<el-menu :default-openeds="['a']" :default-active="menuIndex" @select="setMenuIndex" active-text-color="#409EFF" background-color="#333744" text-color="#fff" style="margin-top: 10px;">
-					<el-submenu index="a">
-						<template slot="title"><img src="../assets/image/m-download.png" class="m-image"/>图片下载</template>
-						<el-menu-item index="1">
-							<img src="../assets/image/m-douyin.png" class="m-image"/><span slot="title">抖音</span>
-						</el-menu-item>
-						<el-menu-item index="2">
-							<img src="../assets/image/m-kuaishou.png" class="m-image"/><span slot="title">快手</span>
-						</el-menu-item>
-						<el-menu-item index="3">
-							<img src="../assets/image/m-weibo.png" class="m-image"/><span slot="title">微博</span>
-						</el-menu-item>
-						<el-menu-item index="10">
-							<img src="../assets/image/m-chrome.png" class="m-image"/><span slot="title">其他(Beta)</span>
-						</el-menu-item>
-					</el-submenu>
-				</el-menu>
-			</el-aside>
-			
-			<el-container>
-				<el-header height="45px" style="background-color: #fafafa; padding: 0 10px;">
-					<soft-header ref="headerRef" @update-soft="updateSoft()" @export-file="exportFile" @login-url="loginUrl" @clear-cache="clearCache"></soft-header>
-				</el-header>
-								
-				<el-main ref="el-main" style="background-color: #fafafa;">
-					<template>
-						<div class="content-top">
-							<div>
-								<el-button-group>
-									<el-button type="primary" size="mini" icon="el-icon-circle-plus-outline"
-										@click="addVisible = true;">添加链接</el-button>
-									<el-button type="primary" size="mini" icon="el-icon-upload"
-										@click="pickLink()">导入链接</el-button>
-									<el-button type="primary" size="mini" icon="el-icon-delete"
-										@click="clearList()">清空链接</el-button>
-								</el-button-group>
-								
-								<el-link type="info" style="margin-left: 20px; vertical-align:baseline; font-size: 12px;" @click="downloadExample()">导入模板下载<i class="el-icon-download"></i></el-link>
-							</div>
-							
-							<el-row type="flex" style="align-items: center;">
-								<div class="set-item">
-									<span class="set-title">保存目录:</span>
-									<el-input :title="downloadDir" ref="upload-input" size="mini" @focus="pickPath" placeholder="请选择输出目录" v-model="downloadDir" readonly style="width:200px;" 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>
-								</div>
-								
-								<el-button type="danger" @click="exportFile()" :loading="loading">开始下载</el-button>
-							</el-row>
-						</div>
-						
-						<div style="padding: 20px 20px 0 20px; height: calc(100% - 62px);">
-							<el-row type="flex" justify="space-between">
-								<div>
-									<h3 style="display: inline-block;">
-										<span v-if="menuIndex == '1'">抖音 - </span>
-										<span v-if="menuIndex == '2'">快手 - </span>
-										<span v-if="menuIndex == '3'">微博 - </span>
-										<span v-if="menuIndex == '10'">网页 - </span>
-										视频下载
-									</h3>
-									<!-- <el-popover placement="bottom" popper-class="popper-open" trigger="hover" content="下载类型至少选一个,评论图默认只下载商品首页展示的评论内容">
-										<i class="el-icon-info" slot="reference" style="margin-right: 10px; color: #F56C6C;"></i>
-									</el-popover> -->
-									<el-link v-if="menuIndex != '10'" :underline="false" type="danger" style="text-align: center; font-size: 12px;">
-										不支持win7及以下系统
-									</el-link>
-									<el-link v-if="menuIndex == '10'" :underline="false" type="danger" style="text-align: center; font-size: 12px;">
-										非会员功能,仅提供测试
-									</el-link>
-									
-								</div>
-							</el-row>
-						
-							<div class="table-scroll" style="padding-top: 30px; height: calc(100% - 31px);">
-								<!-- 1、 -->
-								<vxe-table 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 type="seq" width="60"></vxe-column>
-									<vxe-column field="title" title="目录名称" width="200">
-										<template #default="{ row, rowIndex }">
-											<span v-if="row.title">{{row.title}}</span>
-											<el-tag size="mini" v-else>默认使用网页标题</el-tag>
-										</template>
-									</vxe-column>
-									<vxe-column field="url" title="网页链接"></vxe-column>
-									<vxe-column field="status" title="下载状态" width="200">
-										<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-loading" style="font-size: 16px; color: #999;"></i>
-												<span>任务处理中...</span>
-											</template>
-											<template v-if="row.status == '3'">
-												<i class="el-icon-loading" style="font-size: 16px; color: #999;"></i>
-												<span>视频下载中..</span>
-											</template>
-											<template v-if="row.status == '4'">
-												<i class="el-icon-success" style="font-size: 16px; color: #19be6b;"></i>
-												<span>下载完成</span>
-											</template>
-											<template v-if="row.status == '5'">
-												<i class="el-icon-error" style="font-size: 16px; color: #ed4014;"></i>
-												<span>网络异常,请重试!</span>
-											</template>
-										</template>
-									</vxe-column>
-									<vxe-column title="操作" width="80">
-										<template #default="{ row, rowIndex }">
-											<i class="el-icon-delete cur-pointer" style="font-size: 20px;" @click="delFile(rowIndex)"></i>
-										</template>
-									</vxe-column>
-								</vxe-table>
-							</div>
-						</div>
-			
-					</template>
-								
-					<el-dialog title="添加链接" :visible.sync="addVisible" width="500px" :close-on-click-modal="false" :close-on-press-escape="false" :show-close="false">
-						<div>
-							<el-form label-position="right" label-width="80px" :rules="rules" :model="formData" ref="formData">
-								<el-form-item label="目录名称" prop="title">
-									<el-input v-model="formData.title" placeholder="为空则默认使用网页标题前50个字符"></el-input>
-								</el-form-item>
-								<el-form-item label="网页链接" prop="url">
-									<el-input type="textarea" :rows="10" v-if="menuIndex < 10" :placeholder="'(例:' + exampleUrl[menuIndex-1] + ')'" v-model="formData.url"></el-input>
-									<el-input type="textarea" :rows="10" v-else :placeholder="'请输入网址链接'" v-model="formData.url"></el-input>
-								</el-form-item>
-							</el-form>
-						</div>
-						<span slot="footer" class="dialog-footer">
-							<el-button @click="addVisible = false; $refs['formData'].resetFields();">取 消</el-button>
-							<el-button type="primary" @click="onSubmit">确 定</el-button>
-						</span>
-					</el-dialog>
-					
-					<el-dialog title="提示" :visible.sync="loginVisible" width="400px" :close-on-click-modal="false" :close-on-press-escape="false">
-						<div style="text-align: center; color: #999; font-size: 14px;">
-							<template v-if="menuIndex == '1'">
-								<p>阿里巴巴渠道建议登录后下载</p>
-								<p class="visible-tips-style">目前检测还未登录阿里巴巴账号,未登录可能会导致图片下载不全</p>
-							</template>
-							<template v-else-if="menuIndex == '2'">
-								<p>京东渠道需要登录后才能下载</p>
-								<p class="visible-tips-style">目前检测还未登录京东账号,需立即登录</p>
-							</template>
-							<template v-else-if="menuIndex == '5'">
-								<p>小红书渠道需要登录后才能下载</p>
-								<p class="visible-tips-style">目前检测还未登录小红书账号,需立即登录</p>
-							</template>
-							<template v-else>
-								<p>天猫/淘宝渠道需要登录后才能下载</p>
-								<p class="visible-tips-style">目前检测还未登录天猫/淘宝账号,需立即登录</p>
-							</template>
-							
-						</div>
-						<div slot="footer" class="dialog-footer-center">
-							<el-button v-if="menuIndex == '2'" @click="loginVisible = false; loginUrl('https://passport.jd.com/new/login.aspx')">点击登录京东账号</el-button>
-							<template v-else-if="menuIndex == '1'">
-								<el-button @click="loginVisible = false; loginUrl('https://www.1688.com')">点击登录阿里巴巴账号</el-button>
-								<el-button type="primary" @click="loginVisible = false; skipLogin = true; exportFile();">继续下载</el-button>
-							</template>
-							<el-button v-else-if="menuIndex == '5'" @click="loginVisible = false; loginUrl('https://www.xiaohongshu.com')">点击登录小红书账号</el-button>
-							<el-button v-else @click="loginVisible = false; loginUrl('https://login.taobao.com')">点击登录天猫/淘宝账号</el-button>
-						</div>
-					</el-dialog>
-					
-					<!-- 非会员转换提示框 -->
-					<el-dialog title="非会员提示" :visible.sync="tipsModal" width="400px">
-						<div class="member-model">
-							<div class="tips-flex">
-								<i class="el-icon-s-opportunity"></i>
-								<p class="m-title">{{tipsDesc}}</p>
-							</div>
-							<div class="member-btn">
-								<el-button size="small" style="margin:0 10px;" @click="exportFile(true)" round v-if="usageTimes > 0">继续试用</el-button>
-								<el-button size="small" round type="primary" @click="openVip()">开通会员</el-button>
-							</div>
-						</div>
-					</el-dialog>
-			
-				</el-main>
-				
-				<el-footer height="48px">
-					<!-- 更新 -->
-					<soft-update ref="updateRef" :showDowload="dowloadModel" :dowloadFinish="finishModel"></soft-update>
-				</el-footer>
-			</el-container>
-		</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 listNameArr = ['douyin','kuaishou','weibo','','','','','', '' ,'common'];
-	
-	let separator = '';
-	if (os.platform == 'linux') {
-		separator = '/'
-	} else {
-		separator = '\\'
-	}
-	
-	// let chromePath = process.cwd() + '\\resources\\app\\node_modules\\puppeteer\\.local-chromium\\win64-1045629\\chrome-win\\chrome.exe';
-	// if (process.env.NODE_ENV == 'development') {
-	//     chromePath = process.cwd() + '\\node_modules\\puppeteer\\.local-chromium\\win64-1045629\\chrome-win\\chrome.exe';
-	// }
-	export default {
-		name: 'landing-page',
-		components: {
-			softUpdate,
-			softHeader
-		},
-		data() {
-			return {
-				usageTimes: 3,
-				tipsModal: false,
-				tipsDesc: "试用次数已经用完,请开通VIP会员使用。",
-				settingArr: ['mainImg'],
-				loginVisible: false,
-				addVisible: false,
-				formData: {
-					title: '',
-					url: ''
-				},
-				rules:{ //   
-					title: [
-						{ min: 0, max: 50, message: '不能超过 50 个字符', trigger: 'blur' },  
-						{ pattern: /^[^\\/:*?"<>|]*$/, message: '标题中不能包含 \\ / : * ? " < > |', trigger: 'blur' } 
-					],
-					url: [
-						{ required: true, message: '请输入网页链接', trigger: 'blur' },
-						{ pattern: /^(http|https):\/\/.+$/, message: '请输入正确的网址链接(http://或https://开头)', trigger: 'blur' } 
-					],
-				},
-				tabLoading: false,
-				douyinList: [],
-				kuaishouList: [],
-				weiboList: [],
-				commonList: [],
-				productName: pjson.softInfo.softName,
-				imgUrl: this.$api.imgUrl,
-				imgSrc: '',
-				menuIndex: '1',
-				settingData: {
-					detailImg: true,
-					skuImg: true,
-					commentImg: false,
-					video: false,
-				},
-				exampleUrl: ['https://www.douyin.com  |  复制打开抖音,看看【某某某的作品】https://v.douyin.com/xxx1234/ 12/26 L@W.CD EaP:/', 
-				'https://www.kuaishou.com  |  https://v.kuaishou.com/AbcDef 春天就要出门踏春..."某某某 点击链接,打开【快手】直接观看!', 
-				'https://www.weibo.com/xxxxxx  |  请使用单个视频网址链接'],
-
-				fileList: [],
-				
-				downloadDir: os.userInfo().homedir + separator + "Downloads",
-				dowloadModel: false,
-				finishModel: false,
-
-				loading: false,
-				checkLoading: false, //点击检测登录状态
-				execLimit: 1,
-				execNum: 3, // 限制5张
-				
-				/** 浏览器名称 **/
-				videoBrowser: null,
-				loginBrowser: null, // 登录用的浏览器实例
-				skipLogin: 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"
-			}
-			
-			if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture-video')) {
-				fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture-video');
-			}
-
-			// 打开浏览器
-			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);
-				});
-			});
-			
-			let name = pjson.softInfo.softMid + pjson.name;
-			fs.stat(os.tmpdir() + separator + name, (err, stats) => {
-				if(!stats){
-					let data = 3;
-					fs.writeFile(os.tmpdir() + separator + name, data, (err) => {
-						if (err) throw err;
-					});
-				}
-			})
-			
-		},
-		methods: {
-			// 实时获取浏览器路径
-			initPath(){
-				let chromePath = puppeteer.executablePath().replace('win32-1', 'win64-1');
-				return chromePath;
-			},
-			// 删除文件夹内容
-			deleteAll(folderPath, flag) {
-				if (fs.existsSync(folderPath)) {
-					fs.readdirSync(folderPath).forEach((file, index) => {
-						var curPath = path.join(folderPath, file);
-						if (fs.lstatSync(curPath).isDirectory()) {
-							this.deleteAll(curPath, true);
-						} else {
-							fs.unlinkSync(curPath);
-						}
-					});
-					if(flag){
-						fs.rmdirSync(folderPath);
-					}
-				}
-			},
-			checkAuthority(){
-				let authority = this.$refs.headerRef.authority;
-				this.$refs.imgRef.authority = authority;
-			},
-			setMenuIndex(index){
-				this.menuIndex = index;
-				if(index.indexOf('2-') > -1){
-					let num = Number(index.split('-')[1]);
-					this.$refs.imgRef.setMenuIndex(num);
-				}
-			},
-			// 选择目录
-			pickPath() {
-				this.$refs['upload-input'].blur();
-				electronApi.call('pickDir', []).then((path) => {
-					if (path) {
-						this.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.$refs.headerRef.openVip();
-			},
-			updateSoft() {
-				this.$refs.updateRef.updateSoft();
-			},
-			// 删除文件
-			delFile(rowIndex){
-				let index = Number(this.menuIndex) - 1;
-				let type = listNameArr[index];
-				
-				this.$confirm('确认删除此行数据吗?', '提示', {
-					confirmButtonText: '确定',
-					cancelButtonText: '取消',
-					type: 'warning'
-				}).then(() => {
-					this[type+'List'].splice(rowIndex, 1);
-					if(this[type+'List'].length == 0) {
-						this.clearList();
-					}
-				}).catch(() => {
-					
-				});
-			},
-			// 清除列表
-			clearList() {
-				let index = Number(this.menuIndex) - 1;
-				this[listNameArr[index]+'List'] = [];
-			},
-			// 提交表单
-			onSubmit(){
-				this.$refs['formData'].validate((valid) => {
-					if (valid) {
-						let info = {
-							url: this.formData.url,
-							title: this.formData.title,
-							status: '1',
-							num: 0,
-							newPath: ''
-						}
-						let index = Number(this.menuIndex) - 1;
-						this[listNameArr[index]+'List'].push(info);
-						this.$refs['formData'].resetFields();
-						this.addVisible = false;
-					} else {
-						return false;
-					}
-				});
-			},
-			async pickLink() { // 导入链接
-				const spinLoad = this.$loading();
-				await electronApi.call('pickFile', ['xlsx,xls', true]).then(async (path) => {
-					spinLoad.close();
-					if(path.length > 0){
-						this.$notify({
-							title: '提示',
-							message: '导入成功',
-							type: 'success'
-						});
-						let workSheetsFromBuffer = xlsx.parse(fs.readFileSync(path[0]));
-						if(workSheetsFromBuffer && workSheetsFromBuffer.length > 0){
-							let errMsg = "";
-							workSheetsFromBuffer[0].data.map((item, index) => {
-								if(item.length > 0){
-									let ititle = '';
-									if(item[0]){
-										ititle = item[0].toString().trim();
-									}
-									
-									if(item[0] == '目录名称' && item[1] == '网页链接'){
-										return false;
-									}
-
-									if(this.containsAnyChar(ititle.toString(), ['\\', '/', ':', '*', '?', '"', '<', '>', '|'])){  //判断是否含有特殊字符
-										errMsg += "第" + (index+1) + '行-名称不能包以下字符 \\ / : * ? " < > |';
-										ititle = ititle.replace(/[\\|/|:|*|?|"|<|>||]/g, "");
-									}
-									if(item[1] == undefined){
-										errMsg += "第" + (index+1) + "行格式有误</br>";
-										item[1] = '';
-									}else if(!/^(http|https):\/\/.+$/.exec(item[1])){
-										errMsg += "第" + (index+1) + "行网址格式有误</br>";
-									}else{
-										let info = {
-											url: item[1],
-											title: ititle,
-											status: '1',
-											num: 0,
-											newPath: ''
-										}
-										let key = Number(this.menuIndex) - 1;
-										this[listNameArr[key]+'List'].push(info);
-									}
-								}
-							});
-							if(errMsg){
-								this.$notify({
-									title: '请检查文件以下问题',
-									dangerouslyUseHTMLString: true,
-									message: errMsg,
-									type: 'warning'
-								});
-							}
-						}else{
-							this.$notify({
-								title: '提示',
-								message: '格式有误,请重新导入',
-								type: 'warning'
-							});
-						}
-					}
-				});
-			},
-			// 清除缓存的后续操作
-			async clearCache(){
-				if(this.loginBrowser){
-					await this.loginBrowser.close();
-					this.loginBrowser = null;
-				}
-				
-				if(this.videoBrowser){
-					await this.videoBrowser.close();
-					this.videoBrowser = null;
-				}
-			},
-			
-			// 去登录
-			loginUrl(url){
-				(async () => {
-					try{
-						if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture-video')) {
-							fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture-video');
-						}
-						let userDataDir = os.tmpdir() + separator + 'chrome-data-capture-video';
-						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;
-						});
-						await page.goto(url, {waitUntil : 'networkidle2'});
-					}catch(e){
-						this.showError(e);
-					}
-				})();
-			},
-			
-			// 开始下载
-			async exportFile(flag) {
-				if(this.loginBrowser){
-					await this.loginBrowser.close();
-					this.loginBrowser = null;
-				}
-				if(this.videoBrowser){
-					await this.videoBrowser.close();
-					this.videoBrowser = null;
-				}
-				let authority = this.$refs.headerRef.authority.isAuthority;
-				if (!fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName)) {
-					fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName);
-				}
-				
-				let index = Number(this.menuIndex) - 1;
-				let fileList = this[listNameArr[index]+'List'];
-				
-				if(fileList.length > 0){
-					if (!authority && !flag) {
-						this.tipsModal = true;
-						let name = pjson.softInfo.softMid + pjson.name;
-						fs.readFile(os.tmpdir() + separator + name, (err, data) => {
-							if (err) throw err;
-							let num = data.toString();
-							if(['1','2','3'].indexOf(num) > -1){
-								this.usageTimes = Number(num);
-								this.tipsDesc = '您共有3次试用机会,目前剩余'+this.usageTimes+'次';
-							}else{
-								this.usageTimes = 0;
-								this.tipsDesc = '试用次数已经用完,请开通会员使用';
-							}
-						});
-						return false;
-					}
-					
-					if(!authority && flag && this.usageTimes < 1){
-						this.tipsModal = true;
-						this.tipsDesc = '试用次数已经用完,请开通会员';
-						return false;
-					}
-					
-					this.tipsModal = false;
-					this.loading = true;
-					setTimeout(() => {
-						this.loading = false;
-					}, 10000)
-					
-					if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture-video')) {
-						fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture-video');
-					}
-					
-					let taskArr = [];
-					let task = "";
-					let userDataDir = os.tmpdir() + separator + 'chrome-data-capture-video';
-					// 运行不同平台的浏览器
-					puppeteer.use(StealthPlugin());
-					this.videoBrowser = await puppeteer.launch({
-						headless: true,
-						executablePath: this.initPath(),
-						userDataDir: userDataDir, 
-						args: [
-							'--start-maximized',
-							'--no-sandbox',
-							'--disable-setuid-sandbox',
-							'--disable-blink-features=AutomationControlled',
-						]
-					});
-					
-					for(let i = 0; i < fileList.length; i++){
-						let item = fileList[i];
-						
-						if(Number(this.usageTimes) >= 1){
-							let data = Number(this.usageTimes) - 1;
-							this.usageTimes -= 1;
-							let name = pjson.softInfo.softMid + pjson.name;
-							fs.writeFile(os.tmpdir() + separator + name, data, (err) => {
-								if (err) throw err;
-							});
-						}else{
-							videoBrowser
-							return false;
-						}
-						
-						if(this.menuIndex == '1'){
-							task = this.douyinDownload(item, this.videoBrowser);
-						}else{
-							task = this.videoDownload(item, this.videoBrowser);
-						}
-					
-						if(task){
-							taskArr.push(task);
-						}
-						
-						if((i+1) % this.execLimit == 0){
-							await Promise.all(taskArr).then(result => {
-								taskArr = [];
-							}).catch(err => {
-								console.log('err'+i, err)
-							})
-						}
-					}
-					
-					if(taskArr.length > 0){
-						await Promise.all(taskArr).then(result => {
-							taskArr = [];
-						}).catch(err => {
-							// 错误文件添加到服务中
-							console.log('err',err)
-						})
-					}
-					
-					if(this.videoBrowser){
-						this.videoBrowser.close();
-						this.videoBrowser = null;
-					}
-					
-					this.loading = false;
-					// 打开文件夹
-					if(fileList.length > 0){
-						this.$message({message: '恭喜你,任务已完成!', type: 'success'});
-						electronApi.call('showItemInfolder',[this.downloadDir + separator + pjson.softInfo.softName +'\\tty.tty'])
-					}
-				}
-			},
-			
-			// 抖音视频下载
-			async douyinDownload(urlInfo, browser){
-				let task = await new Promise((resolve,reject) =>{
-					(async () => {
-						try{
-							let authority = this.$refs.headerRef.authority.isAuthority;
-							urlInfo.status = '2';
-							urlInfo.num = 0;
-							const page = await browser.newPage();
-							
-							let responseVideo = [];
-							let responseUrl = [];
-							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());
-									}
-								}
-								
-								if (response.headers()['content-type'] && response.headers()['content-type'].startsWith('application/json')) {
-									if(response.url().indexOf('/aweme/detail/') > -1){
-										console.log(response.url(), '------------111111111111111111');
-										if(responseUrl.indexOf(response.url()) < 0){
-											responseUrl.push(response.url());
-										}else{
-											return false;
-										}
-										
-										let jsonText = await response.text();
-										let jsonObj = {};
-										if(jsonText && typeof jsonText == 'string'){
-											jsonObj = JSON.parse(jsonText);
-										}
-										
-										
-										let arr = ['aweme_detail', 'video', 'play_addr', 'url_list', '2'];
-										for(let i = 0; i < 5; i++){
-											jsonObj = jsonObj[arr[i]];
-										}
-										
-										console.log(jsonObj, '-----------22222222222222222');
-										
-										
-										
-										
-									}
-								}
-								
-								
-							});
-							await page.goto(urlInfo.url, {waitUntil : 'networkidle2'});
-							
-							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 scrollInt = setInterval(async() => {
-								start ++;
-								
-								if(start > num || start > 30){ // 防止页面过长,滚动30次自动停止
-									urlInfo.status = '3';
-									clearInterval(scrollInt);
-									
-									if(urlInfo.title){
-										if (fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title)) {
-											urlInfo.newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title;
-										} else {
-											fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title);
-											urlInfo.newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title;
-										}
-									}else{
-										await this.getTitle(page, urlInfo); // 生成页面标题对应的文件夹
-									}
-									
-									//detailImg:详情图;skuImg:sku图片;commentImg: 评论图;video: 视频
-									const imgInfo = await page.evaluate((authority) => {
-										let outObj = {
-											video: []
-										};
-										// 视频
-										let arr5 = document.querySelectorAll('video source');
-										for(let i=0; i< arr5.length; i++){
-											if(outObj.video.indexOf(arr5[i].src) < 0 && !arr5[i].src.startsWith('blob:https://')){
-												if(arr5[i].src){
-													outObj.video.push(arr5[i].src);
-												}
-											}
-										}
-										return outObj;
-									}, authority);
-									
-									if(responseVideo.length > 0){
-										for(let l=0; l<responseVideo.length; l++){
-											if(imgInfo.video.indexOf(responseVideo[l]) < 0){
-												imgInfo.video.push(responseVideo[l]);
-											}
-										}
-									}
-									
-									urlInfo.status = '3';
-									console.log(imgInfo.video);
-									
-									//视频下载
-									for(let j = 0; j < imgInfo.video.length; j++){
-										let num = Number(j) + 1;
-										let suffix = '.mp4';
-										let outputPath = urlInfo.newPath + '\\视频' + num + suffix;
-										console.log(imgInfo.video[j], '--------------333333333333');
-										// await this.downloadImage(imgInfo.video[j], outputPath, urlInfo);
-									}
-									
-									this.loading = false;
-									urlInfo.status = '4';
-									resolve(true);
-								}
-							}, 600);
-						}catch(e){
-							urlInfo.status = '5';
-							reject(e);
-							this.showError(e);
-						}
-					})();
-				});
-			},
-			
-			// 视频下载
-			async videoDownload(urlInfo, browser){
-				let task = await new Promise((resolve,reject) =>{
-					(async () => {
-						try{
-							let authority = this.$refs.headerRef.authority.isAuthority;
-							urlInfo.status = '2';
-							urlInfo.num = 0;
-							const page = await browser.newPage();
-							
-							let responseVideo = [];
-							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());
-									}
-								}
-							});
-							await page.goto(urlInfo.url, {waitUntil : 'networkidle2'});
-							
-							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 scrollInt = setInterval(async() => {
-								start ++;
-								
-								let startTime = 30;
-								if(this.menuIndex == '10'){
-									startTime = 100;
-									
-									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);
-									num = Math.ceil(scrollHeight2 / cHeight);
-								}
-								
-								if(start > num || start > startTime){ // 防止页面过长,滚动30次自动停止
-									urlInfo.status = '3';
-									clearInterval(scrollInt);
-									
-									if(urlInfo.title){
-										if (fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title)) {
-											urlInfo.newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title;
-										} else {
-											fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title);
-											urlInfo.newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title;
-										}
-									}else{
-										await this.getTitle(page, urlInfo); // 生成页面标题对应的文件夹
-									}
-									
-									//detailImg:详情图;skuImg:sku图片;commentImg: 评论图;video: 视频
-									const imgInfo = await page.evaluate((authority) => {
-										let outObj = {
-											video: []
-										};
-										// 视频
-										let arr5 = document.querySelectorAll('video source');
-										if(arr5.length == 0){
-											arr5 = document.querySelectorAll('video');
-										}
-										for(let i=0; i< arr5.length; i++){
-											if(outObj.video.indexOf(arr5[i].src) < 0 && !arr5[i].src.startsWith('blob:https://')){
-												if(arr5[i].src){
-													outObj.video.push(arr5[i].src);
-												}
-											}
-										}
-										return outObj;
-									}, authority);
-									
-									if(responseVideo.length > 0){
-										for(let l=0; l<responseVideo.length; l++){
-											if(imgInfo.video.indexOf(responseVideo[l]) < 0){
-												imgInfo.video.push(responseVideo[l]);
-											}
-										}
-									}
-									
-									urlInfo.status = '3';
-									console.log(imgInfo.video);
-									
-									//视频下载
-									for(let j = 0; j < imgInfo.video.length; j++){
-										let num = Number(j) + 1;
-										let suffix = '.mp4';
-										let outputPath = urlInfo.newPath + '\\视频' + num + suffix;
-										await this.downloadImage(imgInfo.video[j], outputPath, urlInfo);
-									}
-									
-									this.loading = false;
-									urlInfo.status = '4';
-									resolve(true);
-								}
-							}, 600);
-						}catch(e){
-							urlInfo.status = '5';
-							reject(e);
-							this.showError(e);
-						}
-					})();
-				});
-			},
-			
-			//
-			downloadExample(){
-				let url = 'https://www.xingyousoft.com/soft/XYCapture/example.xlsx';
-				if (!fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName)) {
-					fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName);
-				}
-				let path = this.downloadDir + separator + pjson.softInfo.softName + '\\链接模板下载.xlsx';
-				this.downloadImage(url, path, 'example');
-			},
-			
-			// 下载网址链接的图片
-			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(this.menuIndex == '1' && (status == 403 || isNaN(total_bytes))){
-								fs.unlinkSync(outputPath);
-							}
-							
-							
-						});
-									
-						req.on('data', (chunk) => {
-						    received_bytes += chunk.length;
-						});
-						
-						req.on('end', ()=> {
-							if(urlInfo != 'example'){
-								urlInfo.num += 1;
-							}else{
-								this.$msgbox({
-									title: '消息',
-									message: '模板下载成功,保存位置:' + this.downloadDir + separator + pjson.softInfo.softName,
-									showCancelButton: true,
-									confirmButtonText: '去查看',
-									cancelButtonText: '取消',
-								}).then(action => {
-									this.openFolder();
-								}).catch(action => {
-									
-								});
-							}
-							//console.log('下载完成', outputPath)
-							resolve(true);
-						});
-					});
-			    } catch (error) {  
-			        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(/[\\|/|:|*|?|"|<|>||]/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, charsArray) {
-			    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;  
-			} 
-			
-		}
-	};
-</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;
-		}
-	}
-	
-</style>

+ 93 - 72
src/renderer/components/home.vue

@@ -9,9 +9,9 @@
 				<template>
 					<div style="padding: 10px 20px 0 20px; height: 100%;">
 						
-						<el-row type="flex" align="middle">
+						<el-row type="flex" align="middle" justify="space-between">
 							<div>
-								<span>平台:</span>
+								<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>
@@ -62,14 +62,18 @@
 									<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="excelType">
-								<el-radio label="xlsx">xlsx</el-radio>
-								<el-radio label="xls">xls</el-radio>
-								<el-radio label="txt">txt</el-radio>
+							提取模式:
+							<el-radio-group v-model="exeType">
+								<el-radio :label="1">后台运行</el-radio>
+								<el-radio :label="2">前台显示</el-radio>
 							</el-radio-group>
 						</el-row>
 						
@@ -88,7 +92,7 @@
 								<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>
+								<el-button size="small" type="danger" @click="exportLinks()">合并导出全部</el-button>
 							</div>
 						</div>
 											
@@ -181,7 +185,7 @@
 		data() {
 			return {
 				menuIndex: '4',
-				excelType: 'xlsx',
+				exeType: 1,
 				
 				usageTimes: 3,
 				tipsModal: false,
@@ -286,7 +290,6 @@
 			}
 			
 			// 初始化开发者设置
-			this.$utils.setStorage('headless', 1);
 			this.$utils.setStorage('waitUntil', 'networkidle2');
 			
 			document.getElementById('aaa').addEventListener('contextmenu', e => {
@@ -312,7 +315,7 @@
 					headless: true,
 					waitUntil: 'networkidle2'
 				};
-				let n1 = this.$utils.getStorage('headless');
+				let n1 = this.exeType;
 				let n2 = this.$utils.getStorage('waitUntil');
 				if(n1){
 					if(n1 == 1){
@@ -595,8 +598,6 @@
 					}
 				}
 				
-				let taskArr = [];
-				let task = "";
 				let userDataDir = this.initDataDir();
 				if(this.menuIndex == '2'){
 					userDataDir = this.initDataDir('jd');
@@ -614,45 +615,52 @@
 				if(['3','4','5'].indexOf(this.menuIndex) > -1){
 					redSize = '--window-size=1920,800'; //给浏览器一个初始大小,在无头模式下,页面会自适用缩放
 				}
-				this[browserName] = await puppeteer.launch({
-					headless: false,
-					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, this.alibabaBrowser);
-						break;
-					case '2': // 京东
-						this.jdScanUrl(this.formatUrl, this.jdBrowser);
-						break;
-					case '3': // 天猫
-					case '4': // 淘宝
-						this.tbScanUrl(this.formatUrl, this.tbBrowser);
-						break;
-					case '5': // 小红书
-						this.redScanUrl(this.formatUrl, this.redBrowser);
-						break;
-					case '10': // 普通网址
-						this.commonScanUrl(this.formatUrl, this.commonBrowser);
-						break;
+				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, tbBrowser){
+			tbScanUrl(url){
 				(async () => {
 					try{
 						let authority = this.$refs.headerRef.authority.isAuthority;
-						let page = await tbBrowser.newPage();
+						let page = await this.tbBrowser.newPage();
 						
 						let responseVideo = [];
 						let waitUntil = 'networkidle2';
@@ -704,14 +712,14 @@
 								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]').innerText || '淘宝商品'+new Date().getTime();
-									let priceInt = arr1[i].querySelector('[class^=priceInt]').innerText || 0;
-									let priceFloat = arr1[i].querySelector('[class^=priceFloat]').innerText || '';
+									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]').innerText || '';
-									let shopNameText = arr1[i].querySelector('[class^=shopNameText]').innerText;
-									let shopUrl = arr1[i].querySelector('a[class^=shopName]').href;
-									let mainPic = arr1[i].querySelector('img[class^=mainImg]').src;
+									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,
@@ -754,11 +762,11 @@
 			},
 			
 			// 阿里巴巴扫描网址
-			alibabaScanUrl(url, alibabaBrowser){
+			alibabaScanUrl(url){
 				(async () => {
 					try{
 						let authority = this.$refs.headerRef.authority.isAuthority;
-						let page = await alibabaBrowser.newPage();
+						let page = await this.alibabaBrowser.newPage();
 						
 						let responseVideo = [];
 						let waitUntil = 'networkidle2';
@@ -818,14 +826,14 @@
 										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]').innerText || '阿里巴巴商品'+new Date().getTime();
-										let priceText = arr1[i].querySelector('[class^=price-item]').innerText || '';
+										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]').innerText;
-										let shopUrl = arr1[i].querySelector('[class^=offer-shop-row] a').href;
-										let mainPic = arr1[i].querySelector('img[class^=main-img]').src;
+										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,
@@ -862,11 +870,11 @@
 			},
 			
 			// 京东扫描网址
-			jdScanUrl(url, jdBrowser){
+			jdScanUrl(url){
 				(async () => {
 					try{
 						let authority = this.$refs.headerRef.authority.isAuthority;
-						let page = await jdBrowser.newPage();
+						let page = await this.jdBrowser.newPage();
 						
 						let responseVideo = [];
 						let waitUntil = 'networkidle2';
@@ -941,14 +949,14 @@
 									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]').innerText || '京东商品'+new Date().getTime();
-										let priceText = arr1[i].querySelector('[class*=price]').innerText || '';
+										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]').innerText;
-										let shopUrl = arr1[i].querySelector('[class*=shopFloor] a').href;
-										let mainPic = arr1[i].querySelector('img').src;
+										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,
@@ -990,11 +998,11 @@
 			},
 			
 			// 小红书扫描网址
-			redScanUrl(url, redBrowser){
+			redScanUrl(url){
 				(async () => {
 					try{
 						let authority = this.$refs.headerRef.authority.isAuthority;
-						let page = await redBrowser.newPage();
+						let page = await this.redBrowser.newPage();
 						
 						let responseVideo = [];
 						let waitUntil = 'networkidle2';
@@ -1021,6 +1029,11 @@
 						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;
@@ -1039,10 +1052,10 @@
 								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]').href;
+									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').src;
+									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 : "";
 									
@@ -1055,7 +1068,9 @@
 										name: name,
 										time: time
 									}
-									outObj.urls.push(info);
+									if(href || title || name){
+										outObj.urls.push(info);
+									}
 								}
 								
 								window.scrollTo({
@@ -1093,6 +1108,7 @@
 							if(start > num || start > 500){ // 防止页面过长,滚动200次自动停止
 								clearInterval(scrollInt);
 								await this.redBrowser.close();
+								this.redBrowser = null;
 								this.addLoading = false;
 							}
 						}, scrollTime);
@@ -1105,11 +1121,11 @@
 			
 			
 			// 普通扫描网址
-			commonScanUrl(url, commonBrowser){
+			commonScanUrl(url){
 				(async () => {
 					try{
 						let authority = this.$refs.headerRef.authority.isAuthority;
-						let page = await commonBrowser.newPage();
+						let page = await this.commonBrowser.newPage();
 						
 						let responseVideo = [];
 						let waitUntil = 'networkidle2';
@@ -1136,6 +1152,11 @@
 						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;

BIN
static/icon.ico