qiushang hace 4 meses
padre
commit
1ebb17376e
Se han modificado 2 ficheros con 238 adiciones y 137 borrados
  1. 226 135
      src/renderer/components/home.vue
  2. 12 2
      src/renderer/utils/utils.js

+ 226 - 135
src/renderer/components/home.vue

@@ -2,7 +2,7 @@
 	<div>
 		<el-container style="height: 100vh;">
 			<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>
+				<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;">
@@ -23,7 +23,7 @@
 							</div>
 						</el-row>
 						
-						<div style="margin: 30px 0;">
+						<div style="margin-top: 20px;">
 							<el-input type="textarea" :rows="8" placeholder="请输入需要解析的视频地址" v-model="formatUrl"></el-input>
 							
 							<div class="content-top" style="padding: 10px 0;">
@@ -44,10 +44,25 @@
 						</div>
 						
 					
-						<div class="table-scroll" style="height: calc(100% - 330px);">
+						<div class="table-scroll" style="height: calc(100% - 330px); overflow: hidden;">
+							<el-row type="flex" justify="space-between">
+								<div>
+									<h4 style="display: inline-block;">
+										视频信息:
+									</h4>
+									<el-link :underline="false" style="font-size: 12px;">
+										
+									</el-link>
+									
+								</div>
+							</el-row>
 							<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="videoList" :scroll-y="{enabled: true}">
-								<vxe-column field="format_id" title="ID"></vxe-column>
+								<vxe-column field="title" title="标题">
+									<template #default="{ row }">
+										{{row.title}}[{{row.format_id}}]
+									</template>
+								</vxe-column>
 								<vxe-column field="ext" title="扩展名" width="70"></vxe-column>
 								<vxe-column field="resolution" title="分辨率" width="100"></vxe-column>
 								<vxe-column field="fps" title="帧率" width="60"></vxe-column>
@@ -56,9 +71,9 @@
 										{{$utils.handleSize(row.filesize)}}
 									</template>
 								</vxe-column>
-								<vxe-column field="vcodec" title="视频编码" width="100"></vxe-column>
-								<vxe-column field="acodec" title="音频编码" width="100"></vxe-column>
-								<vxe-column field="status" title="下载状态" width="120">
+								<vxe-column field="vcodec" title="视频编码" width="120"></vxe-column>
+								<vxe-column field="acodec" title="音频编码" width="120"></vxe-column>
+								<vxe-column field="status" title="下载状态" width="140">
 									<template #default="{ row }">
 										<template v-if="row.status == '1'">
 											<i class="el-icon-info" style="font-size: 16px; color: #999;"></i>
@@ -150,6 +165,7 @@
 
 				formatUrl: '',
 				tabLoading: false,
+				videoInfo: {},
 				videoList: [],
 				productName: pjson.softInfo.softName,
 				imgUrl: this.$api.imgUrl,
@@ -242,16 +258,30 @@
 				}
 				let newPath = this.downloadDir + separator + pjson.softInfo.softName;
 				
-				if(item.tag && item.tag == 'douyin'){ //抖音下载
+				if(item.tag){ //抖音下载
 					let outputPath = newPath + separator + item.title.substring(0, 50) + '[' + item.format_id + ']' + '.mp4';
 					let url = item.urlList.length > 0 ? item.urlList[0] : '';
-					item.urlList.map(uitem => {
-						if(uitem.startsWith('https://www.douyin.com/')){
-							url = uitem;
-						}
-					})
+					
+					if(item.tag == 'douyin'){
+						item.urlList.map(uitem => {
+							if(uitem.startsWith('https://www.douyin.com/')){
+								url = uitem;
+							}
+						})
+					}
+					
 					item.status = '2';
 					item.loading = true;
+					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{
+						return false;
+					}
 					await this.downloadImage(url, outputPath, item);
 					item.loading = false;
 					return false;
@@ -264,20 +294,30 @@
 						newPath + separator + '%(title).50s['+item.format_id+'].%(ext)s',
 						this.formatUrl
 					];
+					item.status = '2';
 					electronApi.spawnExec(['dlp.exe', ...params],{
 						stdout:(data) =>{
-							item.status = '2';
 							let str = data.toString();
 							const regexDuration = /[download].*? (.*?)%/;
 							const res = regexDuration.exec(str);
 							if(res && res[1]){
 								item.percent = res[1];
 							}
-							console.log('stdout', data.toString());
+							console.log('stdout', item.percent, '----', data.toString());
 						}
 					}).then(res => {
 						let outData = res.stdout ? res.stdout.toString() : '{}';
 						item.status = '3';
+						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{
+							return false;
+						}
 						
 						console.log(this.videoList)
 						console.log(outData);
@@ -286,8 +326,6 @@
 						console.log(err);
 					})
 				}
-				
-				
 			},
 			
 			// 开始解析
@@ -308,9 +346,17 @@
 						this.douyinParsing(formatUrl);
 						return false;
 					}
+
+					// const regex2 = /https:\/\/.*?.kuaishou.com/;
+					// const res2 = regex2.exec(formatUrl);
+					// if(res2 && res2.length > 0){ //其他视频解析,使用puputter
+					// 	this.videoParsing(formatUrl);
+					// 	return false;
+					// }
 					
 					this.parseLoading = true;
 					this.tabLoading = true;
+					this.videoList = [];
 					let params = [
 						'--dump-json',
 						formatUrl
@@ -319,15 +365,27 @@
 						this.parseLoading = false;
 						this.tabLoading = false;
 						let info = res.stdout ? res.stdout.toString() : '{formats: []}';
-						let videoInfo = JSON.parse(info);
-						this.videoList = videoInfo.formats || [];
+						this.videoInfo = JSON.parse(info);
+						this.videoList = this.videoInfo.formats || [];
 						this.videoList.map(item => {
+							item.title = this.videoInfo.title,
 							item.status = '1';
 						})
+						console.log(this.videoInfo);
 					}).catch(err =>{
 						this.parseLoading = false;
 						this.tabLoading = false;
 						console.log('err1',err.stderr.toString());
+						let errStr = err.stderr.toString();
+						if(errStr.indexOf('Unsupported URL') > -1){
+							this.videoParsing(formatUrl);
+							return false;
+						}else{
+							this.$notify.error({
+								title: '网址解析失败!',
+								message: errStr
+							});
+						}
 					})
 				}
 			},
@@ -430,7 +488,7 @@
 				setTimeout(()=> {
 					this.parseLoading = false;
 					this.tabLoading = false;
-				}, 10000)
+				}, 20000)
 				
 				let userDataDir = os.tmpdir() + separator + 'chrome-data-capture-video';
 				// 运行不同平台的浏览器
@@ -481,18 +539,13 @@
 								
 							});
 							await page.goto(url, {waitUntil : 'networkidle2'});
-							await this.videoBrowser.close();
+							await page.close();
 							
 							let arr = ['aweme_detail']; //'video' ,'play_addr', 'url_list', '2'];
 							for(let i = 0; i < arr.length; i++){
 								responseObj = responseObj[arr[i]];
 							}
-							// responseObj.preview_title; 标题
-							// responseObj.video.play_addr width height data_size url_list
-							// responseObj.video.play_addr_265 width height data_size url_list
-							// responseObj.video.play_addr_h264 width height data_size url_list 'https://www.douyin.com'
 							
-							console.log(responseObj);
 							if(responseObj.video && responseObj.video.play_addr){
 								let vinfo = {
 									title: responseObj.preview_title,
@@ -549,8 +602,6 @@
 							
 							this.parseLoading = false;
 							this.tabLoading = false;
-							
-							
 						}catch(e){
 							this.parseLoading = false;
 							this.tabLoading = false;
@@ -562,8 +613,8 @@
 				
 			},
 			
-			// 开始下载
-			async exportFile(flag) {
+			// 解析视频-快手-其他
+			async videoParsing(url){
 				if(this.loginBrowser){
 					await this.loginBrowser.close();
 					this.loginBrowser = null;
@@ -572,118 +623,158 @@
 					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);
+				if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture-video')) {
+					fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture-video');
 				}
 				
-				let index = Number(this.menuIndex) - 1;
-				let fileList = this[listNameArr[index]+'List'];
+				this.parseLoading = true;
+				this.tabLoading = true;
+				this.videoList = [];
 				
-				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;
+				setTimeout(()=> {
+					this.parseLoading = false;
+					this.tabLoading = false;
+				}, 20000)
+				
+				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',
+					]
+				});
+				
+				await new Promise((resolve,reject) =>{
+					(async () => {
+						try{
+							let authority = this.$refs.headerRef.authority.isAuthority;
+							const page = await this.videoBrowser.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://')){
+										
+										let title = await page.title();
+										if(title){
+											title = title.substring(0, 50);
+											if(this.containsAnyChar(title, ['\\', '/', ':', '*', '?', '"', '<', '>', '|'])){  //判断是否含有特殊字符
+												title = title.replace(/[\\|/|:|*|?|"|<|>||]/g, "");
+											}
+										}
+										
+										let vinfo = {
+											title: title,
+											tag: 'kuaishou',
+											format_id: 'default',
+											ext: 'mp4',
+											resolution: '-',
+											fps: '-',
+											filesize: response.headers()['content-length'], 
+											vcodec: '-',
+											acodec: '-',
+											urlList: [response.url()],
+											status: '1',
+											loading: false
+										}
+										responseVideo.push(response.url());
+										this.videoList.push(vinfo);
+									}
+								}
+								
 							});
-						}else{
-							videoBrowser
-							return false;
-						}
-						
-						task = this.videoDownload(item, this.videoBrowser);
-					
-						if(task){
-							taskArr.push(task);
-						}
-						
-						if((i+1) % 1 == 0){
-							await Promise.all(taskArr).then(result => {
-								taskArr = [];
-							}).catch(err => {
-								console.log('err'+i, err)
-							})
+							await page.goto(url, {waitUntil : 'networkidle2'});
+							// await page.waitForTimeout(1500);
+							
+							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 > 20){ // 防止页面过长,滚动50次自动停止
+									clearInterval(scrollInt);
+									
+									const videoArr = await page.evaluate(() => {
+										let video = [];
+										// 视频
+										let arr5 = document.querySelectorAll('video');
+										if(arr5.length == 0){
+											arr5 = document.querySelectorAll('video source');
+										}
+										for(let i=0; i< arr5.length; i++){
+											if(video.indexOf(arr5[i].src) < 0 && !arr5[i].src.startsWith('blob:https://')){
+												if(arr5[i].src){
+													video.push(arr5[i].src);
+												}
+											}
+										}
+										return video;
+									});
+									
+									if(videoArr.length > 0){
+										let title = await page.title();
+										if(title){
+											title = title.substring(0, 50);
+											if(this.containsAnyChar(title, ['\\', '/', ':', '*', '?', '"', '<', '>', '|'])){  //判断是否含有特殊字符
+												title = title.replace(/[\\|/|:|*|?|"|<|>||]/g, "");
+											}
+										}
+										
+										videoArr.map((item, index) => {
+											let vinfo = {
+												title: title,
+												tag: '',
+												format_id: index,
+												ext: 'mp4',
+												resolution: '-',
+												fps: '-',
+												filesize: '-', 
+												vcodec: '-',
+												acodec: '-',
+												urlList: [item],
+												status: '1',
+												loading: false
+											}
+											this.videoList.push(vinfo);
+										});
+									}
+									await page.close();
+								}
+							}, 600);
+							
+							console.log(this.videoList);
+							this.parseLoading = false;
+							this.tabLoading = false;
+							
+							
+						}catch(e){
+							this.parseLoading = false;
+							this.tabLoading = false;
+							reject(e);
+							this.showError(e);
 						}
-					}
-					
-					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 videoDownload(urlInfo, browser){
 				let task = await new Promise((resolve,reject) =>{

+ 12 - 2
src/renderer/utils/utils.js

@@ -122,10 +122,20 @@ function main(src, cb) {
 
 // 处理文件大小
 function handleSize(size) {
+	let number = '';
+	let outStr = '';
 	if ((size / 1024 / 1024) < 1) {
-		return (size / 1024).toFixed(2) + 'KB';
+		number = (size / 1024).toFixed(2);
+		outStr = (size / 1024).toFixed(2) + 'KB';
 	} else {
-		return (size / 1024 / 1024).toFixed(2) + 'MB';
+		number = (size / 1024 / 1024).toFixed(2);
+		outStr = (size / 1024 / 1024).toFixed(2) + 'MB';
+	}
+	
+	if(isNaN(number)){
+		return '-';
+	}else{
+		return outStr;
 	}
 }