mirror of
https://github.com/cuiocean/ZY-Player.git
synced 2026-02-14 07:55:27 +08:00
Compare commits
63 Commits
v2.7.0
...
v2.7.1-Hap
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fea076318d | ||
|
|
df867fa919 | ||
|
|
a7f0030462 | ||
|
|
b5274c79b0 | ||
|
|
a2de1984e3 | ||
|
|
81b5391f64 | ||
|
|
2c6ad44974 | ||
|
|
e1c942dc7b | ||
|
|
4420e6961e | ||
|
|
2deffab3ba | ||
|
|
05a07bee62 | ||
|
|
025d1606f7 | ||
|
|
b72c88dfb9 | ||
|
|
db240cc163 | ||
|
|
0ef55f0139 | ||
|
|
0ad9b49224 | ||
|
|
ccbf4fb5d7 | ||
|
|
46e376a351 | ||
|
|
23e693a314 | ||
|
|
3a3e37f4bd | ||
|
|
e568053b95 | ||
|
|
fe9cd9f5bc | ||
|
|
8cf3ec94d9 | ||
|
|
112f92d3e0 | ||
|
|
88db766337 | ||
|
|
205b9d7979 | ||
|
|
d5a7771a67 | ||
|
|
655ed7fb16 | ||
|
|
808f3d2012 | ||
|
|
ee4b944abf | ||
|
|
b4abd9369f | ||
|
|
079da637ec | ||
|
|
0c8a100d1c | ||
|
|
0cc330463f | ||
|
|
f50d669a5f | ||
|
|
57fd1d325e | ||
|
|
e31b921486 | ||
|
|
08b39a5bb1 | ||
|
|
1fefc792fc | ||
|
|
b9a4784de2 | ||
|
|
855472fe68 | ||
|
|
4834d4423c | ||
|
|
4de2177cc7 | ||
|
|
ca9f9c9160 | ||
|
|
7c0f688f9d | ||
|
|
4bfae63201 | ||
|
|
419a56518f | ||
|
|
36efdcd869 | ||
|
|
a297aca812 | ||
|
|
0b4dd2e859 | ||
|
|
3142306a0c | ||
|
|
9d4765c1ea | ||
|
|
547dffb922 | ||
|
|
84e61acde7 | ||
|
|
11c756466c | ||
|
|
06291ffc4b | ||
|
|
1f65e5ba0a | ||
|
|
392f0fd326 | ||
|
|
a6b6407679 | ||
|
|
96678bf5df | ||
|
|
3c37b8286f | ||
|
|
38862f6ad8 | ||
|
|
35213238f4 |
@@ -12,6 +12,7 @@ module.exports = {
|
||||
},
|
||||
rules: {
|
||||
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||
'standard/no-callback-literal': 0
|
||||
}
|
||||
}
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/bug.md
vendored
4
.github/ISSUE_TEMPLATE/bug.md
vendored
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: 报告Bug(请先查看常见问题及搜索issue列表中有无你要提的问题)
|
||||
name: 报告Bug(请先查看常见问题及搜索已关闭issue列表中有无你要提的问题)
|
||||
about: 创建报告以帮助我们改进
|
||||
title: '(未回答的问题请删除)'
|
||||
title: '(未回答的问题请删除,减少多余信息干扰)'
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
|
||||
32
package.json
32
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "zy",
|
||||
"version": "2.7.0",
|
||||
"version": "2.7.1-HappyNewYear",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
@@ -17,54 +17,54 @@
|
||||
},
|
||||
"main": "background.js",
|
||||
"dependencies": {
|
||||
"@imjs/electron-differential-updater": "^5.1.3",
|
||||
"axios": "^0.21.0",
|
||||
"cheerio": "^1.0.0-rc.3",
|
||||
"core-js": "^3.8.0",
|
||||
"axios": "^0.21.1",
|
||||
"cheerio": "^1.0.0-rc.5",
|
||||
"core-js": "^3.8.1",
|
||||
"dexie": "^3.0.3",
|
||||
"electron-localshortcut": "^3.2.1",
|
||||
"electron-proxy-agent": "^1.2.0",
|
||||
"electron-updater": "^4.3.5",
|
||||
"element-ui": "^2.14.1",
|
||||
"fast-xml-parser": "^3.17.4",
|
||||
"fast-xml-parser": "^3.17.5",
|
||||
"html2canvas": "^1.0.0-rc.7",
|
||||
"iptv-playlist-parser": "^0.5.0",
|
||||
"iptv-playlist-parser": "^0.5.1",
|
||||
"m3u": "0.0.2",
|
||||
"m3u8-parser": "^4.5.0",
|
||||
"memcached": "^2.2.2",
|
||||
"modern-normalize": "^1.0.0",
|
||||
"mousetrap": "^1.6.5",
|
||||
"pinyin-match": "^1.1.1",
|
||||
"pinyin-match": "^1.1.7",
|
||||
"qrcode.vue": "^1.7.0",
|
||||
"randomstring": "^1.1.5",
|
||||
"session": "^0.1.0",
|
||||
"sortablejs": "^1.12.0",
|
||||
"v-fit-columns": "^0.2.0",
|
||||
"vue": "^2.6.12",
|
||||
"vue-clickaway": "^2.2.2",
|
||||
"vue-infinite-loading": "^2.4.5",
|
||||
"vue-waterfall-plugin": "^1.1.0",
|
||||
"vuedraggable": "^2.24.3",
|
||||
"vuex": "^3.6.0",
|
||||
"xgplayer": "^2.13.2",
|
||||
"xgplayer-hls.js": "^2.2.5"
|
||||
"xgplayer": "^2.16.0",
|
||||
"xgplayer-flv.js": "^2.1.2",
|
||||
"xgplayer-hls.js": "^2.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~4.5.9",
|
||||
"@vue/cli-plugin-eslint": "~4.5.9",
|
||||
"@vue/cli-plugin-vuex": "~4.5.9",
|
||||
"@vue/cli-service": "~4.5.9",
|
||||
"@vue/eslint-config-standard": "^5.1.2",
|
||||
"@vue/eslint-config-standard": "^6.0.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-plugin-component": "^1.1.1",
|
||||
"electron": "^11.0.3",
|
||||
"electron": "^11.1.1",
|
||||
"electron-devtools-installer": "^3.1.1",
|
||||
"eslint": "^7.14.0",
|
||||
"eslint": "^7.16.0",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-standard": "^4.1.0",
|
||||
"eslint-plugin-vue": "^7.1.0",
|
||||
"sass": "^1.29.0",
|
||||
"eslint-plugin-vue": "^7.3.0",
|
||||
"sass": "^1.30.0",
|
||||
"sass-loader": "^10.1.0",
|
||||
"vue-cli-plugin-electron-builder": "2.0.0-rc.5",
|
||||
"vue-template-compiler": "^2.6.12"
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<meta name="referrer" content="same-origin"/>
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
</head>
|
||||
|
||||
@@ -131,6 +131,12 @@
|
||||
border-color: var(--d-c-8);
|
||||
}
|
||||
}
|
||||
.selected {
|
||||
background-color: var(--d-c-5);
|
||||
&:hover{
|
||||
background-color: var(--d-c-5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +131,12 @@
|
||||
border-color: var(--g-c-8);
|
||||
}
|
||||
}
|
||||
.selected {
|
||||
background-color: var(--g-c-5);
|
||||
&:hover{
|
||||
background-color: var(--g-c-5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +131,12 @@
|
||||
border-color: var(--l-c-8);
|
||||
}
|
||||
}
|
||||
.selected {
|
||||
background-color: var(--l-c-5);
|
||||
&:hover{
|
||||
background-color: var(--l-c-5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +131,12 @@
|
||||
border-color: var(--p-c-8);
|
||||
}
|
||||
}
|
||||
.selected {
|
||||
background-color: var(--p-c-5);
|
||||
&:hover{
|
||||
background-color: var(--p-c-5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
|
||||
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
|
||||
import { initUpdater } from './lib/update/update'
|
||||
const isDevelopment = process.env.NODE_ENV !== 'production'
|
||||
// const log = require('electron-log') // 用于调试主程序
|
||||
|
||||
app.commandLine.appendSwitch('disable-features', 'OutOfBlinkCors') // 允许跨域
|
||||
app.commandLine.appendSwitch('--ignore-certificate-errors', 'true') // 忽略证书相关错误
|
||||
@@ -35,6 +36,23 @@ function createWindow () {
|
||||
win.loadURL('app://./index.html')
|
||||
}
|
||||
|
||||
// 修改request headers
|
||||
// Sec-Fetch下禁止修改,浏览器自动加上请求头 https://www.cnblogs.com/fulu/p/13879080.html 暂时先用index.html的meta referer policy替代
|
||||
const filter = {
|
||||
urls: ['http://*/*', 'http://*/*']
|
||||
}
|
||||
win.webContents.session.webRequest.onBeforeSendHeaders(filter, (details, callback) => {
|
||||
const url = new URL(details.url)
|
||||
details.requestHeaders.Origin = url.origin
|
||||
if (!details.url.includes('//localhost') && details.requestHeaders.Referer && details.requestHeaders.Referer.includes('//localhost')) {
|
||||
details.requestHeaders.Referer = url.origin
|
||||
}
|
||||
callback({
|
||||
cancel: false,
|
||||
requestHeaders: details.requestHeaders
|
||||
})
|
||||
})
|
||||
|
||||
initUpdater(win)
|
||||
|
||||
win.on('closed', () => {
|
||||
|
||||
@@ -52,10 +52,16 @@
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="desc" v-show="info.des">{{info.des}}</div>
|
||||
class="desc" v-show="info.des">{{info.des}}
|
||||
</div>
|
||||
<div class="m3u8" v-if="videoFullList.length > 1">
|
||||
<div class="box">
|
||||
<span v-bind:class="{ selected: i.flag === videoFlag }" v-for="(i, j) in videoFullList" :key="j" @click="updateVideoList(i)">{{i.flag}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="m3u8">
|
||||
<div class="box">
|
||||
<span v-for="(i, j) in m3u8List" :key="j" @click="playEvent(j)">{{i | ftName}}</span>
|
||||
<span v-for="(i, j) in videoList" :key="j" @click="playEvent(j)">{{i | ftName}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -76,7 +82,9 @@ export default {
|
||||
data () {
|
||||
return {
|
||||
loading: true,
|
||||
m3u8List: [],
|
||||
videoFlag: '',
|
||||
videoList: [],
|
||||
videoFullList: [],
|
||||
info: {},
|
||||
playOnline: false,
|
||||
selectedOnlineSite: '哔嘀',
|
||||
@@ -121,26 +129,52 @@ export default {
|
||||
set (val) {
|
||||
this.SET_SHARE(val)
|
||||
}
|
||||
},
|
||||
DetailCache: {
|
||||
get () {
|
||||
return this.$store.getters.getDetailCache
|
||||
},
|
||||
set (val) {
|
||||
this.SET_DetailCache(val)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SET_VIEW', 'SET_VIDEO', 'SET_DETAIL', 'SET_SHARE']),
|
||||
...mapMutations(['SET_VIEW', 'SET_VIDEO', 'SET_DETAIL', 'SET_SHARE', 'SET_DetailCache']),
|
||||
addClass (flag) {
|
||||
if (flag === this.videoFlag) {
|
||||
return 'selectedBox'
|
||||
} else {
|
||||
return 'box'
|
||||
}
|
||||
},
|
||||
close () {
|
||||
this.detail.show = false
|
||||
},
|
||||
async updateVideoList (e) {
|
||||
this.videoFlag = e.flag
|
||||
this.videoList = e.list
|
||||
const db = await history.find({ site: this.detail.key, ids: this.detail.info.id })
|
||||
if (db) {
|
||||
const doc = { ...db }
|
||||
doc.videoFlag = e.flag
|
||||
delete doc.id
|
||||
history.update(db.id, doc)
|
||||
}
|
||||
},
|
||||
async playEvent (n) {
|
||||
if (!this.playOnline) {
|
||||
const db = await history.find({ site: this.detail.key, ids: this.detail.info.id })
|
||||
if (db) {
|
||||
this.video = { key: db.site, info: { id: db.ids, name: db.name, index: n, site: this.detail.site } }
|
||||
this.video = { key: db.site, info: { id: db.ids, name: db.name, index: n, site: this.detail.site, videoFlag: this.videoFlag } }
|
||||
} else {
|
||||
this.video = { key: this.detail.key, info: { id: this.detail.info.id, name: this.detail.info.name, index: n, site: this.detail.site } }
|
||||
this.video = { key: this.detail.key, info: { id: this.detail.info.id, name: this.detail.info.name, index: n, site: this.detail.site, videoFlag: this.videoFlag } }
|
||||
}
|
||||
this.video.detail = this.info
|
||||
this.view = 'Play'
|
||||
this.detail.show = false
|
||||
} else {
|
||||
const db = await history.find({ site: this.detail.key, ids: this.detail.info.id })
|
||||
const db = await history.find({ site: this.detail.key, ids: this.info.id })
|
||||
if (db) {
|
||||
db.index = n
|
||||
db.detail = this.info
|
||||
@@ -211,63 +245,54 @@ export default {
|
||||
}
|
||||
},
|
||||
downloadEvent () {
|
||||
const key = this.detail.key
|
||||
const id = this.info.id
|
||||
zy.download(key, id).then(res => {
|
||||
if (res && res.m3u8List) {
|
||||
const list = res.m3u8List.split('#')
|
||||
let downloadUrl = ''
|
||||
for (const i of list) {
|
||||
const url = encodeURI(i.split('$')[1])
|
||||
downloadUrl += (url + '\n')
|
||||
}
|
||||
clipboard.writeText(downloadUrl)
|
||||
this.$message.success('『MP4』格式的链接已复制, 快去下载吧!')
|
||||
} else {
|
||||
zy.detail(key, id).then(res => {
|
||||
const list = [...res.m3u8List]
|
||||
let downloadUrl = ''
|
||||
for (const i of list) {
|
||||
const url = encodeURI(i.split('$')[1])
|
||||
downloadUrl += (url + '\n')
|
||||
}
|
||||
clipboard.writeText(downloadUrl)
|
||||
this.$message.success('『M3U8』格式的链接已复制, 快去下载吧!')
|
||||
})
|
||||
}
|
||||
zy.download(this.detail.key, this.info.id, this.videoFlag).then(res => {
|
||||
clipboard.writeText(res.downloadUrls)
|
||||
this.$message.success(res.info)
|
||||
}).catch((err) => {
|
||||
this.$message.error(err.info)
|
||||
})
|
||||
},
|
||||
shareEvent () {
|
||||
this.share = {
|
||||
show: true,
|
||||
key: this.detail.key,
|
||||
info: this.detail.info
|
||||
info: this.info
|
||||
}
|
||||
},
|
||||
doubanLinkEvent () {
|
||||
const name = this.detail.info.name.trim()
|
||||
zy.doubanLink(name).then(link => {
|
||||
const name = this.info.name.trim()
|
||||
const year = this.info.year
|
||||
zy.doubanLink(name, year).then(link => {
|
||||
const open = require('open')
|
||||
open(link)
|
||||
})
|
||||
},
|
||||
getDoubanRate () {
|
||||
const name = this.detail.info.name.trim()
|
||||
zy.doubanRate(name).then(res => {
|
||||
this.info.rate = res
|
||||
})
|
||||
async getDoubanRate () {
|
||||
const name = this.info.name.trim()
|
||||
const year = this.info.year
|
||||
this.info.rate = await zy.doubanRate(name, year)
|
||||
},
|
||||
getDetailInfo () {
|
||||
async getDetailInfo () {
|
||||
const id = this.detail.info.ids || this.detail.info.id
|
||||
zy.detail(this.detail.key, id).then(res => {
|
||||
if (res) {
|
||||
this.info = res
|
||||
this.$set(this.info, 'rate', '')
|
||||
this.m3u8List = res.m3u8List
|
||||
this.getDoubanRate()
|
||||
this.loading = false
|
||||
const cacheKey = this.detail.key + '@' + id
|
||||
const db = await history.find({ site: this.detail.key, ids: id })
|
||||
if (db) this.videoFlag = db.videoFlag
|
||||
if (!this.DetailCache[cacheKey]) {
|
||||
this.DetailCache[cacheKey] = await zy.detail(this.detail.key, id)
|
||||
}
|
||||
const res = this.DetailCache[cacheKey]
|
||||
if (res) {
|
||||
this.info = res
|
||||
this.$set(this.info, 'rate', this.DetailCache[cacheKey].rate || '')
|
||||
this.videoFlag = this.videoFlag || res.fullList[0].flag
|
||||
this.videoList = res.fullList[0].list
|
||||
this.videoFullList = res.fullList
|
||||
this.loading = false
|
||||
if (!this.info.rate) {
|
||||
await this.getDoubanRate()
|
||||
this.DetailCache[cacheKey].rate = this.info.rate
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
@@ -389,6 +414,15 @@ export default {
|
||||
margin: 6px 10px 0px 0px;
|
||||
padding: 8px 22px;
|
||||
}
|
||||
.selected {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
border: 1px solid;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
margin: 6px 10px 0px 0px;
|
||||
padding: 8px 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +94,9 @@
|
||||
<el-form-item label="下载接口" prop='download'>
|
||||
<el-input v-model="siteInfo.download" :autosize="{ minRows: 2, maxRows: 4}" type="textarea" placeholder="请输入Download接口地址,可以空着"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="解析接口" prop='jiexiUrl'>
|
||||
<el-input v-model="siteInfo.jiexiUrl" :autosize="{ minRows: 2, maxRows: 4}" type="textarea" placeholder="请输入解析接口地址,可以空着"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="分组" prop='group'>
|
||||
<el-select v-model="siteInfo.group" allow-create filterable default-first-option placeholder="请输入分组">
|
||||
<el-option v-for="item in siteGroup" :key="item" :label="item" :value="item"></el-option>
|
||||
@@ -133,6 +136,7 @@ export default {
|
||||
name: '',
|
||||
api: '',
|
||||
download: '',
|
||||
jiexiUrl: '',
|
||||
group: '',
|
||||
isActive: true
|
||||
},
|
||||
@@ -271,6 +275,7 @@ export default {
|
||||
name: '',
|
||||
api: '',
|
||||
download: '',
|
||||
jiexiUrl: '',
|
||||
group: '',
|
||||
isActive: true
|
||||
}
|
||||
@@ -329,6 +334,7 @@ export default {
|
||||
name: this.siteInfo.name,
|
||||
api: this.siteInfo.api,
|
||||
download: this.siteInfo.download,
|
||||
jiexiUrl: this.siteInfo.jiexiUrl,
|
||||
group: this.siteInfo.group,
|
||||
isActive: this.siteInfo.isActive
|
||||
}
|
||||
@@ -339,6 +345,7 @@ export default {
|
||||
name: '',
|
||||
api: '',
|
||||
download: '',
|
||||
jiexiUrl: '',
|
||||
group: ''
|
||||
}
|
||||
this.dialogType === 'edit' ? this.$message.success('修改成功!') : this.$message.success('新增源成功!')
|
||||
|
||||
@@ -332,6 +332,7 @@ export default {
|
||||
selectedSiteName: '',
|
||||
selectedClassName: '',
|
||||
selectedSearchClassNames: [],
|
||||
totalpagecount: 0,
|
||||
pagecount: 0,
|
||||
recordcount: 0,
|
||||
list: [],
|
||||
@@ -403,6 +404,14 @@ export default {
|
||||
this.SET_SETTING(val)
|
||||
}
|
||||
},
|
||||
DetailCache: {
|
||||
get () {
|
||||
return this.$store.getters.getDetailCache
|
||||
},
|
||||
set (val) {
|
||||
this.SET_DetailCache(val)
|
||||
}
|
||||
},
|
||||
filterSettings () {
|
||||
return this.$store.getters.getSetting.excludeR18Films // 需要监听的数据
|
||||
},
|
||||
@@ -468,7 +477,7 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SET_VIEW', 'SET_DETAIL', 'SET_VIDEO', 'SET_SHARE', 'SET_SETTING']),
|
||||
...mapMutations(['SET_VIEW', 'SET_DETAIL', 'SET_VIDEO', 'SET_SHARE', 'SET_SETTING', 'SET_DetailCache']),
|
||||
backTop () {
|
||||
const viewMode = this.showFind ? this.setting.searchViewMode : this.setting.view
|
||||
if (viewMode === 'picture') {
|
||||
@@ -591,12 +600,14 @@ export default {
|
||||
if (this.type.name.endsWith('剧')) this.selectedAreas = []
|
||||
const cacheKey = this.site.key + '@' + this.type.tid
|
||||
if (FILM_DATA_CACHE[cacheKey]) {
|
||||
this.totalpagecount = FILM_DATA_CACHE[cacheKey].totalpagecount
|
||||
this.pagecount = FILM_DATA_CACHE[cacheKey].pagecount
|
||||
this.recordcount = FILM_DATA_CACHE[cacheKey].recordcount
|
||||
this.list = FILM_DATA_CACHE[cacheKey].list
|
||||
this.areas = FILM_DATA_CACHE[cacheKey].areas
|
||||
} else {
|
||||
zy.page(this.site.key, this.type.tid).then(res => {
|
||||
this.totalpagecount = res.pagecount
|
||||
this.pagecount = res.pagecount
|
||||
this.recordcount = res.recordcount
|
||||
this.infiniteId += 1
|
||||
@@ -635,10 +646,20 @@ export default {
|
||||
}
|
||||
return this.r18KeyWords.some(v => name.includes(v))
|
||||
},
|
||||
toFlipPagecount () {
|
||||
// 似乎需要解析的网站的视频排序和其他m3u8采集站的顺序正好相反
|
||||
if (this.site.jiexiUrl) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
infiniteHandler ($state) {
|
||||
const key = this.site.key
|
||||
const typeTid = this.type.tid
|
||||
const page = this.pagecount
|
||||
var page = this.pagecount
|
||||
if (this.toFlipPagecount()) {
|
||||
page = this.totalpagecount - this.pagecount + 1
|
||||
}
|
||||
this.statusText = ' '
|
||||
if (key === undefined || page < 1 || typeTid === undefined) {
|
||||
$state.complete()
|
||||
@@ -658,8 +679,13 @@ export default {
|
||||
$state.complete()
|
||||
}
|
||||
if (type === '[object Array]') {
|
||||
// zy.list 返回的是按时间从旧到新排列, 我门需要翻转为从新到旧
|
||||
this.list.push(...res.reverse())
|
||||
if (!this.toFlipPagecount()) {
|
||||
// zy.list 返回的是按时间从旧到新排列, 我门需要翻转为从新到旧
|
||||
this.list.push(...res.reverse())
|
||||
} else {
|
||||
// 如果是需要解析的视频网站,zy.list已经是按从新到旧排列
|
||||
this.list.push(...res)
|
||||
}
|
||||
}
|
||||
if (type === '[object Object]') {
|
||||
this.list.push(res)
|
||||
@@ -691,9 +717,6 @@ export default {
|
||||
} else {
|
||||
this.video = { key: site.key, info: { id: e.id, name: e.name, index: 0, site: site } }
|
||||
}
|
||||
zy.detail(site.key, e.id).then(detailRes => {
|
||||
this.video.detail = detailRes
|
||||
})
|
||||
this.view = 'Play'
|
||||
},
|
||||
async starEvent (site, e) {
|
||||
@@ -701,17 +724,19 @@ export default {
|
||||
if (db) {
|
||||
this.$message.info('已存在')
|
||||
} else {
|
||||
zy.detail(site.key, e.id).then(detailRes => {
|
||||
const docs = {
|
||||
key: site.key,
|
||||
ids: e.id,
|
||||
site: site,
|
||||
name: e.name,
|
||||
detail: detailRes
|
||||
}
|
||||
star.add(docs).then(res => {
|
||||
this.$message.success('收藏成功')
|
||||
})
|
||||
const cacheKey = site.key + '@' + e.id
|
||||
if (!this.DetailCache[cacheKey]) {
|
||||
this.DetailCache[cacheKey] = await zy.detail(site.key, e.id)
|
||||
}
|
||||
const docs = {
|
||||
key: site.key,
|
||||
ids: e.id,
|
||||
site: site,
|
||||
name: e.name,
|
||||
detail: this.DetailCache[cacheKey]
|
||||
}
|
||||
star.add(docs).then(res => {
|
||||
this.$message.success('收藏成功')
|
||||
})
|
||||
}
|
||||
},
|
||||
@@ -722,31 +747,15 @@ export default {
|
||||
info: e
|
||||
}
|
||||
},
|
||||
downloadEvent (site, row) {
|
||||
const key = site.key
|
||||
const id = row.id
|
||||
zy.download(key, id).then(res => {
|
||||
if (res && res.m3u8List) {
|
||||
const list = res.m3u8List.split('#')
|
||||
let downloadUrl = ''
|
||||
for (const i of list) {
|
||||
const url = encodeURI(i.split('$')[1])
|
||||
downloadUrl += (url + '\n')
|
||||
}
|
||||
clipboard.writeText(downloadUrl)
|
||||
this.$message.success('『MP4』格式的链接已复制, 快去下载吧!')
|
||||
} else {
|
||||
zy.detail(key, id).then(res => {
|
||||
const list = [...res.m3u8List]
|
||||
let downloadUrl = ''
|
||||
for (const i of list) {
|
||||
const url = encodeURI(i.split('$')[1])
|
||||
downloadUrl += (url + '\n')
|
||||
}
|
||||
clipboard.writeText(downloadUrl)
|
||||
this.$message.success('『M3U8』格式的链接已复制, 快去下载吧!')
|
||||
})
|
||||
}
|
||||
async downloadEvent (site, row) {
|
||||
const db = await history.find({ site: site.key, ids: row.id })
|
||||
let videoFlag
|
||||
if (db) videoFlag = db.videoFlag
|
||||
zy.download(site.key, row.id, videoFlag).then(res => {
|
||||
clipboard.writeText(res.downloadUrls)
|
||||
this.$message.success(res.info)
|
||||
}).catch((err) => {
|
||||
this.$message.error(err.info)
|
||||
})
|
||||
},
|
||||
querySearch (queryString, cb) {
|
||||
|
||||
@@ -35,8 +35,8 @@
|
||||
width="180"
|
||||
label="观看至">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.detail && scope.row.detail.m3u8List && scope.row.detail.m3u8List.length > 1">
|
||||
第{{ scope.row.index + 1 }}集(共{{scope.row.detail.m3u8List.length}}集)
|
||||
<span v-if="scope.row.detail && scope.row.detail.fullList[0].list && scope.row.detail.fullList[0].list.length > 1">
|
||||
第{{ scope.row.index + 1 }}集(共{{scope.row.detail.fullList[0].list.length}}集)
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -45,6 +45,7 @@
|
||||
label="时间进度">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.time && scope.row.duration">{{fmtMSS(scope.row.time.toFixed(0))}}/{{fmtMSS(scope.row.duration.toFixed(0))}}</span>
|
||||
<span v-if="scope.row.onlinePlay">在线解析</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
@@ -94,8 +95,9 @@
|
||||
<span v-if="props.data.time && props.data.duration">
|
||||
{{fmtMSS(props.data.time.toFixed(0))}}/{{fmtMSS(props.data.duration.toFixed(0))}}
|
||||
</span>
|
||||
<span v-if="props.data.detail && props.data.detail.m3u8List !== undefined && props.data.detail.m3u8List.length > 1">
|
||||
第{{ props.data.index + 1 }}集(共{{props.data.detail.m3u8List.length}}集)
|
||||
<span v-if="props.data.onlinePlay">在线解析</span>
|
||||
<span v-if="props.data.detail && props.data.detail.fullList[0].list !== undefined && props.data.detail.fullList[0].list.length > 1">
|
||||
第{{ props.data.index + 1 }}集(共{{props.data.detail.fullList[0].list.length}}集)
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -230,43 +232,21 @@ export default {
|
||||
} else {
|
||||
this.video = { key: e.site, info: { id: e.ids, name: e.name, index: 0 } }
|
||||
}
|
||||
zy.detail(e.site, e.ids).then(detailRes => {
|
||||
this.video.detail = detailRes
|
||||
})
|
||||
this.view = 'Play'
|
||||
},
|
||||
shareEvent (e) {
|
||||
this.share = {
|
||||
show: true,
|
||||
key: e.site,
|
||||
info: e
|
||||
info: e.detail
|
||||
}
|
||||
},
|
||||
downloadEvent (e) {
|
||||
const key = e.site
|
||||
const id = e.ids
|
||||
zy.download(key, id).then(res => {
|
||||
if (res && res.m3u8List) {
|
||||
const list = res.m3u8List.split('#')
|
||||
let downloadUrl = ''
|
||||
for (const i of list) {
|
||||
const url = encodeURI(i.split('$')[1])
|
||||
downloadUrl += (url + '\n')
|
||||
}
|
||||
clipboard.writeText(downloadUrl)
|
||||
this.$message.success('『MP4』格式的链接已复制, 快去下载吧!')
|
||||
} else {
|
||||
zy.detail(key, id).then(res => {
|
||||
const list = [...res.m3u8List]
|
||||
let downloadUrl = ''
|
||||
for (const i of list) {
|
||||
const url = encodeURI(i.split('$')[1])
|
||||
downloadUrl += (url + '\n')
|
||||
}
|
||||
clipboard.writeText(downloadUrl)
|
||||
this.$message.success('『M3U8』格式的链接已复制, 快去下载吧!')
|
||||
})
|
||||
}
|
||||
zy.download(e.site, e.ids, e.videoFlag).then(res => {
|
||||
clipboard.writeText(res.downloadUrls)
|
||||
this.$message.success(res.info)
|
||||
}).catch((err) => {
|
||||
this.$message.error(err.info)
|
||||
})
|
||||
},
|
||||
exportHistory () {
|
||||
@@ -342,6 +322,7 @@ export default {
|
||||
})
|
||||
},
|
||||
rowDrop () {
|
||||
if (!document.getElementById('history-table')) return
|
||||
const tbody = document.getElementById('history-table').querySelector('.el-table__body-wrapper tbody')
|
||||
const _this = this
|
||||
Sortable.create(tbody, {
|
||||
|
||||
@@ -4,11 +4,16 @@
|
||||
<div class="title">
|
||||
<span v-if="this.right.list.length > 1">『第 {{(video.info.index + 1)}} 集』</span>{{name}}
|
||||
</div>
|
||||
<div class="player">
|
||||
<div class="player" v-show="!onlineUrl">
|
||||
<div id="xgplayer"></div>
|
||||
</div>
|
||||
<div class="iframePlayer" v-if="onlineUrl" style='width:100%;height:100%;'>
|
||||
<iframe v-bind:src="onlineUrl" width="100%" height="100%"
|
||||
frameborder="0" scrolling="no" allow='autoplay;fullscreen'>
|
||||
</iframe>
|
||||
</div>
|
||||
<div class="more" v-if="!video.iptv" :key="Boolean(video.iptv)">
|
||||
<span class="zy-svg" @click="otherEvent" v-show="name !== ''">
|
||||
<span class="zy-svg" @click="otherEvent" v-show="name !== ''" :class="right.type === 'other' ? 'active' : ''">
|
||||
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-labelledby="coloursIconTitle">
|
||||
<title id="coloursIconTitle">换源</title>
|
||||
<circle cx="12" cy="9" r="5"></circle>
|
||||
@@ -84,7 +89,7 @@
|
||||
<rect x="17" y="6" width="1" height="1"></rect>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="zy-svg" @click="showShortcutEvent" v-show="right.list.length > 0">
|
||||
<span class="zy-svg" @click="showShortcutEvent" :class="right.type === 'shortcut' ? 'active' : ''" v-show="right.list.length > 0">
|
||||
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-labelledby="sendIconTitle">
|
||||
<title id="sendIconTitle">快捷键指南</title>
|
||||
<polygon points="21.368 12.001 3 21.609 3 14 11 12 3 9.794 3 2.394"></polygon>
|
||||
@@ -98,7 +103,7 @@
|
||||
<circle cx="12" cy="12" r="10"></circle>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="timespanSwitch" v-if="right.list.length > 1" title="跳过片头片尾,建议优先通过快捷键设置,更便捷更精准">
|
||||
<span class="timespanSwitch" v-if="right.list.length > 1 && !onlineUrl" title="跳过片头片尾,建议优先通过快捷键设置,更便捷更精准">
|
||||
<el-switch v-model="state.showTimespanSetting" active-text="手动跳略时长"></el-switch>
|
||||
</span>
|
||||
<span class="timespan" v-if="state.showTimespanSetting">
|
||||
@@ -116,11 +121,14 @@
|
||||
<span></span>
|
||||
<input type="button" value="重置" @click="() => { startPosition.min = startPosition.sec = endPosition.min = endPosition.sec = '00'; this.clearPosition() }">
|
||||
</span>
|
||||
<span class="last-tip" v-if="!video.key && right.history.length > 0" @click="historyItemEvent(right.history[0])">
|
||||
上次播放到:【{{right.history[0].site}}】{{right.history[0].name}} 第{{right.history[0].index+1}}集 {{fmtMSS(right.history[0].time.toFixed(0))}}/{{fmtMSS(right.history[0].duration.toFixed(0))}}</span>
|
||||
<span class="last-tip" v-if="!video.key && right.history.length > 0 && right.history[0]" @click="historyItemEvent(right.history[0])">
|
||||
<span>上次播放到:【{{right.history[0].site}}】{{right.history[0].name}} 第{{right.history[0].index+1}}集 </span>
|
||||
<span v-if="right.history[0].time && right.history[0].duration">{{fmtMSS(right.history[0].time.toFixed(0))}}/{{fmtMSS(right.history[0].duration.toFixed(0))}}</span>
|
||||
<span v-if="right.history[0].onlinePlay">在线解析</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="more" v-if="video.iptv" :key="Boolean(video.iptv)">
|
||||
<span class="zy-svg" @click="state.showChannelList = !state.showChannelList">
|
||||
<span class="zy-svg" @click="state.showChannelList = !state.showChannelList" :class="state.showChannelList ? 'active' : ''">
|
||||
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-labelledby="dashboardIconTitle">
|
||||
<title id="dashboardIconTitle">频道列表</title>
|
||||
<rect width="20" height="20" x="2" y="2"></rect>
|
||||
@@ -130,7 +138,7 @@
|
||||
<line x1="7" y1="17" x2="7" y2="17"></line>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="zy-svg" @click="otherEvent">
|
||||
<span class="zy-svg" @click="otherEvent" :class="right.type === 'sources' ? 'active' : ''">
|
||||
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-labelledby="coloursIconTitle">
|
||||
<title id="coloursIconTitle">换源</title>
|
||||
<circle cx="12" cy="9" r="5"></circle>
|
||||
@@ -151,7 +159,7 @@
|
||||
<polyline stroke-linejoin="round" points="8 4 12 7.917 16 4"></polyline>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="zy-svg" @click="showShortcutEvent">
|
||||
<span class="zy-svg" @click="showShortcutEvent" :class="right.type === 'shortcut' ? 'active' : ''">
|
||||
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-labelledby="sendIconTitle">
|
||||
<title id="sendIconTitle">快捷键指南</title>
|
||||
<polygon points="21.368 12.001 3 21.609 3 14 11 12 3 9.794 3 2.394"></polygon>
|
||||
@@ -175,24 +183,24 @@
|
||||
</span>
|
||||
</div>
|
||||
<div class="list-body zy-scroll" :style="{overflowY:scroll? 'auto' : 'hidden',paddingRight: scroll ? '0': '5px' }" @mouseenter="scroll = true" @mouseleave="scroll = false">
|
||||
<ul v-if="right.type === 'list'" class="list-item" v-on-clickaway="closeListEvent">
|
||||
<li v-if="right.list.length > 0" @click="exportM3u8">导出</li>
|
||||
<ul v-if="right.type === 'list'" class="list-item" v-clickoutside="closeListEvent">
|
||||
<li v-if="exportablePlaylist" @click="exportM3u8">导出</li>
|
||||
<li v-if="right.list.length === 0">无数据</li>
|
||||
<li @click="listItemEvent(j)" :class="video.info.index === j ? 'active' : ''" v-for="(i, j) in right.list" :key="j">{{i | ftName(j)}}</li>
|
||||
</ul>
|
||||
<ul v-if="right.type === 'history'" class="list-history" v-on-clickaway="closeListEvent">
|
||||
<ul v-if="right.type === 'history'" class="list-history" v-clickoutside="closeListEvent">
|
||||
<li v-if="right.history.length > 0" @click="clearAllHistory">清空</li>
|
||||
<li v-if="right.history.length === 0">无数据</li>
|
||||
<li @click="historyItemEvent(m)" :class="video.info.id === m.ids ? 'active' : ''" v-for="(m, n) in right.history" :key="n"><span class="title" :title="'【' + m.site + '】' + m.name + ' 第' + (m.index+1) + '集'">【{{m.site}}】{{m.name}} 第{{m.index+1}}集</span><span @click.stop="removeHistoryItem(m)" class="detail-delete">删除</span></li>
|
||||
</ul>
|
||||
<ul v-if="right.type === 'shortcut'" class="list-shortcut" v-on-clickaway="closeListEvent">
|
||||
<ul v-if="right.type === 'shortcut'" class="list-shortcut" v-clickoutside="closeListEvent">
|
||||
<li v-for="(m, n) in right.shortcut" :key="n"><span class="title">{{m.desc}} -- [ {{m.key}} ]</span></li>
|
||||
</ul>
|
||||
<ul v-if="right.type === 'other'" class="list-other" v-on-clickaway="closeListEvent">
|
||||
<ul v-if="right.type === 'other'" class="list-other" v-clickoutside="closeListEvent">
|
||||
<li v-if="right.other.length === 0">无数据</li>
|
||||
<li @click="otherItemEvent(m)" v-for="(m, n) in right.other" :key="n"><span class="title">{{m.name}} - [{{m.site.name}}]</span></li>
|
||||
</ul>
|
||||
<ul v-if="right.type === 'sources'" class="list-channels" v-on-clickaway="closeListEvent">
|
||||
<ul v-if="right.type === 'sources'" class="list-channels" v-clickoutside="closeListEvent">
|
||||
<li v-if="right.sources.length === 0">当前频道已关闭</li>
|
||||
<li v-for="(channel, index) in right.sources" :key="index">
|
||||
<span @click="playChannel(channel)" class="title">{{ channel.id === video.iptv.id ? channel.name + '[当前]' : channel.name }}</span>
|
||||
@@ -203,7 +211,7 @@
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="slideX">
|
||||
<div v-if="state.showChannelList" class="list" v-on-clickaway="closeListEvent">
|
||||
<div v-if="state.showChannelList" class="list" v-clickoutside="closeListEvent">
|
||||
<div class="list-top">
|
||||
<span class="list-top-title">频道列表</span>
|
||||
<span class="list-top-close zy-svg" @click="state.showChannelList = false">
|
||||
@@ -239,8 +247,9 @@ import { star, history, setting, shortcut, mini, channelList, sites } from '../l
|
||||
import zy from '../lib/site/tools'
|
||||
import Player from 'xgplayer'
|
||||
import HlsJsPlayer from 'xgplayer-hls.js'
|
||||
import FlvJsPlayer from 'xgplayer-flv.js'
|
||||
import mt from 'mousetrap'
|
||||
import { directive as onClickaway } from 'vue-clickaway'
|
||||
import Clickoutside from 'element-ui/src/utils/clickoutside'
|
||||
import { exec, execFile } from 'child_process'
|
||||
|
||||
const { remote, clipboard } = require('electron')
|
||||
@@ -327,7 +336,7 @@ export default {
|
||||
videoTitle: true,
|
||||
airplay: true,
|
||||
closeVideoTouch: true,
|
||||
ignores: ['cssFullscreen', 'replay'],
|
||||
ignores: ['cssFullscreen', 'replay', 'error'], // 为了切换播放器类型时避免显示错误刷新,暂时忽略错误
|
||||
preloadTime: 300
|
||||
},
|
||||
state: {
|
||||
@@ -341,7 +350,6 @@ export default {
|
||||
timer: null,
|
||||
scroll: false,
|
||||
isStar: false,
|
||||
isTop: false,
|
||||
miniMode: false,
|
||||
mainWindowBounds: {},
|
||||
searchTxt: '',
|
||||
@@ -355,7 +363,10 @@ export default {
|
||||
startPosition: { min: '00', sec: '00' }, // 对应调略输入框
|
||||
endPosition: { min: '00', sec: '00' },
|
||||
skipendStatus: false, // 是否跳过了片尾
|
||||
currentShortcutList: []
|
||||
currentShortcutList: [],
|
||||
onlineUrl: '',
|
||||
playerType: 'hls',
|
||||
exportablePlaylist: false
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
@@ -369,7 +380,7 @@ export default {
|
||||
}
|
||||
},
|
||||
directives: {
|
||||
onClickaway: onClickaway
|
||||
Clickoutside
|
||||
},
|
||||
computed: {
|
||||
view: {
|
||||
@@ -419,6 +430,14 @@ export default {
|
||||
set (val) {
|
||||
this.SET_SETTING(val)
|
||||
}
|
||||
},
|
||||
DetailCache: {
|
||||
get () {
|
||||
return this.$store.getters.getDetailCache
|
||||
},
|
||||
set (val) {
|
||||
this.SET_DetailCache(val)
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -472,7 +491,7 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SET_VIEW', 'SET_DETAIL', 'SET_VIDEO', 'SET_SHARE', 'SET_APPSTATE']),
|
||||
...mapMutations(['SET_VIEW', 'SET_DETAIL', 'SET_VIDEO', 'SET_SHARE', 'SET_APPSTATE', 'SET_DetailCache']),
|
||||
fmtMSS (s) {
|
||||
return (s - (s %= 60)) / 60 + (s > 9 ? ':' : ':0') + s
|
||||
},
|
||||
@@ -502,6 +521,7 @@ export default {
|
||||
return false
|
||||
}
|
||||
this.name = ''
|
||||
this.onlineUrl = ''
|
||||
if (this.timer !== null) {
|
||||
clearInterval(this.timer)
|
||||
this.timer = null
|
||||
@@ -520,12 +540,14 @@ export default {
|
||||
const key = this.video.key + '@' + this.video.info.id
|
||||
var time = this.video.info.time
|
||||
this.xg.removeAllProgressDot()
|
||||
this.startPosition = this.endPosition = { min: '00', sec: '00' }
|
||||
this.startPosition = { min: '00', sec: '00' }
|
||||
this.endPosition = { min: '00', sec: '00' }
|
||||
if (db) {
|
||||
if (!time && db.index === index) { // 如果video.info.time没有设定的话,从历史中读取时间进度
|
||||
time = db.time
|
||||
}
|
||||
if (!VIDEO_DETAIL_CACHE[key]) VIDEO_DETAIL_CACHE[key] = {}
|
||||
if (!this.video.info.videoFlag) this.video.info.videoFlag = db.videoFlag
|
||||
if (db.startPosition) { // 数据库保存的时长通过快捷键设置时可能为小数, this.startPosition为object对应输入框分秒转化到数据库后肯定为整数
|
||||
VIDEO_DETAIL_CACHE[key].startPosition = db.startPosition
|
||||
this.startPosition = { min: '' + parseInt(db.startPosition / 60), sec: '' + parseInt(db.startPosition % 60) }
|
||||
@@ -550,6 +572,7 @@ export default {
|
||||
},
|
||||
playChannel (channel) {
|
||||
this.isLive = true
|
||||
this.getPlayer('hls')
|
||||
if (channel.channels) {
|
||||
this.right.sources = channel.channels.filter(e => e.isActive)
|
||||
channel = channel.prefer ? channel.channels.find(e => e.id === channel.prefer) : channel.channels.filter(e => e.isActive)[0]
|
||||
@@ -567,112 +590,145 @@ export default {
|
||||
document.querySelector('xg-btn-showhistory').style.display = 'none'
|
||||
document.querySelector('.xgplayer-playbackrate').style.display = 'none'
|
||||
},
|
||||
getPlayer (playerType, force = false) {
|
||||
if (!force && this.playerType === playerType) return
|
||||
this.xg.src = ''
|
||||
this.config.url = ''
|
||||
this.xg.destroy()
|
||||
this.xg = null
|
||||
switch (playerType) {
|
||||
case 'mp4':
|
||||
this.xg = new Player(this.config)
|
||||
break
|
||||
case 'flv':
|
||||
this.xg = new FlvJsPlayer(this.config)
|
||||
break
|
||||
default:
|
||||
this.xg = new HlsJsPlayer(this.config)
|
||||
}
|
||||
this.playerInstall()
|
||||
this.bindEvent()
|
||||
this.playerType = playerType
|
||||
},
|
||||
playVideo (index = 0, time = 0) {
|
||||
this.isLive = false
|
||||
document.querySelector('xg-btn-showhistory').style.display = 'block'
|
||||
document.querySelector('.xgplayer-playbackrate').style.display = 'inline-block'
|
||||
this.fetchM3u8List().then(m3u8Arr => {
|
||||
const url = m3u8Arr[index]
|
||||
if (!m3u8Arr[index].endsWith('.m3u8')) {
|
||||
const onlineUrl = 'https://www.1717yun.com/jiexi/?url=' + url
|
||||
const open = require('open')
|
||||
open(onlineUrl)
|
||||
} else {
|
||||
this.xg.src = m3u8Arr[index]
|
||||
const key = this.video.key + '@' + this.video.info.id
|
||||
const startTime = VIDEO_DETAIL_CACHE[key].startPosition || 0
|
||||
this.xg.play()
|
||||
this.xg.once('playing', () => {
|
||||
this.xg.currentTime = time > startTime ? time : startTime
|
||||
if (VIDEO_DETAIL_CACHE[key].startPosition) this.xg.addProgressDot(VIDEO_DETAIL_CACHE[key].startPosition, '片头')
|
||||
if (VIDEO_DETAIL_CACHE[key].endPosition) this.xg.addProgressDot(this.xg.duration - VIDEO_DETAIL_CACHE[key].endPosition, '片尾')
|
||||
})
|
||||
this.videoPlaying()
|
||||
this.skipendStatus = false
|
||||
this.xg.once('ended', () => {
|
||||
if (m3u8Arr.length > 1 && (m3u8Arr.length - 1 > index)) {
|
||||
this.video.info.time = 0
|
||||
this.video.info.index++
|
||||
}
|
||||
this.xg.off('ended') // 明明是once为何会触发多次,得注销掉以真正只执行一次
|
||||
})
|
||||
this.exportablePlaylist = false
|
||||
this.fetchPlaylist().then(async (fullList) => {
|
||||
var playlist = fullList[0].list // ZY支持的已移到首位
|
||||
// 如果设定了特定的video flag, 获取该flag下的视频列表
|
||||
const videoFlag = this.video.info.videoFlag
|
||||
if (videoFlag) {
|
||||
playlist = fullList.find(x => x.flag === videoFlag).list
|
||||
}
|
||||
this.right.list = playlist
|
||||
var url = playlist[index].split('$')[1]
|
||||
if (playlist.every(e => e.split('$')[1].endsWith('.m3u8'))) this.exportablePlaylist = true
|
||||
if (!url.endsWith('.m3u8') && !url.endsWith('.mp4')) {
|
||||
const currentSite = await sites.find({ key: this.video.key })
|
||||
this.$message.info('即将调用解析接口播放,请等待...')
|
||||
if (currentSite.jiexiUrl) {
|
||||
this.onlineUrl = currentSite.jiexiUrl + url
|
||||
} else {
|
||||
this.onlineUrl = 'https://jx.7kjx.com/?url=' + url
|
||||
}
|
||||
this.videoPlaying('online')
|
||||
return
|
||||
} else {
|
||||
const ext = url.match(/\.\w+?$/)[0].slice(1)
|
||||
this.getPlayer(ext)
|
||||
}
|
||||
this.xg.src = url
|
||||
const key = this.video.key + '@' + this.video.info.id
|
||||
const startTime = VIDEO_DETAIL_CACHE[key].startPosition || 0
|
||||
this.xg.play()
|
||||
if (document.querySelector('xg-btn-showhistory')) document.querySelector('xg-btn-showhistory').style.display = 'block'
|
||||
if (document.querySelector('.xgplayer-playbackrate')) document.querySelector('.xgplayer-playbackrate').style.display = 'inline-block'
|
||||
this.xg.once('playing', () => {
|
||||
this.xg.currentTime = time > startTime ? time : startTime
|
||||
if (VIDEO_DETAIL_CACHE[key].startPosition) this.xg.addProgressDot(VIDEO_DETAIL_CACHE[key].startPosition, '片头')
|
||||
if (VIDEO_DETAIL_CACHE[key].endPosition) this.xg.addProgressDot(this.xg.duration - VIDEO_DETAIL_CACHE[key].endPosition, '片尾')
|
||||
})
|
||||
this.videoPlaying()
|
||||
this.skipendStatus = false
|
||||
this.xg.once('ended', () => {
|
||||
if (playlist.length > 1 && (playlist.length - 1 > index)) {
|
||||
this.video.info.time = 0
|
||||
this.video.info.index++
|
||||
}
|
||||
this.xg.off('ended') // 明明是once为何会触发多次,得注销掉以真正只执行一次
|
||||
})
|
||||
})
|
||||
},
|
||||
fetchM3u8List () {
|
||||
fetchPlaylist () {
|
||||
return new Promise((resolve) => {
|
||||
const cacheKey = this.video.key + '@' + this.video.info.id
|
||||
if (VIDEO_DETAIL_CACHE[cacheKey] && VIDEO_DETAIL_CACHE[cacheKey].list && VIDEO_DETAIL_CACHE[cacheKey].list.length) {
|
||||
this.name = VIDEO_DETAIL_CACHE[cacheKey].name
|
||||
resolve(VIDEO_DETAIL_CACHE[cacheKey].list)
|
||||
}
|
||||
zy.detail(this.video.key, this.video.info.id).then(res => {
|
||||
let res
|
||||
if (!this.DetailCache[cacheKey]) {
|
||||
zy.detail(this.video.key, this.video.info.id).then(res => {
|
||||
this.DetailCache[cacheKey] = res
|
||||
res = this.DetailCache[cacheKey]
|
||||
this.name = res.name
|
||||
VIDEO_DETAIL_CACHE[cacheKey] = Object.assign(VIDEO_DETAIL_CACHE[cacheKey] || { }, {
|
||||
list: res.fullList,
|
||||
name: res.name
|
||||
})
|
||||
resolve(res.fullList)
|
||||
})
|
||||
} else {
|
||||
res = this.DetailCache[cacheKey]
|
||||
this.name = res.name
|
||||
const m3u8Txt = res.m3u8List
|
||||
this.right.list = m3u8Txt
|
||||
const m3u8Arr = []
|
||||
for (const i of m3u8Txt) {
|
||||
const j = i.split('$')
|
||||
if (j.length > 1) {
|
||||
for (let m = 0; m < j.length; m++) {
|
||||
if (j[m].startsWith('http')) {
|
||||
m3u8Arr.push(j[m])
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
m3u8Arr.push(j[0])
|
||||
}
|
||||
}
|
||||
|
||||
VIDEO_DETAIL_CACHE[cacheKey] = Object.assign(VIDEO_DETAIL_CACHE[cacheKey] || {}, {
|
||||
list: m3u8Arr,
|
||||
VIDEO_DETAIL_CACHE[cacheKey] = Object.assign(VIDEO_DETAIL_CACHE[cacheKey] || { }, {
|
||||
list: res.fullList,
|
||||
name: res.name
|
||||
})
|
||||
resolve(m3u8Arr)
|
||||
})
|
||||
resolve(res.fullList)
|
||||
}
|
||||
})
|
||||
},
|
||||
async videoPlaying () {
|
||||
this.changeVideo()
|
||||
async videoPlaying (isOnline) {
|
||||
const db = await history.find({ site: this.video.key, ids: this.video.info.id })
|
||||
const videoFlag = this.video.info.videoFlag || ''
|
||||
let time = this.xg.currentTime || 0
|
||||
let duration = this.xg.duration || 0
|
||||
let startPosition = 0
|
||||
let endPosition = 0
|
||||
if (db) {
|
||||
const doc = {
|
||||
site: db.site,
|
||||
ids: db.ids,
|
||||
name: db.name,
|
||||
type: db.type,
|
||||
year: db.year,
|
||||
index: this.video.info.index,
|
||||
time: db.time,
|
||||
detail: this.video.detail
|
||||
}
|
||||
history.update(db.id, doc)
|
||||
} else {
|
||||
const doc = {
|
||||
site: this.video.key,
|
||||
ids: this.video.info.id,
|
||||
name: this.video.info.name,
|
||||
type: this.video.info.type,
|
||||
year: this.video.info.year,
|
||||
index: this.video.info.index,
|
||||
time: '',
|
||||
detail: this.video.detail
|
||||
}
|
||||
history.add(doc)
|
||||
time = time || db.time
|
||||
duration = duration || db.duration
|
||||
startPosition = db.startPosition
|
||||
endPosition = db.endPosition
|
||||
await history.remove(db.id)
|
||||
}
|
||||
if (isOnline) {
|
||||
time = duration = 0
|
||||
}
|
||||
const doc = {
|
||||
site: this.video.key,
|
||||
ids: this.video.info.id,
|
||||
name: this.video.info.name,
|
||||
type: this.video.info.type,
|
||||
year: this.video.info.year,
|
||||
index: this.video.info.index,
|
||||
time: time,
|
||||
duration: duration,
|
||||
startPosition: startPosition,
|
||||
endPosition: endPosition,
|
||||
detail: this.DetailCache[this.video.key + '@' + this.video.info.id],
|
||||
onlinePlay: isOnline,
|
||||
videoFlag: videoFlag
|
||||
}
|
||||
await history.add(doc)
|
||||
this.updateStar()
|
||||
this.timerEvent()
|
||||
},
|
||||
changeVideo () {
|
||||
win.setProgressBar(-1)
|
||||
this.checkStar()
|
||||
this.checkTop()
|
||||
if (!isOnline) this.timerEvent()
|
||||
},
|
||||
async setProgressDotEvent (position, timespan, text) { // 根据跳略时长在进度条上添加标记, position为位置, timespan为时长,text为标记文本(title)
|
||||
const key = this.video.key + '@' + this.video.info.id
|
||||
const db = await history.find({ site: this.video.key, ids: this.video.info.id })
|
||||
if (db && this.xg && VIDEO_DETAIL_CACHE[key].list.length > 1) {
|
||||
if (db && this.xg && this.right.list.length > 1) {
|
||||
this[position] = { min: '' + parseInt(timespan / 60), sec: '' + parseInt(timespan % 60) }
|
||||
const positionTime = position === 'endPosition' ? this.xg.duration - timespan : timespan
|
||||
if (db[position]) this.xg.removeProgressDot(position === 'endPosition' ? this.xg.duration - db[position] : db[position])
|
||||
@@ -702,10 +758,6 @@ export default {
|
||||
},
|
||||
timerEvent () {
|
||||
this.timer = setInterval(async () => {
|
||||
const endTime = this.xg.duration
|
||||
const currentTime = this.xg.currentTime
|
||||
const progress = parseFloat((currentTime / endTime).toFixed(2))
|
||||
win.setProgressBar(progress)
|
||||
const db = await history.find({ site: this.video.key, ids: this.video.info.id })
|
||||
if (db) {
|
||||
const doc = { ...db }
|
||||
@@ -781,13 +833,15 @@ export default {
|
||||
const info = this.video.info
|
||||
const db = await star.find({ key: this.video.key, ids: info.id })
|
||||
if (db) {
|
||||
this.isStar = true
|
||||
db.index = info.index
|
||||
star.update(db.id, db)
|
||||
} else {
|
||||
this.isStar = false
|
||||
}
|
||||
},
|
||||
async starEvent () {
|
||||
const info = this.video.info
|
||||
const db = await star.find({ key: this.video.key, ids: info.id })
|
||||
const db = await star.find({ key: this.video.key, ids: this.video.info.id })
|
||||
if (db) {
|
||||
star.remove(db.id).then(res => {
|
||||
if (res) {
|
||||
@@ -798,18 +852,16 @@ export default {
|
||||
}
|
||||
})
|
||||
} else {
|
||||
zy.detail(this.video.key, info.id).then(detailRes => {
|
||||
const docs = {
|
||||
key: this.video.key,
|
||||
ids: info.id,
|
||||
name: info.name,
|
||||
detail: detailRes,
|
||||
index: info.index
|
||||
}
|
||||
star.add(docs).then(res => {
|
||||
this.$message.success('收藏成功')
|
||||
this.isStar = true
|
||||
})
|
||||
const docs = {
|
||||
key: this.video.key,
|
||||
ids: this.video.info.id,
|
||||
name: this.video.info.name,
|
||||
detail: this.DetailCache[this.video.key + '@' + this.video.info.id],
|
||||
index: this.video.info.index
|
||||
}
|
||||
star.add(docs).then(res => {
|
||||
this.$message.success('收藏成功')
|
||||
this.isStar = true
|
||||
})
|
||||
}
|
||||
},
|
||||
@@ -852,14 +904,14 @@ export default {
|
||||
this.share = {
|
||||
show: true,
|
||||
key: this.video.key,
|
||||
info: this.video.info
|
||||
info: this.DetailCache[this.video.key + '@' + this.video.info.id]
|
||||
}
|
||||
},
|
||||
issueEvent () {
|
||||
const info = {
|
||||
video: this.video,
|
||||
list: this.right.list,
|
||||
m3u8List: VIDEO_DETAIL_CACHE[this.video.key + '@' + this.video.info.id] || [],
|
||||
playlist: VIDEO_DETAIL_CACHE[this.video.key + '@' + this.video.info.id] || [],
|
||||
playerError: this.xg.error || '',
|
||||
playerState: this.xg.readyState || '',
|
||||
networkState: this.xg.networkState || ''
|
||||
@@ -869,8 +921,8 @@ export default {
|
||||
},
|
||||
playWithExternalPalyerEvent () {
|
||||
const fs = require('fs')
|
||||
const externalPlayer = this.setting.externalPlayer
|
||||
if (this.video.iptv) {
|
||||
var externalPlayer = this.setting.externalPlayer
|
||||
if (!externalPlayer) {
|
||||
this.$message.error('请设置第三方播放器路径')
|
||||
return
|
||||
@@ -880,25 +932,30 @@ export default {
|
||||
} else {
|
||||
exec(externalPlayer, [this.video.iptv.url])
|
||||
}
|
||||
return
|
||||
}
|
||||
this.fetchM3u8List().then(m3u8Arr => {
|
||||
var externalPlayer = this.setting.externalPlayer
|
||||
} else {
|
||||
const playlistUrls = this.right.list.map(e => e.split('$')[1])
|
||||
if (!externalPlayer) {
|
||||
this.$message.error('请设置第三方播放器路径')
|
||||
// 在线播放该视频
|
||||
var link = 'https://www.m3u8play.com/?play=' + m3u8Arr[this.video.info.index]
|
||||
const open = require('open')
|
||||
open(link)
|
||||
if (playlistUrls[this.video.info.index].endsWith('.m3u8')) {
|
||||
var link = 'https://www.m3u8play.com/?play=' + playlistUrls[this.video.info.index]
|
||||
const open = require('open')
|
||||
open(link)
|
||||
}
|
||||
} else {
|
||||
var m3uFile = this.generateM3uFile(this.video.info.name, m3u8Arr, this.video.info.index)
|
||||
if (fs.existsSync(externalPlayer)) {
|
||||
execFile(externalPlayer, [m3uFile])
|
||||
let playlist
|
||||
if (playlistUrls.every(e => e.endsWith('.m3u8'))) {
|
||||
playlist = this.generateM3uFile(this.video.info.name, playlistUrls, this.video.info.index)
|
||||
} else {
|
||||
exec(externalPlayer, [m3uFile])
|
||||
playlist = playlistUrls[this.video.info.index]
|
||||
}
|
||||
if (fs.existsSync(externalPlayer)) {
|
||||
execFile(externalPlayer, [playlist])
|
||||
} else {
|
||||
exec(externalPlayer, [playlist])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
generateM3uFile (fileName, m3u8Arr, startIndex) {
|
||||
const path = require('path')
|
||||
@@ -917,21 +974,18 @@ export default {
|
||||
fs.writeFileSync(filePath, str)
|
||||
return filePath
|
||||
},
|
||||
async checkStar () {
|
||||
const db = await star.find({ key: this.video.key, ids: this.video.info.id })
|
||||
if (db) {
|
||||
this.isStar = true
|
||||
} else {
|
||||
this.isStar = false
|
||||
}
|
||||
},
|
||||
checkTop () {
|
||||
this.isTop = this.appState.windowIsOnTop
|
||||
},
|
||||
closeListEvent () {
|
||||
this.right.show = false
|
||||
this.right.type = ''
|
||||
this.state.showChannelList = false
|
||||
const lastRightType = this.right.type
|
||||
const lastChannelListState = this.state.showChannelList
|
||||
setTimeout(() => {
|
||||
if (lastRightType === this.right.type) {
|
||||
this.right.show = false
|
||||
this.right.type = ''
|
||||
}
|
||||
if (lastChannelListState === this.state.showChannelList) {
|
||||
this.state.showChannelList = false
|
||||
}
|
||||
}, 50)
|
||||
},
|
||||
exportM3u8 () {
|
||||
const m3u8Arr = []
|
||||
@@ -955,15 +1009,15 @@ export default {
|
||||
link: link
|
||||
})
|
||||
}
|
||||
let m3u8Content = '#EXTM3U'
|
||||
let m3u8Content = '#EXTM3U\n'
|
||||
for (const item of m3u8Arr) {
|
||||
m3u8Content += `#EXTINF:-1, ${item.name}\n${item.link}`
|
||||
m3u8Content += `#EXTINF:-1, ${item.name}\n${item.link}\n`
|
||||
}
|
||||
const blob = new Blob([m3u8Content], { type: 'application/vnd.apple.mpegurl' })
|
||||
const downloadElement = document.createElement('a')
|
||||
const href = window.URL.createObjectURL(blob)
|
||||
downloadElement.href = href
|
||||
downloadElement.download = `${this.name}.m3u8`
|
||||
downloadElement.download = `${this.name}.m3u`
|
||||
document.body.appendChild(downloadElement)
|
||||
downloadElement.click()
|
||||
document.body.removeChild(downloadElement)
|
||||
@@ -1040,7 +1094,6 @@ export default {
|
||||
this.getOtherSites()
|
||||
this.right.currentTime = this.xg.currentTime
|
||||
} else {
|
||||
this.state.showChannelList = false
|
||||
this.right.type = 'sources'
|
||||
}
|
||||
this.right.show = true
|
||||
@@ -1084,8 +1137,6 @@ export default {
|
||||
if (this.xg) {
|
||||
if (this.xg.paused) {
|
||||
this.xg.play()
|
||||
// 继续播放时,隐藏进度条
|
||||
win.setProgressBar(-1)
|
||||
} else {
|
||||
this.xg.pause()
|
||||
}
|
||||
@@ -1430,7 +1481,6 @@ export default {
|
||||
}
|
||||
var historyItem = this.right.history[0]
|
||||
this.video = { key: historyItem.site, info: { id: historyItem.ids, name: historyItem.name, index: historyItem.index } }
|
||||
this.getUrls()
|
||||
} else if (this.video.iptv && !this.isLive) {
|
||||
this.playChannel(this.video.iptv)
|
||||
this.state.showChannelList = false
|
||||
@@ -1439,27 +1489,18 @@ export default {
|
||||
})
|
||||
},
|
||||
videoStop () {
|
||||
win.setProgressBar(-1)
|
||||
if (this.xg.fullscreen) {
|
||||
this.xg.exitFullscreen()
|
||||
}
|
||||
clearInterval(this.timer)
|
||||
this.video.key = ''
|
||||
this.xg.src = ''
|
||||
this.config.url = ''
|
||||
this.xg.destroy(false)
|
||||
this.xg = null
|
||||
this.name = ''
|
||||
this.isLive = false
|
||||
this.state.showChannelList = true
|
||||
this.state.showTimespanSetting = false
|
||||
this.right.list = []
|
||||
this.getAllhistory()
|
||||
setTimeout(() => {
|
||||
this.xg = new HlsJsPlayer(this.config)
|
||||
this.playerInstall()
|
||||
this.bindEvent()
|
||||
}, 100)
|
||||
this.getPlayer(this.playerType, true)
|
||||
},
|
||||
minMaxEvent () {
|
||||
win.on('minimize', () => {
|
||||
@@ -1505,11 +1546,16 @@ export default {
|
||||
})
|
||||
},
|
||||
showShortcutEvent () {
|
||||
this.right.show = !this.right.show
|
||||
shortcut.all().then(res => {
|
||||
this.right.type = 'shortcut'
|
||||
this.right.shortcut = res
|
||||
})
|
||||
if (this.right.type === 'shortcut') {
|
||||
this.right.show = false
|
||||
this.right.type = ''
|
||||
} else {
|
||||
this.right.show = true
|
||||
shortcut.all().then(res => {
|
||||
this.right.type = 'shortcut'
|
||||
this.right.shortcut = res
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="listpage" id="recommendataions">
|
||||
<div class="listpage-header" id="recommendataions-header">
|
||||
<div class="listpage" id="recommendations">
|
||||
<div class="listpage-header" id="recommendations-header">
|
||||
<el-switch v-model="setting.recommendationViewMode" active-text="海报" active-value="picture" inactive-text="列表" inactive-value="table" @change="updateViewMode"></el-switch>
|
||||
<el-button type="text">视频数:{{ recommendations.length }}</el-button>
|
||||
<el-select v-model="selectedAreas" size="small" multiple placeholder="地区" popper-class="popper" :popper-append-to-body="false">
|
||||
@@ -29,10 +29,10 @@
|
||||
</el-select>
|
||||
<el-button :loading="loading" @click.stop="updateEvent" icon="el-icon-refresh">更新推荐</el-button>
|
||||
</div>
|
||||
<div class="listpage-body" id="recommendataions-body" >
|
||||
<div class="listpage-body" id="recommendations-body" >
|
||||
<div class="show-table" id="star-table" v-if="setting.recommendationViewMode === 'table'">
|
||||
<el-table size="mini" fit height="100%" row-key="id"
|
||||
ref="recommendataionsTable"
|
||||
ref="recommendationsTable"
|
||||
:data="filteredRecommendations"
|
||||
@row-click="detailEvent">
|
||||
<el-table-column
|
||||
@@ -80,7 +80,7 @@
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="show-picture" id="star-picture" v-if="setting.recommendationViewMode === 'picture'">
|
||||
<Waterfall ref="recommendataionsWaterfall" :list="filteredRecommendations" :gutter="20" :width="240"
|
||||
<Waterfall ref="recommendationsWaterfall" :list="filteredRecommendations" :gutter="20" :width="240"
|
||||
:breakpoints="{
|
||||
1200: { //当屏幕宽度小于等于1200
|
||||
rowPerView: 4,
|
||||
@@ -100,7 +100,7 @@
|
||||
<div class="rate" v-if="props.data.rate && props.data.rate !== '暂无评分'">
|
||||
<span>{{props.data.rate}}分</span>
|
||||
</div>
|
||||
<img style="width: 100%" :src="props.data.detail.pic" alt="" @load="$refs.recommendataionsWaterfall.refresh()" @click="detailEvent(props.data)">
|
||||
<img style="width: 100%" :src="props.data.detail.pic" alt="" @load="$refs.recommendationsWaterfall.refresh()" @click="detailEvent(props.data)">
|
||||
<div class="operate">
|
||||
<div class="operate-wrap">
|
||||
<span class="o-play" @click="playEvent(props.data)">播放</span>
|
||||
@@ -198,7 +198,7 @@ export default {
|
||||
watch: {
|
||||
view () {
|
||||
if (this.view === 'Recommendation') {
|
||||
if (this.$refs.recommendataionsWaterfall) this.$refs.recommendataionsWaterfall.resize()
|
||||
if (this.$refs.recommendationsWaterfall) this.$refs.recommendationsWaterfall.resize()
|
||||
}
|
||||
},
|
||||
sortKeyword () {
|
||||
@@ -279,31 +279,15 @@ export default {
|
||||
info: e.detail
|
||||
}
|
||||
},
|
||||
downloadEvent (e) {
|
||||
const key = e.key
|
||||
const id = e.ids
|
||||
zy.download(key, id).then(res => {
|
||||
if (res && res.m3u8List) {
|
||||
const list = res.m3u8List.split('#')
|
||||
let downloadUrl = ''
|
||||
for (const i of list) {
|
||||
const url = encodeURI(i.split('$')[1])
|
||||
downloadUrl += (url + '\n')
|
||||
}
|
||||
clipboard.writeText(downloadUrl)
|
||||
this.$message.success('『MP4』格式的链接已复制, 快去下载吧!')
|
||||
} else {
|
||||
zy.detail(key, id).then(res => {
|
||||
const list = [...res.m3u8List]
|
||||
let downloadUrl = ''
|
||||
for (const i of list) {
|
||||
const url = encodeURI(i.split('$')[1])
|
||||
downloadUrl += (url + '\n')
|
||||
}
|
||||
clipboard.writeText(downloadUrl)
|
||||
this.$message.success('『M3U8』格式的链接已复制, 快去下载吧!')
|
||||
})
|
||||
}
|
||||
async downloadEvent (e) {
|
||||
const db = await history.find({ site: e.key, ids: e.ids })
|
||||
let videoFlag
|
||||
if (db) videoFlag = db.videoFlag
|
||||
zy.download(e.key, e.ids, videoFlag).then(res => {
|
||||
clipboard.writeText(res.downloadUrls)
|
||||
this.$message.success(res.info)
|
||||
}).catch((err) => {
|
||||
this.$message.error(err.info)
|
||||
})
|
||||
},
|
||||
getRecommendations () {
|
||||
@@ -319,7 +303,7 @@ export default {
|
||||
this.areas = [...new Set(this.recommendations.map(ele => ele.detail.area))].filter(x => x)
|
||||
},
|
||||
updateViewMode () {
|
||||
setTimeout(() => { if (this.$refs.recommendataionsWaterfall) this.$refs.recommendataionsWaterfall.refresh() }, 700)
|
||||
setTimeout(() => { if (this.$refs.recommendationsWaterfall) this.$refs.recommendationsWaterfall.refresh() }, 700)
|
||||
setting.find().then(res => {
|
||||
res.recommendationViewMode = this.setting.recommendationViewMode
|
||||
setting.update(res)
|
||||
@@ -331,7 +315,7 @@ export default {
|
||||
},
|
||||
mounted () {
|
||||
addEventListener('resize', () => {
|
||||
setTimeout(() => { if (this.$refs.recommendataionsWaterfall) this.$refs.recommendataionsWaterfall.resize() }, 500)
|
||||
setTimeout(() => { if (this.$refs.recommendationsWaterfall) this.$refs.recommendationsWaterfall.resize() }, 500)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,14 +205,11 @@
|
||||
<div class="wrapper">
|
||||
<div class="body">
|
||||
<div class="content" v-html="update.html"></div>
|
||||
<div class="progress" v-show="update.percent > 0">
|
||||
<el-progress :percentage="update.percent"></el-progress>
|
||||
<div class="size" style="font-size: 14px">更新包大小: {{update.size}} KB</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<el-button size="small" @click="cancelUpdate">取消</el-button>
|
||||
<el-button size="small" v-show="!update.downloaded" @click="startUpdate">更新</el-button>
|
||||
<el-button size="small" @click="closeUpdate">关闭</el-button>
|
||||
<el-button size="small" v-show="update.showDownload" @click="startUpdate">更新</el-button>
|
||||
<el-button size="small" v-show="!update.showDownload && !update.downloaded">正在更新...</el-button>
|
||||
<el-button size="small" v-show="update.downloaded" @click="installUpdate">安装</el-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -258,9 +255,8 @@ export default {
|
||||
version: '',
|
||||
show: false,
|
||||
html: '',
|
||||
percent: 0,
|
||||
size: 0,
|
||||
downloaded: false
|
||||
downloaded: false,
|
||||
showDownload: true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -498,15 +494,12 @@ export default {
|
||||
openUpdate () {
|
||||
this.update.show = true
|
||||
},
|
||||
cancelUpdate () {
|
||||
closeUpdate () {
|
||||
this.update.show = false
|
||||
},
|
||||
startUpdate () {
|
||||
this.update.showDownload = false
|
||||
ipcRenderer.send('downloadUpdate')
|
||||
ipcRenderer.on('download-progress', (info, progress) => {
|
||||
this.update.size = progress.total
|
||||
this.update.percent = parseFloat(progress.percent).toFixed(1)
|
||||
})
|
||||
ipcRenderer.on('update-downloaded', () => {
|
||||
this.update.downloaded = true
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="share" id="share" @click="shareClickEvent" v-on-clickaway="shareClickEvent">
|
||||
<div class="share" id="share" @click="shareClickEvent" v-clickoutside="shareClickEvent">
|
||||
<div class="left">
|
||||
<img :src="pic" alt="" @load="picLoadEvent">
|
||||
</div>
|
||||
@@ -22,7 +22,7 @@ import { mapMutations } from 'vuex'
|
||||
import QrcodeVue from 'qrcode.vue'
|
||||
import html2canvas from 'html2canvas'
|
||||
import zy from '../lib/site/tools'
|
||||
import { directive as onClickaway } from 'vue-clickaway'
|
||||
import Clickoutside from 'element-ui/src/utils/clickoutside'
|
||||
const { clipboard, nativeImage } = require('electron')
|
||||
export default {
|
||||
name: 'share',
|
||||
@@ -45,6 +45,14 @@ export default {
|
||||
set (val) {
|
||||
this.SET_SHARE(val)
|
||||
}
|
||||
},
|
||||
DetailCache: {
|
||||
get () {
|
||||
return this.$store.getters.getDetailCache
|
||||
},
|
||||
set (val) {
|
||||
this.SET_DetailCache(val)
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -58,10 +66,10 @@ export default {
|
||||
}
|
||||
},
|
||||
directives: {
|
||||
onClickaway: onClickaway
|
||||
Clickoutside
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SET_SHARE']),
|
||||
...mapMutations(['SET_SHARE', 'SET_DetailCache']),
|
||||
shareClickEvent () {
|
||||
this.share = {
|
||||
show: false,
|
||||
@@ -74,9 +82,14 @@ export default {
|
||||
return t.split('#')[0].split('$')[1]
|
||||
} else {
|
||||
const id = this.share.info.ids || this.share.info.id
|
||||
const res = await zy.detail(this.share.key, id)
|
||||
const cacheKey = this.share.key + '@' + id
|
||||
let res = this.DetailCache[cacheKey]
|
||||
if (!this.DetailCache[cacheKey]) {
|
||||
res = await zy.detail(this.share.key, id)
|
||||
this.DetailCache[cacheKey] = res
|
||||
}
|
||||
if (res) {
|
||||
return res.m3u8List[1]
|
||||
return res.fullList[0].list[0]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
<div class="update" v-if="props.data.hasUpdate">
|
||||
<span>有更新</span>
|
||||
</div>
|
||||
<div class="progress" v-if="props.data.index && props.data.detail && props.data.detail.m3u8List !== undefined && props.data.detail.m3u8List.length > 1">
|
||||
<div class="progress" v-if="props.data.index && props.data.detail && props.data.detail.fullList[0].list !== undefined && props.data.detail.fullList[0].list.length > 1">
|
||||
<span>
|
||||
看至第{{ props.data.index + 1 }}集
|
||||
</span>
|
||||
@@ -138,7 +138,7 @@
|
||||
</template>
|
||||
<script>
|
||||
import { mapMutations } from 'vuex'
|
||||
import { star, sites, setting } from '../lib/dexie'
|
||||
import { history, star, sites, setting } from '../lib/dexie'
|
||||
import zy from '../lib/site/tools'
|
||||
import { remote } from 'electron'
|
||||
import fs from 'fs'
|
||||
@@ -339,31 +339,15 @@ export default {
|
||||
this.updateEvent(e)
|
||||
})
|
||||
},
|
||||
downloadEvent (e) {
|
||||
const key = e.key
|
||||
const id = e.id
|
||||
zy.download(key, id).then(res => {
|
||||
if (res && res.m3u8List) {
|
||||
const list = res.m3u8List.split('#')
|
||||
let downloadUrl = ''
|
||||
for (const i of list) {
|
||||
const url = encodeURI(i.split('$')[1])
|
||||
downloadUrl += (url + '\n')
|
||||
}
|
||||
clipboard.writeText(downloadUrl)
|
||||
this.$message.success('『MP4』格式的链接已复制, 快去下载吧!')
|
||||
} else {
|
||||
zy.detail(key, id).then(res => {
|
||||
const list = [...res.m3u8List]
|
||||
let downloadUrl = ''
|
||||
for (const i of list) {
|
||||
const url = encodeURI(i.split('$')[1])
|
||||
downloadUrl += (url + '\n')
|
||||
}
|
||||
clipboard.writeText(downloadUrl)
|
||||
this.$message.success('『M3U8』格式的链接已复制, 快去下载吧!')
|
||||
})
|
||||
}
|
||||
async downloadEvent (e) {
|
||||
const db = await history.find({ site: e.key, ids: e.ids })
|
||||
let videoFlag
|
||||
if (db) videoFlag = db.videoFlag
|
||||
zy.download(e.key, e.ids, videoFlag).then(res => {
|
||||
clipboard.writeText(res.downloadUrls)
|
||||
this.$message.success(res.info)
|
||||
}).catch((err) => {
|
||||
this.$message.error(err.info)
|
||||
})
|
||||
},
|
||||
getSiteName (row) {
|
||||
@@ -430,6 +414,16 @@ export default {
|
||||
json.reverse().forEach(ele => {
|
||||
const starExists = starList.some(x => x.key === ele.key && x.ids === ele.ids)
|
||||
if (!starExists) {
|
||||
const newDetail = {
|
||||
director: ele.director,
|
||||
actor: ele.actor,
|
||||
type: ele.type,
|
||||
area: ele.area,
|
||||
lang: ele.lang,
|
||||
year: ele.year,
|
||||
last: ele.last,
|
||||
note: ele.note
|
||||
}
|
||||
var doc = {
|
||||
id: id,
|
||||
key: ele.key,
|
||||
@@ -439,16 +433,7 @@ export default {
|
||||
hasUpdate: ele.hasUpdate,
|
||||
index: ele.index,
|
||||
rate: ele.rate,
|
||||
detail: ele.detail === undefined ? {
|
||||
director: ele.director,
|
||||
actor: ele.actor,
|
||||
type: ele.type,
|
||||
area: ele.area,
|
||||
lang: ele.lang,
|
||||
year: ele.year,
|
||||
last: ele.last,
|
||||
note: ele.note
|
||||
} : ele.detail
|
||||
detail: ele.detail === undefined ? newDetail : ele.detail
|
||||
}
|
||||
id += 1
|
||||
starList.push(doc)
|
||||
@@ -481,6 +466,7 @@ export default {
|
||||
})
|
||||
},
|
||||
rowDrop () {
|
||||
if (!document.getElementById('star-table')) return
|
||||
const tbody = document.getElementById('star-table').querySelector('.el-table__body-wrapper tbody')
|
||||
const _this = this
|
||||
Sortable.create(tbody, {
|
||||
|
||||
@@ -16,6 +16,7 @@ db.version(4).stores({
|
||||
channelList: '++id, name, prefer, channels, group, isActive'
|
||||
})
|
||||
|
||||
// 开发和稳定版同一版本号会有不同的数据库
|
||||
// 参考https://github.com/dfahlander/Dexie.js/releases/tag/v3.0.0-alpha.3 upgrade可以改变主键和表名了
|
||||
// https://dexie.org/docs/Version/Version.stores()
|
||||
// https://dexie.org/docs/Version/Version.upgrade()
|
||||
@@ -30,6 +31,23 @@ db.version(6).stores({
|
||||
await tx.shortcut.bulkAdd(localKey)
|
||||
})
|
||||
|
||||
db.version(7).stores({
|
||||
sites: '++id, key, name, api, download, jiexiUrl, isActive, group',
|
||||
history: '++id, [site+ids], name, type, year, index, time, duration, detail, onlinePlay'
|
||||
}).upgrade(trans => {
|
||||
trans.sites.toCollection().modify(site => {
|
||||
site.jiexiUrl = ''
|
||||
})
|
||||
trans.history.toCollection().modify(record => {
|
||||
record.detail.fullList = [].concat(record.detail.m3u8List)
|
||||
delete record.detail.m3u8List
|
||||
})
|
||||
trans.star.toCollection().modify(favorite => {
|
||||
favorite.detail.fullList = [].concat(favorite.detail.m3u8List)
|
||||
delete favorite.detail.m3u8List
|
||||
})
|
||||
})
|
||||
|
||||
db.on('populate', () => {
|
||||
db.setting.bulkAdd(setting)
|
||||
db.sites.bulkAdd(sites)
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
"name": "麻花资源",
|
||||
"api": "http://www.mhapi123.com/inc/ldg_api.php",
|
||||
"download": "",
|
||||
"jiexiUrl": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
@@ -15,9 +15,9 @@
|
||||
"name": "1886 资源",
|
||||
"api": "http://cj.1886zy.co/inc/api.php",
|
||||
"download": "",
|
||||
"jiexiUrl": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
@@ -25,138 +25,158 @@
|
||||
"name": "123 资源",
|
||||
"api": "http://cj.123ku2.com:12315/inc/api.php",
|
||||
"download": "",
|
||||
"jiexiUrl": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"key": "7K资源",
|
||||
"id": 4,
|
||||
"name": "7K资源",
|
||||
"api": "https://zy.7kjx.com/cjapi.php",
|
||||
"download": "",
|
||||
"jiexiUrl": "https://jx.7kjx.com/?url=",
|
||||
"group": "默认",
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"key": "1717云资源网",
|
||||
"id": 5,
|
||||
"name": "1717云资源网",
|
||||
"api": "http://zy.itono.cn/inc/api.php",
|
||||
"download": "",
|
||||
"jiexiUrl": "https://www.1717yun.com/jiexi/?url=",
|
||||
"group": "默认",
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"key": "subo988",
|
||||
"name": "速播资源站",
|
||||
"api": "https://www.subo988.com/inc/api.php",
|
||||
"download": "",
|
||||
"jiexiUrl": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"id": 7,
|
||||
"key": "88zyw",
|
||||
"name": "88 影视资源站",
|
||||
"api": "http://www.88zyw.net/inc/api.php",
|
||||
"download": "",
|
||||
"jiexiUrl": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"key": "zuidazy",
|
||||
"id": 6,
|
||||
"id": 8,
|
||||
"name": "最大资源网",
|
||||
"api": "http://www.zdziyuan.com/inc/ldg_sea.php",
|
||||
"download": "http://www.zdziyuan.com/inc/apidown.php",
|
||||
"jiexiUrl": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"key": "mbo",
|
||||
"id": 7,
|
||||
"id": 9,
|
||||
"name": "秒播资源",
|
||||
"api": "http://caiji.mb77.vip/inc/seacmsapi.php",
|
||||
"download": "",
|
||||
"jiexiUrl": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"id": 10,
|
||||
"key": "apibdzy",
|
||||
"name": "百度云资源",
|
||||
"api": "https://api.apibdzy.com/api.php/provide/vod/at/xml",
|
||||
"download": "",
|
||||
"jiexiUrl": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"id": 11,
|
||||
"key": "okzy",
|
||||
"name": "OK 资源网",
|
||||
"api": "http://cj.okzy.tv/inc/api.php",
|
||||
"download": "http://cj.okzy.tv/inc/apidown.php",
|
||||
"jiexiUrl": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"id": 12,
|
||||
"key": "kuyunzy",
|
||||
"name": "酷云资源",
|
||||
"api": "http://caiji.kuyun98.com/inc/ldg_api.php",
|
||||
"download": "http://caiji.kuyun98.com/inc/apidown.php",
|
||||
"jiexiUrl": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"id": 13,
|
||||
"key": "kubozy",
|
||||
"name": "酷播资源",
|
||||
"api": "http://api.kbzyapi.com/inc/api.php",
|
||||
"download": "",
|
||||
"jiexiUrl": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"id": 14,
|
||||
"key": "yongjiuzy",
|
||||
"name": "永久资源",
|
||||
"api": "http://cj.yongjiuzyw.com/inc/api.php",
|
||||
"download": "",
|
||||
"jiexiUrl": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"id": 15,
|
||||
"key": "rrzy",
|
||||
"name": "人人资源",
|
||||
"api": "https://www.rrzyw.cc/api.php/provide/vod/from/rrm3u8/at/xml/",
|
||||
"download": "",
|
||||
"jiexiUrl": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"id": 16,
|
||||
"key": "bbkdj",
|
||||
"name": "步步高顶尖资源网",
|
||||
"api": "http://api.bbkdj.com/api",
|
||||
"download": "",
|
||||
"jiexiUrl": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"id": 17,
|
||||
"key": "zuixinzy",
|
||||
"name": "最新资源",
|
||||
"api": "http://api.zuixinapi.com/inc/api.php",
|
||||
"download": "",
|
||||
"jiexiUrl": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"id": 16,
|
||||
"id": 18,
|
||||
"key": "209zy",
|
||||
"name": "209 资源",
|
||||
"api": "http://cj.1156zy.com/inc/api.php",
|
||||
"download": "",
|
||||
"jiexiUrl": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
"isActive": true
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
@@ -15,7 +15,8 @@ var session = win.webContents.session
|
||||
var ElectronProxyAgent = require('electron-proxy-agent')
|
||||
|
||||
// 请求超时时限
|
||||
axios.defaults.timeout = 10000 // 可能使用代理,增长超时
|
||||
// axios.defaults.timeout = 10000 // 可能使用代理,增长超时
|
||||
const TIMEOUT = 6000
|
||||
|
||||
// 重试次数,共请求3次
|
||||
axios.defaults.retry = 2
|
||||
@@ -23,11 +24,20 @@ axios.defaults.retry = 2
|
||||
// 请求的间隙
|
||||
axios.defaults.retryDelay = 1000
|
||||
|
||||
// 使用请求拦截器动态调整超时
|
||||
axios.interceptors.request.use(function (config) {
|
||||
if (config.__retryCount === undefined) {
|
||||
config.timeout = TIMEOUT
|
||||
} else {
|
||||
config.timeout = TIMEOUT * (config.__retryCount + 1)
|
||||
}
|
||||
return config
|
||||
}, function (err) {
|
||||
return Promise.reject(err)
|
||||
})
|
||||
|
||||
// 添加响应拦截器
|
||||
axios.interceptors.response.use(function (response) {
|
||||
// 对响应数据做些事
|
||||
if (response.status && response.status === 200 && response.request.responseURL.includes('api.php') && !response.data.startsWith('<?xml')) {
|
||||
}
|
||||
return response
|
||||
}, function (err) { // 请求错误时做些事
|
||||
// 请求超时的之后,抛出 err.code = ECONNABORTED的错误..错误信息是 timeout of xxx ms exceeded
|
||||
@@ -139,7 +149,11 @@ const zy = {
|
||||
const json = parser.parse(data, this.xmlConfig)
|
||||
const jsondata = json.rss === undefined ? json : json.rss
|
||||
const videoList = jsondata.list.video
|
||||
resolve(videoList)
|
||||
if (videoList && videoList.length) {
|
||||
resolve(videoList)
|
||||
} else {
|
||||
resolve([])
|
||||
}
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
@@ -163,7 +177,7 @@ const zy = {
|
||||
url = `${site.api}?ac=videolist`
|
||||
}
|
||||
axios.post(url).then(async res => {
|
||||
const data = res.data
|
||||
const data = res.data.match(/<list [^>]*>/)[0] + '</list>' // 某些源站不含页码时获取到的数据parser无法解析
|
||||
const json = parser.parse(data, this.xmlConfig)
|
||||
const jsondata = json.rss === undefined ? json : json.rss
|
||||
const pg = {
|
||||
@@ -222,21 +236,46 @@ const zy = {
|
||||
const json = parser.parse(data, this.xmlConfig)
|
||||
const jsondata = json.rss === undefined ? json : json.rss
|
||||
const videoList = jsondata.list.video
|
||||
// Parse m3u8List
|
||||
var m3u8List = []
|
||||
// Parse video lists
|
||||
var fullList = []
|
||||
let index = 0
|
||||
const supportedFormats = ['m3u8', 'mp4']
|
||||
const dd = videoList.dl.dd
|
||||
const type = Object.prototype.toString.call(dd)
|
||||
if (type === '[object Array]') {
|
||||
for (const i of dd) {
|
||||
// 如果含有多个视频列表的话, 仅获取m3u8列表
|
||||
if (i._flag.includes('m3u8')) {
|
||||
m3u8List = i._t.split('#')
|
||||
const ext = Array.from(new Set(...i._t.split('#').map(e => e.split('$')[1].match(/\.\w+?$/)))).map(e => e.slice(1))
|
||||
if (ext.length && ext.length <= supportedFormats.length && ext.every(e => supportedFormats.includes(e))) {
|
||||
if (ext.length === 1) {
|
||||
i._flag = ext[0]
|
||||
} else {
|
||||
i._flag = index ? 'ZY支持-' + index : 'ZY支持'
|
||||
index++
|
||||
}
|
||||
}
|
||||
fullList.push(
|
||||
{
|
||||
flag: i._flag,
|
||||
list: i._t.split('#').filter(e => e && e.split('$')[1] && e.split('$')[1].startsWith('http'))
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
m3u8List = dd._t.split('#')
|
||||
fullList.push(
|
||||
{
|
||||
flag: dd._flag,
|
||||
list: dd._t.split('#').filter(e => e && e.split('$')[1] && e.split('$')[1].startsWith('http'))
|
||||
}
|
||||
)
|
||||
}
|
||||
videoList.m3u8List = m3u8List
|
||||
if (fullList.length > 1) { // 将ZY支持的播放列表前置
|
||||
index = fullList.findIndex(e => supportedFormats.includes(e.flag) || e.flag.startsWith('ZY支持'))
|
||||
if (index !== -1) {
|
||||
const first = fullList.splice(index, 1)
|
||||
fullList = first.concat(fullList)
|
||||
}
|
||||
}
|
||||
videoList.fullList = fullList
|
||||
resolve(videoList)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
@@ -252,8 +291,10 @@ const zy = {
|
||||
* @param {*} id 资源唯一标识符 id
|
||||
* @returns
|
||||
*/
|
||||
download (key, id) {
|
||||
download (key, id, videoFlag) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let info = ''
|
||||
let downloadUrls = ''
|
||||
this.getSite(key).then(res => {
|
||||
const site = res
|
||||
if (site.download) {
|
||||
@@ -263,24 +304,42 @@ const zy = {
|
||||
const json = parser.parse(data, this.xmlConfig)
|
||||
const jsondata = json.rss === undefined ? json : json.rss
|
||||
const videoList = jsondata.list.video
|
||||
// Parse m3u8List
|
||||
var m3u8List = []
|
||||
const dd = videoList.dl.dd
|
||||
const type = Object.prototype.toString.call(dd)
|
||||
if (type === '[object Array]') {
|
||||
for (const i of dd) {
|
||||
m3u8List = i._t.split('#')
|
||||
downloadUrls = i._t.split('#').map(e => encodeURI(e.split('$')[1])).join('\n')
|
||||
}
|
||||
} else {
|
||||
m3u8List = dd._t.split('#')
|
||||
downloadUrls = dd._t.split('#').map(e => encodeURI(e.split('$')[1])).join('\n')
|
||||
}
|
||||
videoList.m3u8List = m3u8List
|
||||
resolve(videoList)
|
||||
}).catch(err => {
|
||||
if (downloadUrls) {
|
||||
info = '调用下载接口获取到的链接已复制, 快去下载吧!'
|
||||
resolve({ downloadUrls: downloadUrls, info: info })
|
||||
} else {
|
||||
throw new Error()
|
||||
}
|
||||
}).catch((err) => {
|
||||
err.info = '无法获取到下载链接,请通过播放页面点击“调试”按钮获取'
|
||||
reject(err)
|
||||
})
|
||||
} else {
|
||||
resolve([])
|
||||
zy.detail(key, id).then(res => {
|
||||
const dl = res.fullList.find(e => e.flag === videoFlag) || res.fullList[0]
|
||||
for (const i of dl.list) {
|
||||
const url = encodeURI(i.split('$')[1])
|
||||
downloadUrls += (url + '\n')
|
||||
}
|
||||
if (downloadUrls) {
|
||||
info = '视频源链接已复制, 快去下载吧!'
|
||||
resolve({ downloadUrls: downloadUrls, info: info })
|
||||
} else {
|
||||
throw new Error()
|
||||
}
|
||||
}).catch((err) => {
|
||||
err.info = '无法获取到下载链接,请通过播放页面点击“调试”按钮获取'
|
||||
reject(err)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -328,28 +387,26 @@ const zy = {
|
||||
/**
|
||||
* 获取豆瓣页面链接
|
||||
* @param {*} name 视频名称
|
||||
* @param {*} year 视频年份
|
||||
* @returns 豆瓣页面链接,如果没有搜到该视频,返回搜索页面链接
|
||||
*/
|
||||
doubanLink (name) {
|
||||
doubanLink (name, year) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 豆瓣搜索链接
|
||||
var nameToSearch = name.replace(/\s/g, '')
|
||||
var doubanSearchLink = 'https://www.douban.com/search?q=' + nameToSearch
|
||||
axios.get(doubanSearchLink).then(res => {
|
||||
const $ = cheerio.load(res.data)
|
||||
// 比较第一和第二给豆瓣搜索结果, 看名字是否相符
|
||||
// 查询所有搜索结果, 看名字和年代是否相符
|
||||
var link = ''
|
||||
var linkInDouban = $($('div.result')[0]).find('div>div>h3>a').first()
|
||||
var nameInDouban = linkInDouban.text().replace(/\s/g, '')
|
||||
if (nameToSearch === nameInDouban) {
|
||||
link = linkInDouban.attr('href')
|
||||
} else {
|
||||
linkInDouban = $($('div.result')[1]).find('div>div>h3>a').first()
|
||||
nameInDouban = linkInDouban.text().replace(/\s/g, '')
|
||||
if (nameToSearch === nameInDouban) {
|
||||
$('div.result').each(function () {
|
||||
var linkInDouban = $(this).find('div>div>h3>a').first()
|
||||
var nameInDouban = linkInDouban.text().replace(/\s/g, '')
|
||||
var subjectCast = $(this).find('span.subject-cast').text()
|
||||
if (nameToSearch === nameInDouban && subjectCast && subjectCast.includes(year)) {
|
||||
link = linkInDouban.attr('href')
|
||||
}
|
||||
}
|
||||
})
|
||||
if (link) {
|
||||
resolve(link)
|
||||
} else {
|
||||
@@ -364,12 +421,13 @@ const zy = {
|
||||
/**
|
||||
* 获取豆瓣评分
|
||||
* @param {*} name 视频名称
|
||||
* @param {*} year 视频年份
|
||||
* @returns 豆瓣评分
|
||||
*/
|
||||
doubanRate (name) {
|
||||
doubanRate (name, year) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var nameToSearch = name.replace(/\s/g, '')
|
||||
this.doubanLink(nameToSearch).then(link => {
|
||||
this.doubanLink(nameToSearch, year).then(link => {
|
||||
if (link.includes('https://www.douban.com/search')) {
|
||||
resolve('暂无评分')
|
||||
} else {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { BrowserWindow, ipcMain } from 'electron'
|
||||
const { autoUpdater } = require('@imjs/electron-differential-updater')
|
||||
const { autoUpdater } = require('electron-updater')
|
||||
|
||||
// electron-updater 增量更新时似乎无法显示进度
|
||||
export function initUpdater (win = BrowserWindow) {
|
||||
autoUpdater.autoDownload = false
|
||||
autoUpdater.autoInstallOnAppQuit = false
|
||||
autoUpdater.autoInstallOnAppQuit = true
|
||||
|
||||
// 主进程监听检查更新事件
|
||||
ipcMain.on('checkForUpdate', () => {
|
||||
@@ -41,8 +42,8 @@ export function initUpdater (win = BrowserWindow) {
|
||||
})
|
||||
|
||||
// 下载更新进度
|
||||
autoUpdater.on('download-progress', (info, progress) => {
|
||||
win.webContents.send('download-progress', info, progress)
|
||||
autoUpdater.on('download-progress', (progressObj) => {
|
||||
win.webContents.send('download-progress', progressObj)
|
||||
})
|
||||
|
||||
// 下载完成
|
||||
|
||||
@@ -28,7 +28,8 @@ export default new Vuex.Store({
|
||||
},
|
||||
appState: {
|
||||
windowIsOnTop: false
|
||||
}
|
||||
},
|
||||
DetailCache: {}
|
||||
},
|
||||
getters: {
|
||||
getView: state => {
|
||||
@@ -48,6 +49,9 @@ export default new Vuex.Store({
|
||||
},
|
||||
getAppState: state => {
|
||||
return state.appState
|
||||
},
|
||||
getDetailCache: state => {
|
||||
return state.DetailCache
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
@@ -68,6 +72,9 @@ export default new Vuex.Store({
|
||||
},
|
||||
SET_APPSTATE: (state, payload) => {
|
||||
state.appState = payload
|
||||
},
|
||||
set_DetailCache: (state, payload) => {
|
||||
state.DetailCache = payload
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user