qiushang 8 달 전
부모
커밋
8ad2fd07f8
3개의 변경된 파일152개의 추가작업 그리고 50개의 파일을 삭제
  1. 18 12
      src/renderer/components/header.vue
  2. 133 37
      src/renderer/components/home.vue
  3. 1 1
      src/renderer/components/img.vue

+ 18 - 12
src/renderer/components/header.vue

@@ -8,14 +8,16 @@
 				</p>
 				<div style="-webkit-app-region:no-drag">
 					<div>
-						<span v-if="authority.isAuthority" class="o-member twinkle_text" @click="openVip()">
-							<img src="../assets/image/i-vip.png" />
-							<span>会员中心</span>
-						</span>
-						<span v-else class="o-member twinkle_text" @click="openVip()">
-							<img src="../assets/image/i-vip.png" />
-							<span>开通会员</span>
-						</span>
+						<template v-if="authority.validity_type != 2">
+							<span v-if="authority.isAuthority" class="o-member twinkle_text" @click="openVip()">
+								<img src="../assets/image/i-vip.png" />
+								<span>会员中心</span>
+							</span>
+							<span v-else class="o-member twinkle_text" @click="openVip()">
+								<img src="../assets/image/i-vip.png" />
+								<span>开通会员</span>
+							</span>
+						</template>
 						
 						<div class="login-cur" v-if="!userInfo.username" @click="loginModel = true">
 							<el-avatar icon="el-icon-user-solid" size="small" class="login-icon"></el-avatar><span class="font-12">未登录</span>
@@ -28,7 +30,7 @@
 							<img src="../assets/image/vip.png" v-if="authority.isAuthority" style="width: 25px;vertical-align: middle;"/>
 						</div>
 						<el-dropdown @command="changeMenu">
-						    <i class="el-icon-s-operation sys-icon"></i>
+						    <i class="el-icon-s-operation sys-icon" title="菜单"></i>
 						    <el-dropdown-menu slot="dropdown">
 						        <el-dropdown-item command="vip">{{authority.isAuthority ? '会员中心' : '开通会员'}}</el-dropdown-item>
 						        <el-dropdown-item command="update">检查更新</el-dropdown-item>
@@ -127,9 +129,10 @@
 			<div>
 				<el-divider content-position="left">账号登录</el-divider>
 				<el-row type="flex" justify="space-between">
-					<el-button size="mini" @click="toLogin('alibaba')" :loading="alibabaLoading">阿里巴巴账号</el-button>
-					<el-button size="mini" @click="toLogin('jd')" :loading="jdLoading">京东账号</el-button>
-					<el-button size="mini" @click="toLogin('tb')" :loading="tbLoading">天猫/淘宝账号</el-button>
+					<el-button size="mini" @click="toLogin('alibaba')" :loading="alibabaLoading">阿里巴巴</el-button>
+					<el-button size="mini" @click="toLogin('jd')" :loading="jdLoading">京东</el-button>
+					<el-button size="mini" @click="toLogin('tb')" :loading="tbLoading">天猫/淘宝</el-button>
+					<el-button size="mini" @click="toLogin('red')" :loading="redLoading">小红书</el-button>
 				</el-row>
 				<el-row style="text-align: center; margin-top: 10px;">
 					<el-link :underline="false" type="danger" style="text-align: center; font-size: 13px;">账号登录完成后请关闭浏览器使用</el-link>
@@ -219,6 +222,7 @@
 				alibabaLoading: false,
 				jdLoading: false,
 				tbLoading: false,
+				redLoading: false,
 				cacheLoading: false,
 			}
 		},
@@ -333,6 +337,8 @@
 					url = 'https://passport.jd.com/new/login.aspx';
 				}else if(type == 'tb'){
 					url = 'https://login.taobao.com';
+				}else if(type == 'red'){
+					url = 'https://www.xiaohongshu.com';
 				}
 				this[type + 'Loading'] = true;
 				setTimeout(() => {

+ 133 - 37
src/renderer/components/home.vue

@@ -116,8 +116,7 @@
 									<el-row type="flex" justify="space-between">
 										<div v-if="menuIndex == '5'" style="padding-top: 10px;">
 											<label>下载类型:</label>
-											<el-checkbox :value="true" style="opacity: 0.6; cursor: not-allowed;">文章图</el-checkbox>
-											<span style="font-size: 12px;">(不包含Live图)</span>
+											<el-checkbox :value="true" style="opacity: 0.6; cursor: not-allowed;">文章图/视频</el-checkbox>
 										</div>
 										
 										<div v-if="menuIndex == '10'" style="padding-top: 10px;">
@@ -138,11 +137,6 @@
 												<i class="el-icon-info" slot="reference" style="margin-left: 10px; color: #F56C6C;"></i>
 											</el-popover>
 											
-											<!-- <el-checkbox :value="true" style="opacity: 0.6; cursor: not-allowed;">主图</el-checkbox>
-											<el-checkbox v-model="settingData.detailImg" >详情图</el-checkbox>
-											<el-checkbox v-model="settingData.skuImg" >SKU图</el-checkbox>
-											<el-checkbox v-model="settingData.commentImg" v-if="menuIndex == '3' || menuIndex == '4'">评论图</el-checkbox>
-											<el-checkbox v-model="settingData.video" >视频</el-checkbox> -->
 										</div>
 										
 										<!-- 天猫/淘宝 -->
@@ -164,8 +158,17 @@
 												<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>
 									</el-row>
-									
 								</div>
 							
 								<div class="table-scroll">
@@ -240,11 +243,23 @@
 						
 						<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;">
-								<p>{{menuIndex == '2' ? '京东' : '天猫/淘宝'}}渠道需要登录后才能下载</p>
-								<p style="font-size: 18px; color: #f73131; font-weight: 600; padding: 30px 40px 0;">目前检测还未登录{{menuIndex == '2' ? '京东' : '天猫/淘宝'}}账号,需立即登录</p>
+								<template v-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>
+								<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>
@@ -343,6 +358,7 @@
 				checkLoading: false, //点击检测登录状态
 				tbStatus: 1, // 1、未检测 2、已经登录 3、未登录 
 				jdStatus: 1, // 1、未检测 2、已经登录 3、未登录 
+				redStatus: 1, //同上
 				execLimit: 1,
 				execNum: 3, // 限制5张
 
@@ -768,6 +784,23 @@
 						}
 					}
 					
+					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 taskArr = [];
 					let task = "";
 					for(let i = 0; i < fileList.length; i++){
@@ -1166,6 +1199,7 @@
 											
 											for(let i = 0; i < detailImgArr.length; i++){
 												let imgUrl = 'https:' + detailImgArr[i];
+												imgUrl = imgUrl.replace('.avif', '');
 												let fileName = imgUrl.split('/').pop();
 												if(fileName){
 													let queryIndex = fileName.indexOf('?');
@@ -2009,6 +2043,39 @@
 				await browser.close();
 			},
 			
+			// 检查小红书登录状态
+			checkRedLogin(){
+				this.checkLoading = true;
+				this.redStatus = 1;
+				return new Promise((resolve, reject) => {
+					(async () => {
+						try{
+							const redBrowser = await puppeteer.launch({
+								executablePath: puppeteer.executablePath().replace('win32-1', 'win64-1'),
+								userDataDir: os.tmpdir() + separator + 'chrome-data-capture-jd', 
+							});
+							const page = await redBrowser.newPage();
+							let testUrl = 'https://www.xiaohongshu.com';
+							await page.goto(testUrl, {waitUntil : 'networkidle2'});
+							
+							let loginContainer = await page.$$('.login-container');
+							let loginBtn = await page.$$('#login-btn');
+							if(loginContainer.length > 0 || loginBtn.length > 0){
+								this.redStatus = 3; //未登录
+							}else{
+								this.redStatus = 2;
+							}
+							
+							resolve(this.redStatus);
+							this.checkLoading = false;
+							redBrowser.close();
+						}catch(e){
+							reject(3);
+							this.showError(e);
+						}
+					})();
+				});
+			},
 			// 5-小红书下载
 			async redDownload(urlInfo){
 				let task = await new Promise((resolve,reject) =>{
@@ -2030,6 +2097,15 @@
 								]
 							});
 							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'});
 							
 							if(urlInfo.title){
@@ -2044,33 +2120,42 @@
 							}
 							urlInfo.status = '3';
 							
-							//'blob:https://www.xiaohongshu.com/3696ba14-7658-4d60-b897-1a7608737e15'
-							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){
-										responseVideo.push(response.url());
-									}
-								}
-							});
-							
-							let noteImg = await page.$$('img[class^=note-slider-img]');
-							if(noteImg.length == 0){
-								let refreshImg = await page.$$('.xgplayer-error-refresh');
-								let startImg = await page.$$('.xgplayer-start');
-								//点击播放生成视频
-								if(refreshImg.length == 0){
-									await page.waitForSelector('.xgplayer-start', { visible: true });
-									await page.click('.xgplayer-start');
-								}else{
-									await page.waitForSelector('.xgplayer-error-refresh', { visible: true });
-									await page.click('.xgplayer-error-refresh');
-									await page.click('.xgplayer-error-refresh');
-									await page.click('.xgplayer-error-refresh');
-								}
+							// 定位元素
+							const handle = await page.$$('.pagination-media-container .pagination-item'); 
+							if(handle.length > 0){ // 模拟鼠标拖动 将鼠标移动到元素的中心,然后开始拖动
+								let handleLength = handle.length;
+								const box = await handle[0].boundingBox();
+								const boxEnd = await handle[handleLength - 1].boundingBox();
+								const center = {
+									x: box.x + box.width / 2,
+									y: box.y + box.height / 2
+								};
+								const centerEnd = {
+									x: boxEnd.x + boxEnd.width / 2,
+									y: boxEnd.y + boxEnd.height / 2
+								};
+								await page.mouse.move(center.x, center.y);
+								await page.mouse.down();
+								await page.mouse.move(centerEnd.x, centerEnd.y, { steps: 50 }); // 新的位置,可以根据需要调整步骤数
 							}
 							
+							// let noteImg = await page.$$('img[class^=note-slider-img]');
+							// if(noteImg.length == 0){
+							// 	let refreshImg = await page.$$('.xgplayer-error-refresh');
+							// 	let startImg = await page.$$('.xgplayer-start');
+							// 	console.log(refreshImg, startImg);
+							// 	//点击播放生成视频
+							// 	if(startImg.length > 0){
+							// 		await page.waitForSelector('.xgplayer-start', { visible: true });
+							// 		await page.click('.xgplayer-start');
+							// 	}else{
+							// 		await page.waitForSelector('.xgplayer-error-refresh', { visible: true });
+							// 		await page.click('.xgplayer-error-refresh');
+							// 		await page.click('.xgplayer-error-refresh');
+							// 		await page.click('.xgplayer-error-refresh');
+							// 	}
+							// }
+							
 							//detailImg:详情图;skuImg:sku图片;commentImg: 评论图;video: 视频
 							const imgInfo = await page.evaluate((authority, execNum) => {
 								let outObj = {
@@ -2148,7 +2233,12 @@
 										fileName = fileName.substr(0, queryIndex);  
 									}
 									
-									let outputPath = urlInfo.newPath + '\\' + fileName;
+									let num = Number(j) + 1;
+									let suffix = '.mp4';
+									if(fileName.lastIndexOf('.') > -1){
+										suffix = fileName.substr(fileName.lastIndexOf('.'));
+									}
+									let outputPath = urlInfo.newPath + '\\视频' + num + suffix;
 									await this.downloadImage(imgInfo.video[j], outputPath, urlInfo);
 								}
 							}
@@ -2164,7 +2254,6 @@
 						}
 					})();
 				});
-				
 			},
 			
 			//
@@ -2513,4 +2602,11 @@
 	.dialog-footer-center{
 		text-align: center;
 	}
+	
+	.visible-tips-style{
+		font-size: 18px; 
+		color: #f73131; 
+		font-weight: 600; 
+		padding: 30px 40px 0;
+	}
 </style>

+ 1 - 1
src/renderer/components/img.vue

@@ -356,7 +356,7 @@ export default {
             imgInfo: '',
 			imgInfoIndex: 0,
             menuIndex: 1, // 选中菜单
-            imgFormat: ['PNG','BMP','JPEG','JPG','ICO','WBMP','WEBP','HEIC','GIF','JFIF','TTF','TIF','TIFF','SVG','3FR','3G2','3GP','AAI','AI','ART','ARW','BGR','BGRA','BGRO','BIE','BMP2','BMP3','BRF','CAL','CALS','CANVAS','CAPTION','CIN','CIP','CLIP','CMYK','CMYKA','CR2','CRW','CUR','CUT','DATA','DCM','DCR','DCX','DDS','DFONT','DJVU','DNG','DOT','DPX','DXT1','DXT5','EPDF','EPI','EPS','EPS2','EPS3','EPSF','EPSI','EPT','EPT2','EPT3','ERF','EXR','FAX','FILE','FITS','FRACTAL','FTP','FTS','G3','G4','GIF87','GRADIENT','GRAY','GRAYA','GROUP4','GV','H','HALD','HDR','HISTOGRAM','HRZ','ICB','ICON','IIQ','INFO','INLINE','IPL','ISOBRL','ISOBRL6','J2C','J2K','JBG','JBIG','JNG','JNX','JP2','JPC','JPE','JPM','JPS','JPT','JSON','K25','KDC','LABEL','M2V','M4V','MAC','MAGICK','MAP','MASK','MAT','MATTE','MEF','MIFF','MKV','MNG','MONO','MRW','MSL','MSVG','MVG','NEF','NRW','ORF','OTB','OTF','PAL','PALM','PAM','PANGO','PATTERN','PBM','PCD','PCDS','PCL','PCT','PEF','PES','PFA','PFB','PFM','PGM','PGX','PICON','PICT','PIX','PJPEG','PLASMA','PNG00','PNG24','PNG32','PNG48','PNG64','PNG8','PNM','PPM','PREVIEW','PS','PS2','PS3','PSB','PSD','PTIF','PWP','RADIAL-GRADIENT','RAF','RAS','RAW','RGB','RGBA','RGBO','RGF','RLA','RLE','RMF','RW2','SCR','SCT','SFW','SGI','SHTML','SIX','SIXEL','SPARSE-COLOR','SR2','SRF','STEGANO','SUN','SVGZ','TGA','THUMBNAIL','TIFF64','TILE','UBRL','UBRL6','UIL','UYVY','VDA','VICAR','VID','VIFF','VIPS','VST','WMF','WMV','WMZ','WPG','X','X3F','XBM','XC','XCF','XPM','XPS','XV','XWD','YCbCr','YCbCrA','YUV'], // 图片格式
+            imgFormat: ['PNG','BMP','JPEG','JPG','ICO','WBMP','WEBP','HEIC','GIF','JFIF','TTF','TIF','TIFF','SVG','3FR','3G2','3GP','AAI','AVIF','AI','ART','ARW','BGR','BGRA','BGRO','BIE','BMP2','BMP3','BRF','CAL','CALS','CANVAS','CAPTION','CIN','CIP','CLIP','CMYK','CMYKA','CR2','CRW','CUR','CUT','DATA','DCM','DCR','DCX','DDS','DFONT','DJVU','DNG','DOT','DPX','DXT1','DXT5','EPDF','EPI','EPS','EPS2','EPS3','EPSF','EPSI','EPT','EPT2','EPT3','ERF','EXR','FAX','FILE','FITS','FRACTAL','FTP','FTS','G3','G4','GIF87','GRADIENT','GRAY','GRAYA','GROUP4','GV','H','HALD','HDR','HISTOGRAM','HRZ','ICB','ICON','IIQ','INFO','INLINE','IPL','ISOBRL','ISOBRL6','J2C','J2K','JBG','JBIG','JNG','JNX','JP2','JPC','JPE','JPM','JPS','JPT','JSON','K25','KDC','LABEL','M2V','M4V','MAC','MAGICK','MAP','MASK','MAT','MATTE','MEF','MIFF','MKV','MNG','MONO','MRW','MSL','MSVG','MVG','NEF','NRW','ORF','OTB','OTF','PAL','PALM','PAM','PANGO','PATTERN','PBM','PCD','PCDS','PCL','PCT','PEF','PES','PFA','PFB','PFM','PGM','PGX','PICON','PICT','PIX','PJPEG','PLASMA','PNG00','PNG24','PNG32','PNG48','PNG64','PNG8','PNM','PPM','PREVIEW','PS','PS2','PS3','PSB','PSD','PTIF','PWP','RADIAL-GRADIENT','RAF','RAS','RAW','RGB','RGBA','RGBO','RGF','RLA','RLE','RMF','RW2','SCR','SCT','SFW','SGI','SHTML','SIX','SIXEL','SPARSE-COLOR','SR2','SRF','STEGANO','SUN','SVGZ','TGA','THUMBNAIL','TIFF64','TILE','UBRL','UBRL6','UIL','UYVY','VDA','VICAR','VID','VIFF','VIPS','VST','WMF','WMV','WMZ','WPG','X','X3F','XBM','XC','XCF','XPM','XPS','XV','XWD','YCbCr','YCbCrA','YUV'], // 图片格式
             positionList: ['上左', '上中', '上右', '中左', '中间', '中右', '下左', '下中', '下右'],
 
             downloadDir: '', // 默认下载目录