|
@@ -35,7 +35,6 @@
|
|
<el-button type="danger" @click="startParsing()" :loading="parseLoading">开始解析</el-button>
|
|
<el-button type="danger" @click="startParsing()" :loading="parseLoading">开始解析</el-button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
-
|
|
|
|
|
|
|
|
<div class="table-scroll" style="height: calc(100% - 290px); overflow: hidden;">
|
|
<div class="table-scroll" style="height: calc(100% - 290px); overflow: hidden;">
|
|
<el-row type="flex" justify="space-between">
|
|
<el-row type="flex" justify="space-between">
|
|
@@ -43,6 +42,8 @@
|
|
<h4 style="display: inline-block;">
|
|
<h4 style="display: inline-block;">
|
|
视频信息:
|
|
视频信息:
|
|
</h4>
|
|
</h4>
|
|
|
|
+
|
|
|
|
+ <el-button @click="mergeClick()" size="small" :disabled="bUrl">B站音视频合并</el-button>
|
|
</div>
|
|
</div>
|
|
<el-row type="flex" style="align-items: center;">
|
|
<el-row type="flex" style="align-items: center;">
|
|
<div class="set-item">
|
|
<div class="set-item">
|
|
@@ -100,8 +101,49 @@
|
|
</vxe-table>
|
|
</vxe-table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
-
|
|
|
|
</template>
|
|
</template>
|
|
|
|
+
|
|
|
|
+ <!-- B站音视频合并提示框 -->
|
|
|
|
+ <el-dialog title="B站音视频合并" :visible.sync="mergeModal" width="420px" :close-on-click-modal="false" :close-on-press-escape="false">
|
|
|
|
+ <div class="member-model">
|
|
|
|
+ <div class="handle-item">
|
|
|
|
+ <label class="handle-label">视频文件:</label>
|
|
|
|
+ <el-upload :style="{display: 'inline-block'}" action="/" :before-upload="getVideoPath">
|
|
|
|
+ <el-input type="text" readonly size="small" v-model="bVideoInfo.videoPath" style="width:220px;" placeholder="点击选择文件"></el-input>
|
|
|
|
+ <i class="el-icon-folder-opened open-folder" style="font-size:22px;"></i>
|
|
|
|
+ </el-upload>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="handle-item" v-if="bVideoInfo.videoDuration">
|
|
|
|
+ <label class="handle-label">视频时长:</label>
|
|
|
|
+ <span style="color: #999;">{{formatSeconds(bVideoInfo.videoDuration)}}</span>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="handle-item">
|
|
|
|
+ <label class="handle-label">音频文件:</label>
|
|
|
|
+ <el-upload :style="{display: 'inline-block'}" action="/" :before-upload="getAudioPath">
|
|
|
|
+ <el-input type="text" readonly size="small" v-model="bVideoInfo.audioPath" style="width:220px;" placeholder="点击选择文件"></el-input>
|
|
|
|
+ <i class="el-icon-folder-opened open-folder" style="font-size:22px;"></i>
|
|
|
|
+ </el-upload>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="handle-item" v-if="bVideoInfo.audioDuration">
|
|
|
|
+ <label class="handle-label">音频时长:</label>
|
|
|
|
+ <span style="color: #999;">{{formatSeconds(bVideoInfo.audioDuration)}}</span>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="handle-item">
|
|
|
|
+ <label class="handle-label">文件名称:</label>
|
|
|
|
+ <el-input type="text" size="small" placeholder="请输入文字水印内容" style="width:220px;" v-model="bVideoInfo.title"></el-input>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="handle-item">
|
|
|
|
+ <label class="handle-label">文件类型:</label>
|
|
|
|
+ <el-select size="small" style="width:220px;" v-model="bVideoInfo.suffix">
|
|
|
|
+ <el-option value="mp4" label="mp4"></el-option>
|
|
|
|
+ <el-option value="mkv" label="mkv"></el-option>
|
|
|
|
+ </el-select>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="member-btn">
|
|
|
|
+ <el-button size="small" type="danger" @click="mergeVideo()" :loading="mergeLoading">开始合并</el-button>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </el-dialog>
|
|
|
|
|
|
<!-- 非会员转换提示框 -->
|
|
<!-- 非会员转换提示框 -->
|
|
<el-dialog title="非会员提示" :visible.sync="tipsModal" width="400px">
|
|
<el-dialog title="非会员提示" :visible.sync="tipsModal" width="400px">
|
|
@@ -161,6 +203,15 @@
|
|
usageTimes: 3,
|
|
usageTimes: 3,
|
|
tipsModal: false,
|
|
tipsModal: false,
|
|
tipsDesc: "试用次数已经用完,请开通VIP会员使用。",
|
|
tipsDesc: "试用次数已经用完,请开通VIP会员使用。",
|
|
|
|
+ mergeModal: false,
|
|
|
|
+ bVideoInfo: {
|
|
|
|
+ videoPath: '',
|
|
|
|
+ audioPath: '',
|
|
|
|
+ title: '',
|
|
|
|
+ suffix: 'mp4',
|
|
|
|
+ videoDuration: '',
|
|
|
|
+ audioDuration: '',
|
|
|
|
+ },
|
|
|
|
|
|
formatUrl: '',
|
|
formatUrl: '',
|
|
tabLoading: false,
|
|
tabLoading: false,
|
|
@@ -181,6 +232,9 @@
|
|
videoBrowser: null,
|
|
videoBrowser: null,
|
|
loginBrowser: null, // 登录用的浏览器实例
|
|
loginBrowser: null, // 登录用的浏览器实例
|
|
parseLoading: false,
|
|
parseLoading: false,
|
|
|
|
+ mergeLoading: false,
|
|
|
|
+ bUrl: true,
|
|
|
|
+
|
|
};
|
|
};
|
|
},
|
|
},
|
|
async mounted() {
|
|
async mounted() {
|
|
@@ -222,6 +276,210 @@
|
|
|
|
|
|
},
|
|
},
|
|
methods: {
|
|
methods: {
|
|
|
|
+
|
|
|
|
+ // 实时获取浏览器路径
|
|
|
|
+ initPath(){
|
|
|
|
+ let chromePath = puppeteer.executablePath().replace('win32-1', 'win64-1');
|
|
|
|
+ return chromePath;
|
|
|
|
+ },
|
|
|
|
+ checkAuthority(){
|
|
|
|
+ let authority = this.$refs.headerRef.authority;
|
|
|
|
+ this.$refs.imgRef.authority = authority;
|
|
|
|
+ },
|
|
|
|
+ // 选择目录
|
|
|
|
+ pickPath() {
|
|
|
|
+ this.$refs['upload-input'].blur();
|
|
|
|
+ electronApi.call('pickDir', []).then((path) => {
|
|
|
|
+ if (path) {
|
|
|
|
+ this.downloadDir = path;
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ // 打开自定义下载目录
|
|
|
|
+ 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();
|
|
|
|
+ },
|
|
|
|
+ // 清除缓存的后续操作
|
|
|
|
+ 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);
|
|
|
|
+ }
|
|
|
|
+ })();
|
|
|
|
+ },
|
|
|
|
+ getVideoPath(e){
|
|
|
|
+ if (e) {
|
|
|
|
+ this.bVideoInfo.videoPath = e.path;
|
|
|
|
+
|
|
|
|
+ electronApi.spawnExec(['ffprobe.exe','-i', e.path,'-v','quiet','-print_format','json','-show_format', '-show_streams', '-hide_banner']).then((result) => {
|
|
|
|
+ result = result.stdout.toString();
|
|
|
|
+ result = JSON.parse(result);
|
|
|
|
+ this.bVideoInfo.videoDuration = result.format.duration;
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ getAudioPath(e){
|
|
|
|
+ if (e) {
|
|
|
|
+ this.bVideoInfo.audioPath = e.path;
|
|
|
|
+
|
|
|
|
+ electronApi.spawnExec(['ffprobe.exe','-i', e.path,'-v','quiet','-print_format','json','-show_format', '-show_streams', '-hide_banner']).then((result) => {
|
|
|
|
+ result = result.stdout.toString();
|
|
|
|
+ result = JSON.parse(result);
|
|
|
|
+ this.bVideoInfo.audioDuration = result.format.duration;
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ mergeClick(){
|
|
|
|
+ this.mergeModal = true;
|
|
|
|
+ this.bVideoInfo.title = this.videoList[0].title;
|
|
|
|
+ },
|
|
|
|
+ // b站视频合并
|
|
|
|
+ mergeVideo(){
|
|
|
|
+ let newPath = this.downloadDir + separator + pjson.softInfo.softName;
|
|
|
|
+ let params = [
|
|
|
|
+ 'ffmpeg.exe',
|
|
|
|
+ '-i',
|
|
|
|
+ this.bVideoInfo.videoPath,
|
|
|
|
+ '-i',
|
|
|
|
+ this.bVideoInfo.audioPath,
|
|
|
|
+ '-c',
|
|
|
|
+ 'copy',
|
|
|
|
+ newPath + separator + this.bVideoInfo.title + '.' + this.bVideoInfo.suffix,
|
|
|
|
+ '-hide_banner',
|
|
|
|
+ '-y'
|
|
|
|
+ ];
|
|
|
|
+ const regexTime = /time=(.*?) bitrate/;
|
|
|
|
+ this.mergeLoading = true;
|
|
|
|
+ electronApi.spawnExec(params,{
|
|
|
|
+ stderr:(data) =>{
|
|
|
|
+ // let timeStr = regexTime.exec(data.toString());
|
|
|
|
+ // if(timeStr && timeStr[1]){
|
|
|
|
+ // let percent = Math.ceil((this.getSs(timeStr[1])/this.bVideoInfo.videoDuration).toFixed(2) * 100);
|
|
|
|
+ // }
|
|
|
|
+ }
|
|
|
|
+ }).then(res => {
|
|
|
|
+ this.mergeLoading = false;
|
|
|
|
+ this.$message({message: '恭喜你,合并已完成!', type: 'success'});
|
|
|
|
+ electronApi.call('showItemInfolder',[this.downloadDir + separator + pjson.softInfo.softName +'\\tty.tty']);
|
|
|
|
+ }).catch(err =>{
|
|
|
|
+ this.mergeLoading = false;
|
|
|
|
+ this.$notify.error({
|
|
|
|
+ title: '合并失败',
|
|
|
|
+ message: '视频参数有误,请重试! ',
|
|
|
|
+ });
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+ // 开始解析
|
|
|
|
+ async startParsing(){
|
|
|
|
+ if(this.formatUrl.trim()){
|
|
|
|
+ let formatUrl = this.formatUrl.trim();
|
|
|
|
+
|
|
|
|
+ if(formatUrl.indexOf('https://') == -1){
|
|
|
|
+ this.$message.error('错了哦,请输入正确的视频地址(https://开头)');
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ let arr = formatUrl.split('https://');
|
|
|
|
+ formatUrl = 'https://' + arr[1];
|
|
|
|
+
|
|
|
|
+ const regex = /https:\/\/.*?.douyin.com/;
|
|
|
|
+ const res = regex.exec(formatUrl);
|
|
|
|
+ if(res && res.length > 0){ //抖音视频解析,使用puputter
|
|
|
|
+ this.douyinParsing(formatUrl);
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ this.parseLoading = true;
|
|
|
|
+ this.tabLoading = true;
|
|
|
|
+ this.videoList = [];
|
|
|
|
+ let params = [
|
|
|
|
+ '--dump-json',
|
|
|
|
+ formatUrl
|
|
|
|
+ ];
|
|
|
|
+ electronApi.spawnExec(['dlp.exe', ...params]).then(res => {
|
|
|
|
+ this.parseLoading = false;
|
|
|
|
+ this.tabLoading = false;
|
|
|
|
+ let info = res.stdout ? res.stdout.toString() : '{formats: []}';
|
|
|
|
+ this.videoInfo = JSON.parse(info);
|
|
|
|
+ this.videoList = this.videoInfo.formats || [];
|
|
|
|
+ this.videoList.map(item => {
|
|
|
|
+ item.title = this.videoInfo.title,
|
|
|
|
+ item.status = '1';
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ const bregex = /https:\/\/.*?.bilibili.com/;
|
|
|
|
+ const bres = bregex.exec(formatUrl);
|
|
|
|
+ if(bres && bres.length > 0){ //b站的视频
|
|
|
|
+ this.bUrl = false;
|
|
|
|
+ }else{
|
|
|
|
+ this.bUrl = true;
|
|
|
|
+ }
|
|
|
|
+ }).catch(err =>{
|
|
|
|
+ this.parseLoading = false;
|
|
|
|
+ this.tabLoading = false;
|
|
|
|
+ // console.log('err1',err.stderr.toString());
|
|
|
|
+ let errStr = err.stderr.toString();
|
|
|
|
+ this.bUrl = true;
|
|
|
|
+ if(errStr.indexOf('Unsupported URL') > -1){
|
|
|
|
+ this.videoParsing(formatUrl);
|
|
|
|
+ return false;
|
|
|
|
+ }else{
|
|
|
|
+ this.$notify.error({
|
|
|
|
+ title: '网址解析失败!',
|
|
|
|
+ message: errStr
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+
|
|
// 点击下载视频
|
|
// 点击下载视频
|
|
async downloadVideo(index, flag){
|
|
async downloadVideo(index, flag){
|
|
this.selectIndex = index;
|
|
this.selectIndex = index;
|
|
@@ -329,144 +587,11 @@
|
|
item.status = '4';
|
|
item.status = '4';
|
|
item.loading = false;
|
|
item.loading = false;
|
|
this.$forceUpdate();
|
|
this.$forceUpdate();
|
|
- console.log(err);
|
|
|
|
|
|
+ // console.log(err);
|
|
})
|
|
})
|
|
}
|
|
}
|
|
},
|
|
},
|
|
|
|
|
|
- // 开始解析
|
|
|
|
- async startParsing(){
|
|
|
|
- if(this.formatUrl.trim()){
|
|
|
|
- let formatUrl = this.formatUrl.trim();
|
|
|
|
-
|
|
|
|
- if(formatUrl.indexOf('https://') == -1){
|
|
|
|
- this.$message.error('错了哦,请输入正确的视频地址(https://开头)');
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- let arr = formatUrl.split('https://');
|
|
|
|
- formatUrl = 'https://' + arr[1];
|
|
|
|
-
|
|
|
|
- const regex = /https:\/\/.*?.douyin.com/;
|
|
|
|
- const res = regex.exec(formatUrl);
|
|
|
|
- if(res && res.length > 0){ //抖音视频解析,使用puputter
|
|
|
|
- this.douyinParsing(formatUrl);
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- this.parseLoading = true;
|
|
|
|
- this.tabLoading = true;
|
|
|
|
- this.videoList = [];
|
|
|
|
- let params = [
|
|
|
|
- '--dump-json',
|
|
|
|
- formatUrl
|
|
|
|
- ];
|
|
|
|
- electronApi.spawnExec(['dlp.exe', ...params]).then(res => {
|
|
|
|
- this.parseLoading = false;
|
|
|
|
- this.tabLoading = false;
|
|
|
|
- let info = res.stdout ? res.stdout.toString() : '{formats: []}';
|
|
|
|
- this.videoInfo = JSON.parse(info);
|
|
|
|
- this.videoList = this.videoInfo.formats || [];
|
|
|
|
- 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
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
- })
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
- // 实时获取浏览器路径
|
|
|
|
- initPath(){
|
|
|
|
- let chromePath = puppeteer.executablePath().replace('win32-1', 'win64-1');
|
|
|
|
- return chromePath;
|
|
|
|
- },
|
|
|
|
- checkAuthority(){
|
|
|
|
- let authority = this.$refs.headerRef.authority;
|
|
|
|
- this.$refs.imgRef.authority = authority;
|
|
|
|
- },
|
|
|
|
- // 选择目录
|
|
|
|
- pickPath() {
|
|
|
|
- this.$refs['upload-input'].blur();
|
|
|
|
- electronApi.call('pickDir', []).then((path) => {
|
|
|
|
- if (path) {
|
|
|
|
- this.downloadDir = path;
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
- },
|
|
|
|
- // 打开自定义下载目录
|
|
|
|
- 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();
|
|
|
|
- },
|
|
|
|
- // 清除缓存的后续操作
|
|
|
|
- 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 douyinParsing(url){
|
|
async douyinParsing(url){
|
|
if(this.loginBrowser){
|
|
if(this.loginBrowser){
|
|
@@ -689,7 +814,7 @@
|
|
|
|
|
|
});
|
|
});
|
|
await page.goto(url, {waitUntil : 'networkidle2'});
|
|
await page.goto(url, {waitUntil : 'networkidle2'});
|
|
- // await page.waitForTimeout(1500);
|
|
|
|
|
|
+ await page.waitForTimeout(1000);
|
|
|
|
|
|
let pageInfo = await page.evaluate(() => {
|
|
let pageInfo = await page.evaluate(() => {
|
|
let cHeight = document.documentElement.clientHeight;
|
|
let cHeight = document.documentElement.clientHeight;
|
|
@@ -749,27 +874,25 @@
|
|
loading: false
|
|
loading: false
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ let skipFlag = true;
|
|
for(let j = 0; j < this.videoList.length; j++){
|
|
for(let j = 0; j < this.videoList.length; j++){
|
|
- if(this.videoList.urlList[0] == item){
|
|
|
|
-
|
|
|
|
|
|
+ if(this.videoList[j].urlList[0] == item){
|
|
|
|
+ skipFlag = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- this.videoList.push(vinfo);
|
|
|
|
|
|
+ if(skipFlag){
|
|
|
|
+ this.videoList.push(vinfo);
|
|
|
|
+ }
|
|
});
|
|
});
|
|
}
|
|
}
|
|
-
|
|
|
|
- console.log(this.videoList);
|
|
|
|
await page.close();
|
|
await page.close();
|
|
this.parseLoading = false;
|
|
this.parseLoading = false;
|
|
this.tabLoading = false;
|
|
this.tabLoading = false;
|
|
}
|
|
}
|
|
}, 600);
|
|
}, 600);
|
|
|
|
|
|
- console.log(this.videoList);
|
|
|
|
this.parseLoading = false;
|
|
this.parseLoading = false;
|
|
this.tabLoading = false;
|
|
this.tabLoading = false;
|
|
-
|
|
|
|
-
|
|
|
|
}catch(e){
|
|
}catch(e){
|
|
this.parseLoading = false;
|
|
this.parseLoading = false;
|
|
this.tabLoading = false;
|
|
this.tabLoading = false;
|
|
@@ -781,125 +904,6 @@
|
|
|
|
|
|
},
|
|
},
|
|
|
|
|
|
-
|
|
|
|
- // 视频下载
|
|
|
|
- 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);
|
|
|
|
- }
|
|
|
|
- })();
|
|
|
|
- });
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
// 下载网址链接的图片
|
|
// 下载网址链接的图片
|
|
async downloadImage(imageUrl, outputPath, urlInfo) {
|
|
async downloadImage(imageUrl, outputPath, urlInfo) {
|
|
let _this = this;
|
|
let _this = this;
|
|
@@ -938,9 +942,18 @@
|
|
}
|
|
}
|
|
|
|
|
|
});
|
|
});
|
|
-
|
|
|
|
|
|
+
|
|
req.on('data', (chunk) => {
|
|
req.on('data', (chunk) => {
|
|
received_bytes += chunk.length;
|
|
received_bytes += chunk.length;
|
|
|
|
+ if(urlInfo.filesize){
|
|
|
|
+ let size = Number(urlInfo.filesize);
|
|
|
|
+ let percent = Number(received_bytes / size * 100);
|
|
|
|
+ urlInfo.percent = percent.toFixed(2);
|
|
|
|
+ if(percent > 100){
|
|
|
|
+ urlInfo.percent = 100;
|
|
|
|
+ }
|
|
|
|
+ this.$forceUpdate();
|
|
|
|
+ }
|
|
});
|
|
});
|
|
|
|
|
|
req.on('end', ()=> {
|
|
req.on('end', ()=> {
|
|
@@ -1036,7 +1049,37 @@
|
|
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
|
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
|
}
|
|
}
|
|
return result;
|
|
return result;
|
|
- }
|
|
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ //
|
|
|
|
+ formatSeconds(value) {
|
|
|
|
+ var secondTime = parseInt(value); // 秒
|
|
|
|
+ var minuteTime = 0; // 分
|
|
|
|
+ var hourTime = 0; // 小时
|
|
|
|
+ if (secondTime >= 60) {
|
|
|
|
+ minuteTime = parseInt(secondTime / 60);
|
|
|
|
+ secondTime = parseInt(secondTime % 60);
|
|
|
|
+ if (minuteTime >= 60) {
|
|
|
|
+ hourTime = parseInt(minuteTime / 60);
|
|
|
|
+ minuteTime = parseInt(minuteTime % 60);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var result ="" +(parseInt(secondTime) < 10? "0" + parseInt(secondTime): parseInt(secondTime));
|
|
|
|
+ result ="" + (parseInt(minuteTime) < 10? "0" + parseInt(minuteTime) : parseInt(minuteTime)) + ":" + result;
|
|
|
|
+ result ="" + (parseInt(hourTime) < 10 ? "0" + parseInt(hourTime): parseInt(hourTime)) +":" + result;
|
|
|
|
+ return result;
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ // 视频时间转为秒
|
|
|
|
+ getSs(rawDuration){
|
|
|
|
+ const $ar = rawDuration.split(":");
|
|
|
|
+ let $duration = parseFloat($ar[2]);
|
|
|
|
+ if ($ar[1]) $duration += parseInt($ar[1]) * 60;
|
|
|
|
+ if ($ar[0]) $duration += parseInt($ar[0]) * 60 * 60;
|
|
|
|
+
|
|
|
|
+ return $duration;
|
|
|
|
+ },
|
|
|
|
|
|
}
|
|
}
|
|
};
|
|
};
|
|
@@ -1290,4 +1333,8 @@
|
|
margin: 0 3px;
|
|
margin: 0 3px;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ .el-upload-list{
|
|
|
|
+ display: none;
|
|
|
|
+ }
|
|
|
|
+
|
|
</style>
|
|
</style>
|