mirror of
https://github.com/cuiocean/ZY-Player.git
synced 2026-02-14 16:06:48 +08:00
Compare commits
82 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
81b34ff54a | ||
|
|
9b9db55f49 | ||
|
|
e7c7367ea8 | ||
|
|
5e37ef32fd | ||
|
|
85525745a1 | ||
|
|
c7f581a088 | ||
|
|
a88dfb1bc3 | ||
|
|
410cd8fc1a | ||
|
|
bb30be3c4d | ||
|
|
6230c9e87a | ||
|
|
93efb64211 | ||
|
|
3c4dd91d36 | ||
|
|
45041fdab1 | ||
|
|
bcf0613ff0 | ||
|
|
3107b851c5 | ||
|
|
b27883ad0f | ||
|
|
e0c3502c3f | ||
|
|
4c2db002eb | ||
|
|
898f769d24 | ||
|
|
d6549c6a6b | ||
|
|
eea4081d58 | ||
|
|
1e9f48e48c | ||
|
|
0816933679 | ||
|
|
8af6ff2bd7 | ||
|
|
c5d979fd28 | ||
|
|
beb0c29326 | ||
|
|
5509ace412 | ||
|
|
6f296a1170 | ||
|
|
f8228a71f3 | ||
|
|
9886f04b48 | ||
|
|
37c4aad4b0 | ||
|
|
77d7b28e26 | ||
|
|
3505b22344 | ||
|
|
80cec08982 | ||
|
|
f92094daec | ||
|
|
2c06ef1da6 | ||
|
|
06403ece3f | ||
|
|
39a6491403 | ||
|
|
edb82eb3be | ||
|
|
c7ca3df50d | ||
|
|
0b198381b1 | ||
|
|
2dcda83741 | ||
|
|
5b3c3f0ff2 | ||
|
|
23454f7c7f | ||
|
|
0fdfe29343 | ||
|
|
fa7a799e2b | ||
|
|
9c1a707279 | ||
|
|
7b69bb05d4 | ||
|
|
3b6b6ea11b | ||
|
|
9ec65ab027 | ||
|
|
da5531a947 | ||
|
|
4744f91f6b | ||
|
|
36b80c1d7e | ||
|
|
15f4ab7248 | ||
|
|
0e25c25480 | ||
|
|
7ff48a407d | ||
|
|
bbc371b1c5 | ||
|
|
d141d60e77 | ||
|
|
80af701e5c | ||
|
|
f0e70e03cb | ||
|
|
aba3472f2e | ||
|
|
8772076d76 | ||
|
|
4abe03347a | ||
|
|
b3e6e817dd | ||
|
|
e48445c224 | ||
|
|
159f19d5ec | ||
|
|
c2953a530c | ||
|
|
9166f129d8 | ||
|
|
72ac3eafdd | ||
|
|
8610b41fad | ||
|
|
06e4c0e83e | ||
|
|
5db3fd9f9b | ||
|
|
978afb2b38 | ||
|
|
b00b69a582 | ||
|
|
9a33b0cfb3 | ||
|
|
f4bf42bf07 | ||
|
|
671a6e32d0 | ||
|
|
d05534fb17 | ||
|
|
b655c8c8bc | ||
|
|
8fbea8ab57 | ||
|
|
2ddfc66104 | ||
|
|
26d62cdef4 |
10
.github/workflows/x86.yml
vendored
10
.github/workflows/x86.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: release-build
|
||||
name: x86-release-build
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -25,11 +25,3 @@ jobs:
|
||||
shell: pwsh
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: dist_electron
|
||||
path: dist_electron/*.exe
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
6216
package-lock.json
generated
6216
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
34
package.json
34
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "zy",
|
||||
"version": "2.7.9",
|
||||
"version": "2.8.8",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
@@ -17,14 +17,16 @@
|
||||
},
|
||||
"main": "background.js",
|
||||
"dependencies": {
|
||||
"axios": "^0.21.1",
|
||||
"cheerio": "^1.0.0-rc.5",
|
||||
"core-js": "^3.9.1",
|
||||
"dexie": "^3.0.3",
|
||||
"@electron/remote": "^2.0.8",
|
||||
"axios": "^0.21.2",
|
||||
"bootstrap-vue": "^2.22.0",
|
||||
"cheerio": "1.0.0-rc.6",
|
||||
"core-js": "^3.10.2",
|
||||
"dexie": "^3.2.2",
|
||||
"electron-localshortcut": "^3.2.1",
|
||||
"electron-proxy-agent": "^1.2.0",
|
||||
"electron-updater": "^4.3.8",
|
||||
"element-ui": "^2.15.1",
|
||||
"element-ui": "^2.15.9",
|
||||
"fast-xml-parser": "^3.19.0",
|
||||
"html2canvas": "^1.0.0-rc.7",
|
||||
"iptv-playlist-parser": "^0.6.0",
|
||||
@@ -39,34 +41,26 @@
|
||||
"session": "^0.1.0",
|
||||
"sortablejs": "^1.13.0",
|
||||
"v-fit-columns": "^0.2.0",
|
||||
"vue": "^2.6.12",
|
||||
"vue": "^2.6.14",
|
||||
"vue-infinite-loading": "^2.4.5",
|
||||
"vue-waterfall-plugin": "^1.1.0",
|
||||
"vuedraggable": "^2.24.3",
|
||||
"vuex": "^3.6.2",
|
||||
"xgplayer": "2.17.13",
|
||||
"xgplayer": "2.19.1",
|
||||
"xgplayer-flv.js": "^2.3.0",
|
||||
"xgplayer-hls.js": "^2.4.2"
|
||||
"xgplayer-hls.js": "^2.4.2",
|
||||
"xgplayer-mp4": "^1.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~4.5.11",
|
||||
"@vue/cli-plugin-eslint": "~4.5.11",
|
||||
"@vue/cli-plugin-vuex": "~4.5.11",
|
||||
"@vue/cli-service": "~4.5.11",
|
||||
"@vue/eslint-config-standard": "^6.0.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-plugin-component": "^1.1.1",
|
||||
"electron": "^11.3.0",
|
||||
"electron": "^13.0.0",
|
||||
"electron-devtools-installer": "^3.1.1",
|
||||
"eslint": "^7.20.0",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^4.3.1",
|
||||
"eslint-plugin-standard": "^4.1.0",
|
||||
"eslint-plugin-vue": "^7.6.0",
|
||||
"sass": "^1.30.0",
|
||||
"sass-loader": "^10.1.0",
|
||||
"vue-cli-plugin-electron-builder": "2.0.0-rc.6",
|
||||
"vue-template-compiler": "^2.6.12"
|
||||
"vue-template-compiler": "^2.6.14"
|
||||
}
|
||||
}
|
||||
|
||||
54
src/App.vue
54
src/App.vue
@@ -10,7 +10,6 @@
|
||||
<Setting v-show="view === 'Setting'" />
|
||||
<IPTV v-show="view === 'IPTV'" />
|
||||
<EditSites v-if="view === 'EditSites'"/>
|
||||
<Recommendation v-show="view === 'Recommendation'" />
|
||||
</div>
|
||||
<transition name="slide">
|
||||
<Detail v-if="detail.show"/>
|
||||
@@ -22,11 +21,62 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { setting } from './lib/dexie'
|
||||
const remote = require('@electron/remote')
|
||||
export default {
|
||||
name: 'App',
|
||||
data () {
|
||||
return {
|
||||
appTheme: 'theme-light'
|
||||
appTheme: 'theme-light',
|
||||
winSizePosition: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 0,
|
||||
height: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
// 窗口创建口,检查是否有窗口大小位置的记录,如果有的话,更新窗口位置及大小
|
||||
setting.find().then(res => {
|
||||
if (res.restoreWindowPositionAndSize) {
|
||||
var win = remote.getCurrentWindow()
|
||||
win.setBounds({
|
||||
x: res.windowPositionAndSize.x,
|
||||
y: res.windowPositionAndSize.y,
|
||||
width: res.windowPositionAndSize.width,
|
||||
height: res.windowPositionAndSize.height
|
||||
})
|
||||
this.winSizePosition = {
|
||||
x: win.getPosition()[0],
|
||||
y: win.getPosition()[1],
|
||||
width: win.getSize()[0],
|
||||
height: win.getSize()[1]
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
updated () {
|
||||
// 本来想hook up到beforedestroy, 但不工作
|
||||
// 每当窗口更新时,检查窗口大小及位置,记录到setting数据库中
|
||||
if (this.setting.restoreWindowPositionAndSize) {
|
||||
const win = remote.getCurrentWindow()
|
||||
var newWinSizePosition = {
|
||||
x: win.getPosition()[0],
|
||||
y: win.getPosition()[1],
|
||||
width: win.getSize()[0],
|
||||
height: win.getSize()[1]
|
||||
}
|
||||
if (newWinSizePosition.x !== this.winSizePosition.x ||
|
||||
newWinSizePosition.y !== this.winSizePosition.y ||
|
||||
newWinSizePosition.width !== this.winSizePosition.width ||
|
||||
newWinSizePosition.height !== this.winSizePosition.height) {
|
||||
this.winSizePosition = newWinSizePosition
|
||||
setting.find().then(res => {
|
||||
res.windowPositionAndSize = newWinSizePosition
|
||||
setting.update(res)
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
@@ -441,3 +441,134 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// detail
|
||||
.detail{
|
||||
.detail-content{
|
||||
.detail-body{
|
||||
.m3u8{
|
||||
.show-picture{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
.card{
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
transition: 0.2s;
|
||||
&:hover {
|
||||
width: 102%;
|
||||
height: 102%
|
||||
}
|
||||
.img{
|
||||
position: relative;
|
||||
min-height: 40px;
|
||||
img{
|
||||
width: 100%;
|
||||
height: auto;
|
||||
cursor: pointer;
|
||||
}
|
||||
.rate{
|
||||
position: absolute;
|
||||
top: 3%;
|
||||
right: -40%;
|
||||
width: 100%;
|
||||
background-color: #111111aa;
|
||||
color:#2f90b9;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
font-size: 14px;
|
||||
font-weight: bolder;
|
||||
text-align: center;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.site{
|
||||
position: absolute;
|
||||
top: 0%;
|
||||
left: 0%;
|
||||
width: 100%;
|
||||
background-color: #111111aa;
|
||||
color:#2f90b9;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
font-size: 14px;
|
||||
font-weight: bolder;
|
||||
text-align: center;
|
||||
}
|
||||
.progress{
|
||||
position: absolute;
|
||||
bottom: 10%;
|
||||
left: 0%;
|
||||
width: 40%;
|
||||
background-color: #111111aa;
|
||||
color: #f8df70;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
font-size: 14px;
|
||||
font-weight: bolder;
|
||||
text-align: left;
|
||||
}
|
||||
.update{
|
||||
position: absolute;
|
||||
top: 5%;
|
||||
left: -40%;
|
||||
width: 100%;
|
||||
background-color: #68b88e;
|
||||
color: #cdcdcd;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
.operate{
|
||||
display: none;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
background-color: #111111aa;
|
||||
width: 100%;
|
||||
font-size: 13px;
|
||||
.operate-wrap{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.o-play, .o-star, .o-share{
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
width: 80px;
|
||||
height: 36px;
|
||||
text-align: center;
|
||||
line-height: 36px;
|
||||
color: #cdcdcd;
|
||||
&:hover{
|
||||
background-color: #111;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.name{
|
||||
font-size: 16px;
|
||||
padding: 10px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.info{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 12px;
|
||||
padding: 10px;
|
||||
}
|
||||
&:hover{
|
||||
.operate{
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,6 +138,17 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.show-picture{
|
||||
color: var(--d-fc-1);
|
||||
.card{
|
||||
background-color: var(--d-bgc-3);
|
||||
box-shadow: var(--d-bsc);
|
||||
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
|
||||
&:hover{
|
||||
box-shadow: var(--d-bsc-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,6 +138,17 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.show-picture{
|
||||
color: var(--g-fc-1);
|
||||
.card{
|
||||
background-color: var(--g-bgc-3);
|
||||
box-shadow: var(--g-bsc);
|
||||
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
|
||||
&:hover{
|
||||
box-shadow: var(--g-bsc-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
.theme-light{
|
||||
background-color: var(--l-bgc-1);
|
||||
// background-color: var(--l-bgc-1);
|
||||
background: rgba(0, 0, 0, 0);
|
||||
.zy-select{
|
||||
color: var(--l-fc-1);
|
||||
background-color: var(--l-bgc-1);
|
||||
@@ -138,6 +139,17 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.show-picture{
|
||||
color: var(--l-fc-1);
|
||||
.card{
|
||||
background-color: var(--l-bgc-3);
|
||||
box-shadow: var(--l-bsc);
|
||||
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
|
||||
&:hover{
|
||||
box-shadow: var(--l-bsc-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,6 +138,17 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.show-picture{
|
||||
color: var(--p-fc-1);
|
||||
.card{
|
||||
background-color: var(--p-bgc-3);
|
||||
box-shadow: var(--p-bsc);
|
||||
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
|
||||
&:hover{
|
||||
box-shadow: var(--p-bsc-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,10 @@ import { app, protocol, BrowserWindow, globalShortcut } from 'electron'
|
||||
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
|
||||
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
|
||||
import { initUpdater } from './lib/update/update'
|
||||
require('@electron/remote/main').initialize()
|
||||
|
||||
const isDevelopment = process.env.NODE_ENV !== 'production'
|
||||
|
||||
// const log = require('electron-log') // 用于调试主程序
|
||||
|
||||
app.commandLine.appendSwitch('disable-features', 'OutOfBlinkCors') // 允许跨域
|
||||
@@ -23,7 +26,8 @@ function createWindow () {
|
||||
webPreferences: {
|
||||
webSecurity: false,
|
||||
enableRemoteModule: true,
|
||||
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false,
|
||||
allowRunningInsecureContent: false
|
||||
}
|
||||
})
|
||||
@@ -35,12 +39,13 @@ function createWindow () {
|
||||
createProtocol('app')
|
||||
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://*/*']
|
||||
}
|
||||
require("@electron/remote/main").enable(win.webContents)
|
||||
win.webContents.session.webRequest.onBeforeSendHeaders(filter, (details, callback) => {
|
||||
const url = new URL(details.url)
|
||||
details.requestHeaders.Origin = url.origin
|
||||
@@ -63,7 +68,7 @@ function createWindow () {
|
||||
if (process.platform === 'darwin') {
|
||||
app.dock.show()
|
||||
}
|
||||
if (process.platform === 'Linux') {
|
||||
if (process.platform === 'linux') {
|
||||
app.disableHardwareAcceleration()
|
||||
app.commandLine.appendSwitch('--no-sandbox') // linux 关闭沙盒模式
|
||||
}
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
</g>
|
||||
</svg>
|
||||
</span>
|
||||
<span :class="[view === 'Recommendation' ? 'active ': ''] + 'zy-svg'" @click="changeView('Recommendation')">
|
||||
<!-- <span :class="[view === 'Recommendation' ? 'active ': ''] + 'zy-svg'" @click="changeView('Recommendation')">
|
||||
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="48px" height="48px" viewBox="0 0 24 24" aria-labelledby="thumbUpIconTitle" stroke="#2329D6" stroke-width="1" stroke-linecap="square" stroke-linejoin="miter" fill="none" color="#2329D6">
|
||||
<title id="thumbUpIconTitle">影视推荐</title>
|
||||
<path d="M8,8.73984815 C8,8.26242561 8.17078432,7.80075162 8.4814868,7.43826541 L13.2723931,1.84887469 C13.7000127,1.34998522 14.4122932,1.20614658 15,1.5 C15.5737957,1.78689785 15.849314,2.45205792 15.6464466,3.06066017 L14,8 L18.6035746,8 C18.7235578,8 18.8432976,8.01079693 18.9613454,8.03226018 C20.0480981,8.22985158 20.7689058,9.27101818 20.5713144,10.3577709 L19.2985871,17.3577709 C19.1256814,18.3087523 18.2974196,19 17.3308473,19 L10,19 C8.8954305,19 8,18.1045695 8,17 L8,8.73984815 Z"/>
|
||||
<path d="M4,18 L4,9"/>
|
||||
</svg>
|
||||
</span>
|
||||
</span> -->
|
||||
<span :class="[view === 'Play' ? 'active ': ''] + 'zy-svg'" @click="changeView('Play')">
|
||||
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-labelledby="playIconTitle">
|
||||
<title id="playIconTitle">播放</title>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<div class="detail-body zy-scroll" v-show="!loading">
|
||||
<div class="detail-body zy-scroll listpage" v-show="!loading">
|
||||
<div class="info">
|
||||
<div class="info-left">
|
||||
<img :src="info.pic" alt="">
|
||||
@@ -37,9 +37,9 @@
|
||||
</div>
|
||||
<div class="operate">
|
||||
<span @click="playEvent(selectedEpisode)">播放</span>
|
||||
<span @click="starEvent">收藏</span>
|
||||
<span @click="starEvent(info)">收藏</span>
|
||||
<span @click="downloadEvent">下载</span>
|
||||
<span @click="shareEvent">分享</span>
|
||||
<span @click="shareEvent(info,selectedEpisode)">分享</span>
|
||||
<span @click="doubanLinkEvent">豆瓣</span>
|
||||
<span @click="togglePlayOnlineEvent">
|
||||
<input type="checkbox" v-model="playOnline"> 播放在线高清视频
|
||||
@@ -64,6 +64,47 @@
|
||||
<span v-bind:class="{ selected: j === selectedEpisode }" v-for="(i, j) in videoList" :key="j" @click="playEvent(j)" @mouseenter="() => { selectedEpisode = j }">{{ i | ftName(j) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="m3u8">
|
||||
<div class="show-picture" v-show="info.recommendations && info.recommendations.length > 0">
|
||||
<span>喜欢这部电影的人也喜欢 · · · · · ·</span>
|
||||
<Waterfall :list="info.recommendations" :gutter="20" :width="240"
|
||||
:breakpoints="{
|
||||
1200: { //当屏幕宽度小于等于1200
|
||||
rowPerView: 4,
|
||||
},
|
||||
800: { //当屏幕宽度小于等于800
|
||||
rowPerView: 3,
|
||||
},
|
||||
500: { //当屏幕宽度小于等于500
|
||||
rowPerView: 2,
|
||||
}
|
||||
}"
|
||||
animationEffect="fadeIn"
|
||||
backgroundColor="rgba(0, 0, 0, 0)">
|
||||
<template slot="item" slot-scope="props">
|
||||
<div class="card">
|
||||
<div class="img">
|
||||
<img style="width: 100%" :src="props.data.pic" alt="" @click="detailEvent(props.data)">
|
||||
<div class="operate">
|
||||
<div class="operate-wrap">
|
||||
<span class="o-play" @click="playRecommendationEvent(props.data)">播放</span>
|
||||
<span class="o-star" @click="starEvent(props.data)">收藏</span>
|
||||
<span class="o-share" @click="shareEvent(props.data, 0)">分享</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="name">{{props.data.name}}</div>
|
||||
<div class="info">
|
||||
<span>{{props.data.area}}</span>
|
||||
<span>{{props.data.year}}</span>
|
||||
<span>{{props.data.note}}</span>
|
||||
<span>{{props.data.type}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Waterfall>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-mask zy-loading" v-show="loading">
|
||||
<div class="loader"></div>
|
||||
@@ -73,6 +114,7 @@
|
||||
</template>
|
||||
<script>
|
||||
import { mapMutations } from 'vuex'
|
||||
import Waterfall from 'vue-waterfall-plugin'
|
||||
import zy from '../lib/site/tools'
|
||||
import onlineVideo from '../lib/site/onlineVideo'
|
||||
import { star, history } from '../lib/dexie'
|
||||
@@ -85,6 +127,8 @@ export default {
|
||||
videoFlag: '',
|
||||
videoList: [],
|
||||
videoFullList: [],
|
||||
key: '',
|
||||
site: {},
|
||||
info: {},
|
||||
playOnline: false,
|
||||
selectedEpisode: 0, // 选定集数
|
||||
@@ -144,8 +188,22 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Waterfall
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SET_VIEW', 'SET_VIDEO', 'SET_DETAIL', 'SET_SHARE', 'SET_DetailCache']),
|
||||
async playRecommendationEvent (e) {
|
||||
const db = await history.find({ site: this.detail.key, ids: e.id })
|
||||
if (db) {
|
||||
this.video = { key: db.site, info: { id: db.ids, name: db.name, index: db.index, site: this.detail.site } }
|
||||
} else {
|
||||
this.video = { key: this.detail.key, info: { id: e.id, name: e.name, index: 0, site: this.detail.site } }
|
||||
}
|
||||
this.video.detail = e
|
||||
this.view = 'Play'
|
||||
this.detail.show = false
|
||||
},
|
||||
addClass (flag) {
|
||||
if (flag === this.videoFlag) {
|
||||
return 'selectedBox'
|
||||
@@ -200,15 +258,15 @@ export default {
|
||||
onlineVideo.playVideoOnline(this.selectedOnlineSite, this.detail.info.name, n)
|
||||
}
|
||||
},
|
||||
async starEvent () {
|
||||
const db = await star.find({ key: this.detail.key, ids: this.info.id })
|
||||
async starEvent (info) {
|
||||
const db = await star.find({ key: this.detail.key, ids: info.id })
|
||||
const doc = {
|
||||
key: this.detail.key,
|
||||
ids: this.info.id,
|
||||
ids: info.id,
|
||||
site: this.detail.site,
|
||||
name: this.info.name,
|
||||
detail: this.info,
|
||||
rate: this.info.rate
|
||||
name: info.name,
|
||||
detail: info,
|
||||
rate: info.rate
|
||||
}
|
||||
if (db) {
|
||||
star.update(db.id, doc)
|
||||
@@ -219,6 +277,10 @@ export default {
|
||||
})
|
||||
}
|
||||
},
|
||||
detailEvent (info) {
|
||||
this.detail.info = info
|
||||
this.getDetailInfo()
|
||||
},
|
||||
togglePlayOnlineEvent () {
|
||||
this.playOnline = !this.playOnline
|
||||
},
|
||||
@@ -257,12 +319,12 @@ export default {
|
||||
this.$message.error(err.info)
|
||||
})
|
||||
},
|
||||
shareEvent () {
|
||||
shareEvent (info, selectedEpisode) {
|
||||
this.share = {
|
||||
show: true,
|
||||
key: this.detail.key,
|
||||
info: this.info,
|
||||
index: this.selectedEpisode
|
||||
info: info,
|
||||
index: selectedEpisode
|
||||
}
|
||||
},
|
||||
doubanLinkEvent () {
|
||||
@@ -277,6 +339,17 @@ export default {
|
||||
const name = this.info.name.trim()
|
||||
const year = this.info.year
|
||||
this.info.rate = await zy.doubanRate(name, year)
|
||||
const recommendations = await zy.doubanRecommendations(name, year)
|
||||
if (recommendations) {
|
||||
this.info.recommendations = []
|
||||
recommendations.forEach(element => {
|
||||
zy.searchFirstDetail(this.detail.key, element).then(detailRes => {
|
||||
if (detailRes) {
|
||||
this.info.recommendations.push(detailRes)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
async getDetailInfo () {
|
||||
const id = this.detail.info.ids || this.detail.info.id
|
||||
@@ -293,13 +366,14 @@ export default {
|
||||
if (res) {
|
||||
this.info = res
|
||||
this.$set(this.info, 'rate', this.DetailCache[cacheKey].rate || '')
|
||||
this.$set(this.info, 'recommendations', this.DetailCache[cacheKey].recommendations || [])
|
||||
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
|
||||
this.DetailCache[cacheKey] = this.info
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="listpage" id="sites">
|
||||
<div class="listpage-header" v-show="!enableBatchEdit">
|
||||
<el-switch v-model="enableBatchEdit" active-text="批处理分组">></el-switch>
|
||||
<el-checkbox v-model="setting.excludeR18Films" @change="excludeR18FilmsChangeEvent">屏蔽福利片</el-checkbox>
|
||||
<el-button @click="openFilterKeywordsDiag" icon="el-icon-key">关键词过滤</el-button>
|
||||
<el-button @click="addSite" icon="el-icon-document-add">新增</el-button>
|
||||
<el-button @click="exportSites" icon="el-icon-upload2" title="导出全部,自动添加扩展名">导出</el-button>
|
||||
<el-button @click="importSites" icon="el-icon-download" title="支持同时导入多个文件">导入</el-button>
|
||||
@@ -41,7 +41,18 @@
|
||||
<template slot-scope="scope">
|
||||
<el-switch
|
||||
v-model="scope.row.isActive"
|
||||
@click.native.stop='isActiveChangeEvent(scope.row)'>
|
||||
@click.native.stop='propChangeEvent(scope.row)'>
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="reverseOrder"
|
||||
width="120"
|
||||
label="倒序排列">
|
||||
<template slot-scope="scope">
|
||||
<el-switch
|
||||
v-model="scope.row.reverseOrder"
|
||||
@click.native.stop='propChangeEvent(scope.row)'>>
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -83,7 +94,7 @@
|
||||
</div>
|
||||
<!-- 编辑页面 -->
|
||||
<div>
|
||||
<el-dialog :visible.sync="dialogVisible" v-if='dialogVisible' :title="dialogType==='edit'?'编辑源':'新增源'" :append-to-body="true" @close="closeDialog">
|
||||
<el-dialog :visible.sync="editSiteDialogVisible" v-if='editSiteDialogVisible' :title="dialogType==='edit'?'编辑源':'新增源'" :append-to-body="true" @close="closeDialog">
|
||||
<el-form :model="siteInfo" ref='siteInfo' label-width="75px" label-position="left" :rules="rules">
|
||||
<el-form-item label="源站名" prop='name'>
|
||||
<el-input v-model="siteInfo.name" placeholder="请输入源站名" />
|
||||
@@ -112,15 +123,36 @@
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
<!-- 设置过滤关键词页面 -->
|
||||
<div>
|
||||
<el-dialog :visible.sync="filterKeywordsDialogVisible" v-if='filterKeywordsDialogVisible' :title="'分类过滤'" :append-to-body="true" @close="closeDialog">
|
||||
<el-form>
|
||||
<el-switch v-model="excludeRootClasses" active-text="开启主分类过滤">></el-switch>
|
||||
<el-form-item>
|
||||
<el-input v-model="rootClassFilterKeywords" :autosize="{ minRows: 3, maxRows: 6}" type="textarea" placeholder="请输入过滤关键词" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-form>
|
||||
<el-switch v-model="excludeR18Films" active-text="开启福利分类过滤">></el-switch>
|
||||
<el-form-item>
|
||||
<el-input v-model="r18ClassFilterKeywords" :autosize="{ minRows: 3, maxRows: 6}" type="textarea" placeholder="请输入过滤关键词" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="closeDialog">取消</el-button>
|
||||
<el-button type="primary" @click="saveFilterKeywords">保存</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapMutations } from 'vuex'
|
||||
import { sites, setting } from '../lib/dexie'
|
||||
import zy from '../lib/site/tools'
|
||||
import { remote } from 'electron'
|
||||
import fs from 'fs'
|
||||
import Sortable from 'sortablejs'
|
||||
const remote = require('@electron/remote')
|
||||
|
||||
export default {
|
||||
name: 'editSites',
|
||||
@@ -129,7 +161,8 @@ export default {
|
||||
show: false,
|
||||
sites: [],
|
||||
dialogType: 'new',
|
||||
dialogVisible: false,
|
||||
editSiteDialogVisible: false,
|
||||
filterKeywordsDialogVisible: false,
|
||||
siteInfo: {
|
||||
key: '',
|
||||
name: '',
|
||||
@@ -139,6 +172,10 @@ export default {
|
||||
group: '',
|
||||
isActive: true
|
||||
},
|
||||
excludeRootClasses: true,
|
||||
excludeR18Films: true,
|
||||
rootClassFilterKeywords: [],
|
||||
r18ClassFilterKeywords: [],
|
||||
siteGroup: [],
|
||||
rules: {
|
||||
name: [
|
||||
@@ -204,12 +241,6 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SET_SETTING']),
|
||||
excludeR18FilmsChangeEvent () {
|
||||
setting.find().then(res => {
|
||||
res.excludeR18Films = this.setting.excludeR18Films
|
||||
setting.update(res)
|
||||
})
|
||||
},
|
||||
selectionCellClick (selection, row) {
|
||||
if (this.shiftDown && this.selectionBegin !== '' && selection.includes(row)) {
|
||||
this.selectionEnd = row.id
|
||||
@@ -249,6 +280,11 @@ export default {
|
||||
},
|
||||
getSites () {
|
||||
sites.all().then(res => {
|
||||
res.forEach(element => {
|
||||
if (element.reverseOrder === null || element.reverseOrder === undefined) {
|
||||
element.reverseOrder = false
|
||||
}
|
||||
})
|
||||
this.sites = res
|
||||
})
|
||||
},
|
||||
@@ -261,6 +297,29 @@ export default {
|
||||
}
|
||||
this.siteGroup = arr
|
||||
},
|
||||
openFilterKeywordsDiag () {
|
||||
this.excludeRootClasses = this.setting.excludeRootClasses
|
||||
this.excludeR18Films = this.setting.excludeR18Films
|
||||
this.rootClassFilterKeywords = this.setting.rootClassFilter?.join()
|
||||
this.r18ClassFilterKeywords = this.setting.r18ClassFilter?.join()
|
||||
this.filterKeywordsDialogVisible = true
|
||||
},
|
||||
saveFilterKeywords () {
|
||||
// 移除空格,然后按逗号分开
|
||||
this.setting.rootClassFilter = this.rootClassFilterKeywords?.replace(/\s/g, '').split(',')
|
||||
this.setting.r18ClassFilter = this.r18ClassFilterKeywords?.replace(/\s/g, '').split(',')
|
||||
this.setting.classFilter = []
|
||||
this.setting.excludeRootClasses = this.excludeRootClasses
|
||||
if (this.excludeRootClasses) {
|
||||
this.setting.classFilter = this.setting.classFilter.concat(this.setting.rootClassFilter)
|
||||
}
|
||||
this.setting.excludeR18Films = this.excludeR18Films
|
||||
if (this.excludeR18Films) {
|
||||
this.setting.classFilter = this.setting.classFilter.concat(this.setting.r18ClassFilter)
|
||||
}
|
||||
setting.update(this.setting)
|
||||
this.filterKeywordsDialogVisible = false
|
||||
},
|
||||
addSite () {
|
||||
if (this.checkAllSitesLoading) {
|
||||
this.$message.info('正在检测, 请勿操作.')
|
||||
@@ -268,7 +327,7 @@ export default {
|
||||
}
|
||||
this.getSitesGroup()
|
||||
this.dialogType = 'new'
|
||||
this.dialogVisible = true
|
||||
this.editSiteDialogVisible = true
|
||||
this.siteInfo = {
|
||||
key: '',
|
||||
name: '',
|
||||
@@ -286,12 +345,13 @@ export default {
|
||||
}
|
||||
this.getSitesGroup()
|
||||
this.dialogType = 'edit'
|
||||
this.dialogVisible = true
|
||||
this.editSiteDialogVisible = true
|
||||
this.siteInfo = siteInfo
|
||||
this.editOldkey = siteInfo.key
|
||||
},
|
||||
closeDialog () {
|
||||
this.dialogVisible = false
|
||||
this.editSiteDialogVisible = false
|
||||
this.filterKeywordsDialogVisible = false
|
||||
this.getSites()
|
||||
},
|
||||
removeEvent (e) {
|
||||
@@ -348,7 +408,7 @@ export default {
|
||||
group: ''
|
||||
}
|
||||
this.dialogType === 'edit' ? this.$message.success('修改成功!') : this.$message.success('新增源成功!')
|
||||
this.dialogVisible = false
|
||||
this.editSiteDialogVisible = false
|
||||
this.getSites()
|
||||
})
|
||||
this.editOldkey = ''
|
||||
@@ -437,8 +497,7 @@ export default {
|
||||
resetSitesEvent () {
|
||||
let url = this.setting.sitesDataURL
|
||||
if (!url) {
|
||||
// 如果没有设置源站文件链接,使用默认的gitee源
|
||||
url = 'https://gitee.com/cuiocean/ZY-Player-Resources/raw/main/Sites/Sites.json'
|
||||
url = 'https://raw.iqiq.io/Hunlongyu/ZY-Player-Resources/main/Sites/20220713.json'
|
||||
}
|
||||
zy.getDefaultSites(url).then(res => {
|
||||
if (res.length > 0) {
|
||||
@@ -463,9 +522,10 @@ export default {
|
||||
this.sites = this.$refs.editSitesTable.tableData
|
||||
}
|
||||
},
|
||||
isActiveChangeEvent (row) {
|
||||
propChangeEvent (row) {
|
||||
sites.remove(row.id)
|
||||
sites.add(row)
|
||||
this.getSites()
|
||||
},
|
||||
resetId (inArray) {
|
||||
let id = 1
|
||||
|
||||
@@ -281,7 +281,7 @@
|
||||
animationEffect="fadeIn"
|
||||
backgroundColor="rgba(0, 0, 0, 0)">
|
||||
<template slot="item" slot-scope="props">
|
||||
<div class="card" v-show="!setting.excludeR18Films || !containsR18Keywords(props.data.type)">
|
||||
<div class="card" v-show="!setting.excludeR18Films || !containsClassFilterKeyword(props.data.type)">
|
||||
<div class="img">
|
||||
<div class="site">
|
||||
<span>{{props.data.site.name}}</span>
|
||||
@@ -344,9 +344,8 @@ export default {
|
||||
filteredSearchContents: [],
|
||||
currentColumn: '',
|
||||
searchGroup: '',
|
||||
searchGroups: [],
|
||||
// 福利片关键词
|
||||
r18KeyWords: ['伦理', '论理', '倫理', '福利', '激情', '理论', '写真', '情色', '美女', '街拍', '赤足', '性感', '里番', 'VIP'],
|
||||
searchGroups: ['站内', '组内', '全站'],
|
||||
classFilterKeywords: [],
|
||||
filteredList: [],
|
||||
areas: [],
|
||||
searchRunning: false,
|
||||
@@ -414,12 +413,13 @@ export default {
|
||||
}
|
||||
},
|
||||
filterSettings () {
|
||||
return this.$store.getters.getSetting.excludeR18Films // 需要监听的数据
|
||||
return this.$store.getters.getSetting.classFilter // 需要监听的数据
|
||||
},
|
||||
searchSites () {
|
||||
if (this.searchGroup === '站内') return [this.site]
|
||||
if (this.searchGroup === '组内') return this.sites.filter(site => site.group === this.site.group)
|
||||
if (this.searchGroup === '全站') return this.sites
|
||||
return this.sites.filter(site => site.group === this.searchGroup)
|
||||
return this.sites.filter(site => site.isActive)
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
@@ -444,7 +444,7 @@ export default {
|
||||
}
|
||||
},
|
||||
filterSettings () {
|
||||
this.siteClick(this.site.name)
|
||||
this.refreshClass()
|
||||
},
|
||||
list: {
|
||||
handler (list) {
|
||||
@@ -456,9 +456,12 @@ export default {
|
||||
siteSearchCount () {
|
||||
if (this.siteSearchCount === this.searchSites.length) this.searchRunning = false
|
||||
},
|
||||
site () {
|
||||
this.siteClick(this.site.name)
|
||||
},
|
||||
searchContents: {
|
||||
handler (list) {
|
||||
list = list.filter(res => !this.setting.excludeR18Films || !this.containsR18Keywords(res.type))
|
||||
list = list.filter(res => !this.setting.excludeR18Films || !this.containsClassFilterKeyword(res.type))
|
||||
this.areas = [...new Set(list.map(ele => ele.area))].filter(x => x)
|
||||
this.searchClassList = [...new Set(list.map(ele => ele.type))].filter(x => x)
|
||||
this.refreshFilteredList()
|
||||
@@ -500,14 +503,14 @@ export default {
|
||||
let filteredData = this.showFind ? this.searchContents : this.list
|
||||
if (this.showFind) filteredData = filteredData.filter(x => (this.selectedSearchClassNames.length === 0) || this.selectedSearchClassNames.includes(x.type))
|
||||
filteredData = filteredData.filter(x => (this.selectedAreas.length === 0) || this.selectedAreas.includes(x.area))
|
||||
filteredData = filteredData.filter(res => !this.setting.excludeR18Films || !this.containsR18Keywords(res.type))
|
||||
filteredData = filteredData.filter(res => !this.setting.excludeR18Films || !this.containsClassFilterKeyword(res.type))
|
||||
filteredData = filteredData.filter(res => res.year >= this.selectedYears.start)
|
||||
filteredData = filteredData.filter(res => res.year <= this.selectedYears.end)
|
||||
if (!this.showFind) this.selectedClassName = this.type.name + ' ' + filteredData.length + '/' + this.recordcount
|
||||
switch (this.sortKeyword) {
|
||||
case '按上映年份':
|
||||
filteredData.sort(function (a, b) {
|
||||
return a.year - b.year
|
||||
return b.year - a.year
|
||||
})
|
||||
break
|
||||
case '按片名':
|
||||
@@ -521,8 +524,14 @@ export default {
|
||||
})
|
||||
break
|
||||
default:
|
||||
filteredData.sort(function (a, b) {
|
||||
return new Date(b.last) - new Date(a.last)
|
||||
})
|
||||
break
|
||||
}
|
||||
|
||||
// Get unique film data
|
||||
filteredData = Array.from(new Set(filteredData))
|
||||
if (this.showFind) {
|
||||
this.filteredSearchContents = filteredData
|
||||
} else {
|
||||
@@ -592,6 +601,16 @@ export default {
|
||||
})
|
||||
}
|
||||
},
|
||||
refreshClass () {
|
||||
this.getClass().then(res => {
|
||||
this.classList = res
|
||||
// cache classList data
|
||||
FILM_DATA_CACHE[this.site.key] = {
|
||||
classList: this.classList
|
||||
}
|
||||
this.classClick(this.type.name)
|
||||
})
|
||||
},
|
||||
classClick (className) {
|
||||
this.list = []
|
||||
this.type = this.classList.find(x => x.name === className)
|
||||
@@ -619,20 +638,11 @@ export default {
|
||||
getClass () {
|
||||
return new Promise((resolve, reject) => {
|
||||
const key = this.site.key
|
||||
// 屏蔽主分类
|
||||
const classToHide = ['电影', '电影片', '电视剧', '连续剧', '综艺', '动漫']
|
||||
zy.class(key).then(res => {
|
||||
const allClass = [{ name: '最新', tid: 0 }]
|
||||
res.class.forEach(element => {
|
||||
if (!this.setting.excludeRootClasses || !classToHide.includes(element.name)) {
|
||||
if (this.setting.excludeR18Films) {
|
||||
const containKeyWord = this.containsR18Keywords(element.name)
|
||||
if (!containKeyWord) {
|
||||
allClass.push(element)
|
||||
}
|
||||
} else {
|
||||
allClass.push(element)
|
||||
}
|
||||
if (!this.containsClassFilterKeyword(element.name)) {
|
||||
allClass.push(element)
|
||||
}
|
||||
})
|
||||
resolve(allClass)
|
||||
@@ -641,19 +651,20 @@ export default {
|
||||
})
|
||||
})
|
||||
},
|
||||
containsR18Keywords (name) {
|
||||
const containKeyWord = false
|
||||
if (!name) {
|
||||
return containKeyWord
|
||||
containsClassFilterKeyword (name) {
|
||||
let ret = false
|
||||
// 主分类过滤, 检测关键词是否包含分类名
|
||||
if (this.setting.excludeRootClasses) {
|
||||
ret = this.setting.rootClassFilter?.some(v => v.includes(name))
|
||||
}
|
||||
return this.r18KeyWords.some(v => name.includes(v))
|
||||
// 福利过滤,检测分类名是否包含关键词
|
||||
if (this.setting.excludeR18Films && !ret) {
|
||||
ret = this.setting.r18ClassFilter?.some(v => name?.includes(v))
|
||||
}
|
||||
return ret
|
||||
},
|
||||
toFlipPagecount () {
|
||||
// 似乎需要解析的网站的视频排序和其他m3u8采集站的顺序正好相反
|
||||
if (this.site.jiexiUrl) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return this.site.reverseOrder
|
||||
},
|
||||
infiniteHandler ($state) {
|
||||
const key = this.site.key
|
||||
@@ -861,12 +872,34 @@ export default {
|
||||
this.showFind = false
|
||||
}
|
||||
},
|
||||
async getDefaultSites () {
|
||||
const s = await setting.find()
|
||||
zy.getDefaultSites(s.sitesDataURL).then(res => {
|
||||
if (res && typeof res === 'string') {
|
||||
const json = JSON.parse(res)
|
||||
sites.clear().then(sites.bulkAdd(json))
|
||||
}
|
||||
if (res && typeof res === 'object') {
|
||||
sites.clear().then(sites.bulkAdd(res))
|
||||
}
|
||||
sites.all().then(res => {
|
||||
if (res) {
|
||||
this.sites = res.filter(item => item.isActive)
|
||||
if (this.site === undefined || !this.sites.some(x => x.key === this.site.key)) {
|
||||
this.site = this.sites[0]
|
||||
this.selectedSiteName = this.sites[0].name
|
||||
}
|
||||
}
|
||||
})
|
||||
}).catch(error => {
|
||||
this.$message.error('获取云端源站失败. ' + error)
|
||||
})
|
||||
},
|
||||
getAllSites () {
|
||||
sites.all().then(res => {
|
||||
if (res.length <= 0) {
|
||||
this.site = {}
|
||||
this.type = {}
|
||||
this.list = []
|
||||
this.$message.warning('检测到视频源未能正常加载, 即将重置源.')
|
||||
this.getDefaultSites()
|
||||
} else {
|
||||
this.sites = res.filter(item => item.isActive)
|
||||
if (this.site === undefined || !this.sites.some(x => x.key === this.site.key)) {
|
||||
@@ -874,10 +907,6 @@ export default {
|
||||
this.selectedSiteName = this.sites[0].name
|
||||
}
|
||||
}
|
||||
this.searchGroups = [...new Set(this.sites.map(site => site.group))]
|
||||
if (this.searchGroups.length === 1) this.searchGroups = []
|
||||
this.searchGroups.unshift('站内')
|
||||
this.searchGroups.push('全站')
|
||||
this.searchGroup = this.setting.searchGroup
|
||||
if (this.searchGroup === undefined) setting.find().then(res => { this.searchGroup = res.searchGroup })
|
||||
})
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
const { remote } = require('electron')
|
||||
const remote = require('@electron/remote')
|
||||
export default {
|
||||
name: 'frame',
|
||||
computed: {
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
<el-button @click.stop="exportHistory" icon="el-icon-upload2" title="导出全部,自动添加扩展名">导出</el-button>
|
||||
<el-button @click.stop="importHistory" icon="el-icon-download" title="支持同时导入多个文件">导入</el-button>
|
||||
<el-button @click.stop="removeSelectedItems" icon="el-icon-delete-solid">{{ multipleSelection.length === 0 ? "清空" : "删除所选" }}</el-button>
|
||||
<el-button @click.stop="updateAllEvent" icon="el-icon-refresh">检查更新</el-button>
|
||||
<b-button-group>
|
||||
<el-switch v-model="onlyShowItemsHasUpdate" active-text="有更新" inactive-text="全部" @change="refreshFilteredList"></el-switch>
|
||||
<el-button @click.stop="updateAllEvent" icon="el-icon-refresh">检查更新</el-button>
|
||||
</b-button-group>
|
||||
</div>
|
||||
<div class="toolbar" v-show="showToolbar">
|
||||
<el-switch v-model="onlyShowItemsHasUpdate" active-text="有更新" inactive-text="全部" @change="refreshFilteredList"></el-switch>
|
||||
<el-select v-model="selectedAreas" size="small" multiple placeholder="地区" popper-class="popper" :popper-append-to-body="false" @remove-tag="refreshFilteredList" @change="refreshFilteredList">
|
||||
<el-option
|
||||
v-for="item in areas"
|
||||
@@ -79,10 +81,10 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="list.some(e => e.time)"
|
||||
width="150"
|
||||
width="200"
|
||||
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.time && scope.row.duration">{{fmtMSS(scope.row.time.toFixed(0))}}/{{fmtMSS(scope.row.duration.toFixed(0))}} ({{progress(scope.row)}}%)</span>
|
||||
<span v-if="scope.row.onlinePlay">在线解析</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -134,7 +136,7 @@
|
||||
<div class="name" @click="detailEvent(props.data)">{{props.data.name}}</div>
|
||||
<div class="info">
|
||||
<span v-if="props.data.time && props.data.duration">
|
||||
{{fmtMSS(props.data.time.toFixed(0))}}/{{fmtMSS(props.data.duration.toFixed(0))}}
|
||||
{{fmtMSS(props.data.time.toFixed(0))}}/{{fmtMSS(props.data.duration.toFixed(0))}} ({{progress(props.data)}}%)
|
||||
</span>
|
||||
<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">
|
||||
@@ -152,9 +154,9 @@
|
||||
import { mapMutations } from 'vuex'
|
||||
import { history, sites, setting } from '../lib/dexie'
|
||||
import zy from '../lib/site/tools'
|
||||
import { remote } from 'electron'
|
||||
import fs from 'fs'
|
||||
import Waterfall from 'vue-waterfall-plugin'
|
||||
const remote = require('@electron/remote')
|
||||
const { clipboard } = require('electron')
|
||||
|
||||
export default {
|
||||
@@ -169,6 +171,7 @@ export default {
|
||||
multipleSelection: [],
|
||||
areas: [],
|
||||
types: [],
|
||||
filteredList: [],
|
||||
// Update
|
||||
numNoUpdate: 0,
|
||||
// Toolbar
|
||||
@@ -176,7 +179,7 @@ export default {
|
||||
selectedAreas: [],
|
||||
selectedTypes: [],
|
||||
sortKeyword: '',
|
||||
sortKeywords: ['按片名', '按上映年份', '按更新时间'],
|
||||
sortKeywords: ['按片名', '按上映年份', '按更新时间', '按完成度'],
|
||||
selectedYears: { start: 0, end: new Date().getFullYear() },
|
||||
onlyShowItemsHasUpdate: false
|
||||
}
|
||||
@@ -292,7 +295,6 @@ export default {
|
||||
toggleViewMode () {
|
||||
this.setting.historyViewMode = this.setting.historyViewMode === 'picture' ? 'table' : 'picture'
|
||||
if (this.setting.historyViewMode === 'table') {
|
||||
setTimeout(() => { this.rowDrop() }, 100)
|
||||
this.showShiftPrompt()
|
||||
} else {
|
||||
setTimeout(() => { if (this.$refs.historyWaterfall) this.$refs.historyWaterfall.refresh() }, 700)
|
||||
@@ -339,6 +341,9 @@ export default {
|
||||
return new Date(b.detail.last) - new Date(a.detail.last)
|
||||
})
|
||||
break
|
||||
case '按完成度':
|
||||
filteredData.sort(this.sortByProgress)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
@@ -348,6 +353,16 @@ export default {
|
||||
this.filteredList = this.filteredList.filter(x => x.hasUpdate)
|
||||
}
|
||||
},
|
||||
progress (e) {
|
||||
return e.duration > 0 ? ((e.time / e.duration) * 100).toFixed(0) : 0
|
||||
},
|
||||
sortByProgress (a, b) {
|
||||
if (this.progress(a) < this.progress(b)) {
|
||||
return -1
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
},
|
||||
fmtMSS (s) {
|
||||
return (s - (s %= 60)) / 60 + (s > 9 ? ':' : ':0') + s
|
||||
},
|
||||
|
||||
@@ -110,10 +110,10 @@ import { mapMutations } from 'vuex'
|
||||
import { iptv, channelList, setting } from '../lib/dexie'
|
||||
import { iptv as defaultChannels } from '../lib/dexie/initData'
|
||||
import zy from '../lib/site/tools'
|
||||
import { remote } from 'electron'
|
||||
import fs from 'fs'
|
||||
import Sortable from 'sortablejs'
|
||||
import axios from 'axios'
|
||||
const remote = require('@electron/remote')
|
||||
export default {
|
||||
name: 'iptv',
|
||||
data () {
|
||||
|
||||
@@ -252,6 +252,7 @@ import { mapMutations } from 'vuex'
|
||||
import { star, history, setting, shortcut, mini, channelList, sites } from '../lib/dexie'
|
||||
import zy from '../lib/site/tools'
|
||||
import Player from 'xgplayer'
|
||||
import 'xgplayer-mp4'
|
||||
import HlsJsPlayer from 'xgplayer-hls.js'
|
||||
import FlvJsPlayer from 'xgplayer-flv.js'
|
||||
import mt from 'mousetrap'
|
||||
@@ -259,7 +260,8 @@ import Clickoutside from 'element-ui/src/utils/clickoutside'
|
||||
import { exec, execFile } from 'child_process'
|
||||
import PinyinMatch from 'pinyin-match'
|
||||
|
||||
const { remote, clipboard } = require('electron')
|
||||
const { clipboard } = require('electron')
|
||||
const remote = require('@electron/remote')
|
||||
const win = remote.getCurrentWindow()
|
||||
const URL = require('url')
|
||||
const VIDEO_DETAIL_CACHE = {}
|
||||
@@ -342,7 +344,7 @@ export default {
|
||||
videoTitle: true,
|
||||
airplay: true,
|
||||
closeVideoTouch: true,
|
||||
ignores: ['cssFullscreen', 'replay', 'error'], // 为了切换播放器类型时避免显示错误刷新,暂时忽略错误
|
||||
ignores: ['replay', 'error'], // 为了切换播放器类型时避免显示错误刷新,暂时忽略错误
|
||||
preloadTime: 300
|
||||
},
|
||||
state: {
|
||||
@@ -445,6 +447,9 @@ export default {
|
||||
set (val) {
|
||||
this.SET_DetailCache(val)
|
||||
}
|
||||
},
|
||||
VideoEssentialInfo () {
|
||||
return this.video.key + '@' + this.video.info.id + '@' + this.video.info.index
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -458,12 +463,11 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
video: {
|
||||
VideoEssentialInfo: {
|
||||
handler () {
|
||||
if (this.changingIPTV) return
|
||||
this.getUrls()
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
setting: {
|
||||
handler () {
|
||||
@@ -655,9 +659,9 @@ export default {
|
||||
const currentSite = await sites.find({ key: this.video.key })
|
||||
this.$message.info('即将调用解析接口播放,请等待...')
|
||||
if (currentSite.jiexiUrl) {
|
||||
this.onlineUrl = /^\s*(default|默认)\s*$/i.test(currentSite.jiexiUrl) ? this.setting.defaultParseURL + url : currentSite.jiexiUrl + url
|
||||
this.onlineUrl = currentSite.jiexiUrl + url
|
||||
} else {
|
||||
this.onlineUrl = url
|
||||
this.onlineUrl = this.setting.defaultParseURL + url
|
||||
}
|
||||
this.videoPlaying('online')
|
||||
return
|
||||
@@ -1568,7 +1572,7 @@ export default {
|
||||
},
|
||||
minMaxEvent () {
|
||||
win.on('minimize', () => {
|
||||
if (this.xg && this.xg.hasStart) {
|
||||
if (this.xg && this.xg.hasStart && this.setting.pauseWhenMinimize) {
|
||||
this.xg.pause()
|
||||
}
|
||||
})
|
||||
@@ -1664,6 +1668,9 @@ export default {
|
||||
cursor: pointer;
|
||||
margin-left: 3px;
|
||||
}
|
||||
.xgplayer-skin-default .xg-btn-playPrev {
|
||||
margin-left: 50px;
|
||||
}
|
||||
.xgplayer-skin-default .xg-btn-quitMiniMode {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
<template>
|
||||
<div class="listpage" id="recommendations">
|
||||
<div class="listpage-header" id="recommendations-header">
|
||||
<el-select v-model="selectedRecommendationType" size="small" slot="prepend"
|
||||
:popper-append-to-body="false"
|
||||
popper-class="popper"
|
||||
default-first-option placeholder="请选择"
|
||||
@change="changeRecommendationTypeEvent">
|
||||
<el-option
|
||||
v-for="item in recommendationTypes"
|
||||
:key="item"
|
||||
:label="item"
|
||||
:value="item">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-button type="text">视频数:{{ recommendations.length }}</el-button>
|
||||
<el-button :loading="loading" @click.stop="updateEvent" icon="el-icon-refresh">更新推荐</el-button>
|
||||
</div>
|
||||
@@ -86,7 +98,6 @@
|
||||
<el-button @click.stop="playEvent(scope.row)" type="text">播放</el-button>
|
||||
<el-button @click.stop="shareEvent(scope.row)" type="text">分享</el-button>
|
||||
<el-button @click.stop="downloadEvent(scope.row)" type="text">下载</el-button>
|
||||
<el-button @click.stop="deleteEvent(scope.row)" type="text">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -118,7 +129,6 @@
|
||||
<span class="o-play" @click="playEvent(props.data)">播放</span>
|
||||
<span class="o-share" @click="shareEvent(props.data)">分享</span>
|
||||
<span class="o-star" @click="downloadEvent(props.data)">下载</span>
|
||||
<span class="o-star" @click="deleteEvent(props.data)">删除</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -138,10 +148,12 @@
|
||||
</template>
|
||||
<script>
|
||||
import { mapMutations } from 'vuex'
|
||||
import { history, recommendation, setting } from '../lib/dexie'
|
||||
import { history, recommendation, setting, sites, cachedMovies } from '../lib/dexie'
|
||||
import zy from '../lib/site/tools'
|
||||
import Waterfall from 'vue-waterfall-plugin'
|
||||
import axios from 'axios'
|
||||
const { clipboard } = require('electron')
|
||||
|
||||
export default {
|
||||
name: 'recommendations',
|
||||
data () {
|
||||
@@ -152,13 +164,47 @@ export default {
|
||||
types: [],
|
||||
areas: [],
|
||||
filteredList: [],
|
||||
// 不同推荐
|
||||
recommendationsDefault: [],
|
||||
recommendationTypes: ['豆瓣热门电影', '豆瓣高分电影', '豆瓣华语电影', '豆瓣冷门佳片', '豆瓣热门剧集', '豆瓣热门美剧', '豆瓣热门英剧', '豆瓣热门国产剧', '豆瓣热门综艺', '豆瓣热门动漫', '豆瓣热门纪录片', '豆瓣热门动画电影'],
|
||||
selectedRecommendationType: '豆瓣热门电影',
|
||||
// Toolbar
|
||||
showToolbar: false,
|
||||
selectedAreas: [],
|
||||
selectedTypes: [],
|
||||
sortKeyword: '',
|
||||
sortKeywords: ['按片名', '按上映年份', '按更新时间'],
|
||||
selectedYears: { start: 0, end: new Date().getFullYear() }
|
||||
sortKeywords: ['按片名', '按上映年份', '按更新时间', '按评分'],
|
||||
selectedYears: { start: 0, end: new Date().getFullYear() },
|
||||
// 缓存数据
|
||||
localCachedMovies: [],
|
||||
// 豆瓣
|
||||
douban: {
|
||||
page_limit: 50,
|
||||
hotMoviePageStart: 0,
|
||||
hotmovie: [],
|
||||
hotTVPageStart: 0,
|
||||
hotTV: [],
|
||||
highRateMoviePageStart: 0,
|
||||
highRateMovie: [],
|
||||
hotAnimePageStart: 0,
|
||||
hotAnime: [],
|
||||
hotDocumentaryPageStart: 0,
|
||||
hotDocumentary: [],
|
||||
hotTVShowPageStart: 0,
|
||||
hotTVShow: [],
|
||||
hotCartonMoviePageStart: 0,
|
||||
hotCartonMovie: [],
|
||||
hotAmericanTVSeriesPageStart: 0,
|
||||
hotAmericanTVSeries: [],
|
||||
hotBritishTVSeriesPageStart: 0,
|
||||
hotBritishTVSeries: [],
|
||||
hotChineseTVSeriesPageStart: 0,
|
||||
hotChineseTVSeries: [],
|
||||
goodButNotHotMoviesPageStart: 0,
|
||||
goodButNotHotMovies: [],
|
||||
chineseMoviesPageStart: 0,
|
||||
chineseMovies: []
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
@@ -223,6 +269,199 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SET_VIEW', 'SET_DETAIL', 'SET_VIDEO', 'SET_SHARE', 'SET_SETTING']),
|
||||
changeRecommendationTypeEvent () {
|
||||
if (this.selectedRecommendationType === '作者推荐') {
|
||||
this.recommendations = this.recommendationsDefault
|
||||
} else {
|
||||
if (this.selectedRecommendationType === '豆瓣热门电影') {
|
||||
this.recommendations = [...this.douban.hotmovie]
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣高分电影') {
|
||||
this.recommendations = [...this.douban.highRateMovie]
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门剧集') {
|
||||
this.recommendations = [...this.douban.hotTV]
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门美剧') {
|
||||
this.recommendations = [...this.douban.hotAmericanTVSeries]
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门英剧') {
|
||||
this.recommendations = [...this.douban.hotBritishTVSeries]
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门国产剧') {
|
||||
this.recommendations = [...this.douban.hotChineseTVSeries]
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门动漫') {
|
||||
this.recommendations = [...this.douban.hotAnime]
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门纪录片') {
|
||||
this.recommendations = [...this.douban.hotDocumentary]
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门综艺') {
|
||||
this.recommendations = [...this.douban.hotTVShow]
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门动画电影') {
|
||||
this.recommendations = [...this.douban.hotCartonMovie]
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣冷门佳片') {
|
||||
this.recommendations = [...this.douban.goodButNotHotMovies]
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣华语电影') {
|
||||
this.recommendations = [...this.douban.chineseMovies]
|
||||
}
|
||||
if (this.recommendations.length === 0) {
|
||||
this.updateDoubanRecommendationsEvent()
|
||||
}
|
||||
}
|
||||
},
|
||||
getRecommendationsDoubanMovieOrTV (doubanUrl) {
|
||||
axios.get(doubanUrl).then(res => {
|
||||
if (res.data) {
|
||||
res.data.subjects.forEach(element => {
|
||||
const localCachedMovie = this.localCachedMovies.find(e => e.key === this.sites[0].key && e.name === element.title)
|
||||
if (localCachedMovie) {
|
||||
this.updateDoubanRecommendataions(localCachedMovie)
|
||||
} else {
|
||||
this.searchAndCacheMovie(element)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
updateDoubanRecommendataions (movie) {
|
||||
this.recommendations.push(movie)
|
||||
if (this.selectedRecommendationType === '豆瓣热门电影') {
|
||||
this.douban.hotmovie.push(movie)
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣高分电影') {
|
||||
this.douban.highRateMovie.push(movie)
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门剧集') {
|
||||
this.douban.hotTV.push(movie)
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门美剧') {
|
||||
this.douban.hotAmericanTVSeries.push(movie)
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门英剧') {
|
||||
this.douban.hotBritishTVSeries.push(movie)
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门国产剧') {
|
||||
this.douban.hotChineseTVSeries.push(movie)
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门动漫') {
|
||||
this.douban.hotAnime.push(movie)
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门纪录片') {
|
||||
this.douban.hotDocumentary.push(movie)
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门综艺') {
|
||||
this.douban.hotTVShow.push(movie)
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门动画电影') {
|
||||
this.douban.hotCartonMovie.push(movie)
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣冷门佳片') {
|
||||
this.douban.goodButNotHotMovies.push(movie)
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣华语电影') {
|
||||
this.douban.chineseMovies.push(movie)
|
||||
}
|
||||
},
|
||||
searchAndCacheMovie (element) {
|
||||
zy.searchFirstDetail(this.sites[0].key, element.title).then(detailRes => {
|
||||
if (detailRes) {
|
||||
const doc = {
|
||||
key: this.sites[0].key,
|
||||
ids: detailRes.id,
|
||||
site: this.sites[0],
|
||||
name: detailRes.name,
|
||||
detail: detailRes,
|
||||
rate: element.rate
|
||||
}
|
||||
this.updateDoubanRecommendataions(doc)
|
||||
this.localCachedMovies.push(doc)
|
||||
cachedMovies.add(doc)
|
||||
}
|
||||
})
|
||||
},
|
||||
updateEvent () {
|
||||
if (this.selectedRecommendationType === '作者推荐') {
|
||||
this.updateAuthorRecommendataions()
|
||||
} else {
|
||||
this.updateDoubanRecommendationsEvent()
|
||||
}
|
||||
},
|
||||
updateAuthorRecommendataions () {
|
||||
const url = 'https://raw.githubusercontent.com/cuiocean/ZY-Player-Resources/main/Recommendations/Recommendations.json'
|
||||
this.loading = true
|
||||
axios.get(url).then(res => {
|
||||
if (res.status === 200) {
|
||||
if (res.data.length > 0) {
|
||||
this.recommendations = res.data
|
||||
recommendation.clear().then(recommendation.bulkAdd(this.recommendations))
|
||||
this.getFilterData()
|
||||
this.$message.success('更新推荐成功. 仅根据作者cuiocean个人喜好推荐,不喜请无视.')
|
||||
}
|
||||
}
|
||||
this.loading = false
|
||||
}).catch(error => {
|
||||
this.loading = false
|
||||
this.$message.error('更新推荐失败. ' + error)
|
||||
this.$message.warning('最新的推荐数据保存在Github上,请考虑使用代理或者等待下一版本内置数据更新.')
|
||||
})
|
||||
},
|
||||
updateDoubanRecommendationsEvent () {
|
||||
let doubanUrl = ''
|
||||
if (this.selectedRecommendationType === '豆瓣热门电影') {
|
||||
doubanUrl = `https://movie.douban.com/j/search_subjects?type=movie&tag=热门&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.hotMoviePageStart}`
|
||||
this.douban.hotMoviePageStart = this.douban.hotMoviePageStart + this.douban.page_limit
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门剧集') {
|
||||
doubanUrl = `https://movie.douban.com/j/search_subjects?type=tv&tag=热门&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.hotTVPageStart}`
|
||||
this.douban.hotTVPageStart = this.douban.hotTVPageStart + this.douban.page_limit
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门美剧') {
|
||||
doubanUrl = `https://movie.douban.com/j/search_subjects?type=tv&tag=美剧&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.hotCartonMoviePageStart}`
|
||||
this.douban.hotCartonMoviePageStart = this.douban.hotCartonMoviePageStart + this.douban.page_limit
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门英剧') {
|
||||
doubanUrl = `https://movie.douban.com/j/search_subjects?type=tv&tag=英剧&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.hotBritishTVSeriesPageStart}`
|
||||
this.douban.hotBritishTVSeriesPageStart = this.douban.hotBritishTVSeriesPageStart + this.douban.page_limit
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门国产剧') {
|
||||
doubanUrl = `https://movie.douban.com/j/search_subjects?type=tv&tag=国产剧&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.hotChineseTVSeriesPageStart}`
|
||||
this.douban.hotChineseTVSeriesPageStart = this.douban.hotChineseTVSeriesPageStart + this.douban.page_limit
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣高分电影') {
|
||||
doubanUrl = `https://movie.douban.com/j/search_subjects?type=movie&tag=豆瓣高分&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.highRateMoviePageStart}`
|
||||
this.douban.highRateMoviePageStart = this.douban.highRateMoviePageStart + this.douban.page_limit
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门动漫') {
|
||||
doubanUrl = `https://movie.douban.com/j/search_subjects?type=tv&tag=日本动画&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.hotAnimePageStart}`
|
||||
this.douban.hotAnimePageStart = this.douban.hotAnimePageStart + this.douban.page_limit
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门纪录片') {
|
||||
doubanUrl = `https://movie.douban.com/j/search_subjects?type=tv&tag=纪录片&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.hotDocumentaryPageStart}`
|
||||
this.douban.hotDocumentaryPageStart = this.douban.hotDocumentaryPageStart + this.douban.page_limit
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门综艺') {
|
||||
doubanUrl = `https://movie.douban.com/j/search_subjects?type=tv&tag=综艺&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.hotTVShowPageStart}`
|
||||
this.douban.hotTVShowPageStart = this.douban.hotTVShowPageStart + this.douban.page_limit
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣热门动画电影') {
|
||||
doubanUrl = `https://movie.douban.com/j/search_subjects?type=movie&tag=动画&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.hotCartonMoviePageStart}`
|
||||
this.douban.hotCartonMoviePageStart = this.douban.hotCartonMoviePageStart + this.douban.page_limit
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣冷门佳片') {
|
||||
doubanUrl = `https://movie.douban.com/j/search_subjects?type=movie&tag=冷门佳片&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.goodButNotHotMoviesPageStart}`
|
||||
this.douban.goodButNotHotMoviesPageStart = this.douban.goodButNotHotMoviesPageStart + this.douban.page_limit
|
||||
}
|
||||
if (this.selectedRecommendationType === '豆瓣华语电影') {
|
||||
doubanUrl = `https://movie.douban.com/j/search_subjects?type=movie&tag=华语&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.chineseMoviesPageStart}`
|
||||
this.douban.chineseMoviesPageStart = this.douban.chineseMoviesPageStart + this.douban.page_limit
|
||||
}
|
||||
this.getRecommendationsDoubanMovieOrTV(doubanUrl)
|
||||
},
|
||||
toggleViewMode () {
|
||||
this.setting.recommendationViewMode = this.setting.recommendationViewMode === 'picture' ? 'table' : 'picture'
|
||||
if (this.setting.recommendationViewMode === 'table') {
|
||||
@@ -259,7 +498,7 @@ export default {
|
||||
switch (this.sortKeyword) {
|
||||
case '按上映年份':
|
||||
filteredData.sort(function (a, b) {
|
||||
return a.detail.year - b.detail.year
|
||||
return b.detail.year - a.detail.year
|
||||
})
|
||||
break
|
||||
case '按片名':
|
||||
@@ -272,6 +511,11 @@ export default {
|
||||
return new Date(b.detail.last) - new Date(a.detail.last)
|
||||
})
|
||||
break
|
||||
case '按评分':
|
||||
filteredData.sort(function (a, b) {
|
||||
return b.rate - a.rate
|
||||
})
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
@@ -288,26 +532,6 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
updateEvent () {
|
||||
const url = 'https://raw.githubusercontent.com/cuiocean/ZY-Player-Resources/main/Recommendations/Recommendations.json'
|
||||
this.loading = true
|
||||
const axios = require('axios')
|
||||
axios.get(url).then(res => {
|
||||
if (res.status === 200) {
|
||||
if (res.data.length > 0) {
|
||||
this.recommendations = res.data
|
||||
recommendation.clear().then(recommendation.bulkAdd(this.recommendations))
|
||||
this.getFilterData()
|
||||
this.$message.success('更新推荐成功. 仅根据作者cuiocean个人喜好推荐,不喜请无视.')
|
||||
}
|
||||
}
|
||||
this.loading = false
|
||||
}).catch(error => {
|
||||
this.loading = false
|
||||
this.$message.error('更新推荐失败. ' + error)
|
||||
this.$message.warning('最新的推荐数据保存在Github上,请考虑使用代理或者等待下一版本内置数据更新.')
|
||||
})
|
||||
},
|
||||
async playEvent (e) {
|
||||
const db = await history.find({ site: e.key, ids: e.ids })
|
||||
if (db) {
|
||||
@@ -317,14 +541,6 @@ export default {
|
||||
}
|
||||
this.view = 'Play'
|
||||
},
|
||||
deleteEvent (e) {
|
||||
recommendation.remove(e.id).then(res => {
|
||||
if (res) {
|
||||
this.$message.warning('删除失败')
|
||||
}
|
||||
this.getRecommendations()
|
||||
})
|
||||
},
|
||||
shareEvent (e) {
|
||||
this.share = {
|
||||
show: true,
|
||||
@@ -344,12 +560,9 @@ export default {
|
||||
})
|
||||
},
|
||||
getRecommendations () {
|
||||
recommendation.all().then(res => {
|
||||
this.recommendations = res.sort(function (a, b) {
|
||||
return b.id - a.id
|
||||
})
|
||||
this.getFilterData()
|
||||
})
|
||||
this.recommendationsDefault = []
|
||||
this.changeRecommendationTypeEvent()
|
||||
this.getFilterData()
|
||||
},
|
||||
getFilterData () {
|
||||
this.types = [...new Set(this.recommendations.map(ele => ele.detail.type))].filter(x => x)
|
||||
@@ -361,10 +574,24 @@ export default {
|
||||
res.recommendationViewMode = this.setting.recommendationViewMode
|
||||
setting.update(res)
|
||||
})
|
||||
},
|
||||
getAllSites () {
|
||||
sites.all().then(res => {
|
||||
if (res.length > 0) {
|
||||
this.sites = res.filter(item => item.isActive)
|
||||
}
|
||||
})
|
||||
},
|
||||
getCachedMovies () {
|
||||
cachedMovies.all().then(res => {
|
||||
this.localCachedMovies = res
|
||||
})
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getAllSites()
|
||||
this.getRecommendations()
|
||||
this.getCachedMovies()
|
||||
},
|
||||
mounted () {
|
||||
addEventListener('resize', () => {
|
||||
|
||||
@@ -5,9 +5,7 @@
|
||||
<div class="info">
|
||||
<a @click="linkOpen('http://zyplayer.fun/')">官网</a>
|
||||
<a @click="linkOpen('https://github.com/Hunlongyu/ZY-Player')">Github</a>
|
||||
<a @click="linkOpen('https://github.com/Hunlongyu/ZY-Player/releases/tag/v' + pkg.version)">v{{pkg.version}}更新日志</a>
|
||||
<a @click="linkOpen('https://github.com/Hunlongyu/ZY-Player/issues/80')">常见问题</a>
|
||||
<a @click="linkOpen('https://github.com/Hunlongyu/ZY-Player/issues')">反馈建议</a>
|
||||
<a @click="linkOpen('https://github.com/Hunlongyu/ZY-Player/discussions/776')">软件完全免费,如遇收费,请立即给差评并退费!</a>
|
||||
<a style="color:#38dd77" @click="openUpdate()" v-show="update.find" >最新版本v{{update.version}}</a>
|
||||
</div>
|
||||
<div class="shortcut">
|
||||
@@ -93,9 +91,6 @@
|
||||
<div class="zy-select">
|
||||
<div class="vs-placeholder vs-noAfter" @click="show.configSitesDataUrlDialog = true">设置源站接口文件</div>
|
||||
</div>
|
||||
<div class="zy-input" @click="toggleExcludeRootClasses">
|
||||
<input type="checkbox" v-model = "d.excludeRootClasses" @change="updateSettingEvent"> 屏蔽主分类
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="site">
|
||||
@@ -113,6 +108,15 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="site">
|
||||
<div class="title">窗口及播放</div>
|
||||
<div class="site-box">
|
||||
<div class="zy-input">
|
||||
<input type="checkbox" v-model = "d.restoreWindowPositionAndSize" @change="updateSettingEvent"> 记录并恢复窗口位置和大小
|
||||
<input type="checkbox" v-model = "d.pauseWhenMinimize" @change="updateSettingEvent"> 最小化时暂停播放
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="theme">
|
||||
<div class="title">主题</div>
|
||||
<div class="theme-box">
|
||||
@@ -142,13 +146,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qrcode">
|
||||
<div class="title">请作者吃辣条</div>
|
||||
<div class="qrcode-box">
|
||||
<img class="qrcode-item" src="../assets/image/wepay-hunlongyu.png">
|
||||
<img class="qrcode-item" src="../assets/image/wepay_cuiocean.jpg">
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearDB">
|
||||
<span @click="clearDBEvent" class="clearBtn">软件重置</span>
|
||||
<span @click="changePasswordEvent" class="clearBtn">设置密码</span>
|
||||
@@ -167,7 +164,7 @@
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="closeDialog">取消</el-button>
|
||||
<el-button type="danger" @click="get7kParseURL">重置</el-button>
|
||||
<el-button type="danger" @click="resetDefaultParseURL">重置</el-button>
|
||||
<el-button type="primary" @click="configDefaultParseURL">确定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
@@ -181,7 +178,7 @@
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="closeDialog">取消</el-button>
|
||||
<el-button type="danger" @click="getDefaultdeSitesDataURL">重置</el-button>
|
||||
<el-button type="danger" @click="resetDefaultSitesDataURL">重置</el-button>
|
||||
<el-button type="primary" @click="configSitesDataURL">确定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
@@ -259,7 +256,8 @@ import { mapMutations } from 'vuex'
|
||||
import pkg from '../../package.json'
|
||||
import { setting, sites, shortcut } from '../lib/dexie'
|
||||
import { localKey as defaultShortcuts } from '../lib/dexie/initData'
|
||||
import { shell, clipboard, remote, ipcRenderer } from 'electron'
|
||||
import { shell, clipboard, ipcRenderer } from 'electron'
|
||||
const remote = require('@electron/remote')
|
||||
import db from '../lib/dexie/dexie'
|
||||
import zy from '../lib/site/tools'
|
||||
export default {
|
||||
@@ -328,12 +326,17 @@ export default {
|
||||
this.d = res
|
||||
this.setting = this.d
|
||||
if (!this.setting.defaultParseURL) this.configDefaultParseURL()
|
||||
if (!this.setting.sitesDataURL) this.getDefaultdeSitesDataURL()
|
||||
if (!this.setting.sitesDataURL) this.resetDefaultSitesDataURL()
|
||||
})
|
||||
},
|
||||
getDefaultSites () {
|
||||
zy.getDefaultSites(this.setting.sitesDataURL).then(res => {
|
||||
if (res.length > 0) {
|
||||
async getDefaultSites () {
|
||||
const s = await setting.find()
|
||||
zy.getDefaultSites(s.sitesDataURL).then(res => {
|
||||
if (res && typeof res === 'string') {
|
||||
const json = JSON.parse(res)
|
||||
sites.clear().then(sites.bulkAdd(json))
|
||||
}
|
||||
if (res && typeof res === 'object') {
|
||||
sites.clear().then(sites.bulkAdd(res))
|
||||
}
|
||||
}).catch(error => {
|
||||
@@ -374,25 +377,20 @@ export default {
|
||||
this.d.excludeRootClasses = !this.d.excludeRootClasses
|
||||
this.updateSettingEvent()
|
||||
},
|
||||
async get7kParseURL () {
|
||||
this.$message.info('正在获取7K源解析地址...')
|
||||
const parseURL = await zy.get7kParseURL()
|
||||
if (parseURL.startsWith('http')) {
|
||||
this.$message.success('获取成功,更新应用默认解析接口地址...')
|
||||
this.setting.defaultParseURL = parseURL
|
||||
}
|
||||
async resetDefaultParseURL () {
|
||||
this.setting.defaultParseURL = 'https://jx.bpba.cc/?v='
|
||||
},
|
||||
async configDefaultParseURL () {
|
||||
if (!this.setting.defaultParseURL) await this.get7kParseURL()
|
||||
if (!this.setting.defaultParseURL) await this.resetDefaultParseURL()
|
||||
this.d.defaultParseURL = this.setting.defaultParseURL?.trim()
|
||||
this.show.configDefaultParseUrlDialog = false
|
||||
this.updateSettingEvent()
|
||||
},
|
||||
getDefaultdeSitesDataURL () {
|
||||
this.setting.sitesDataURL = 'https://gitee.com/cuiocean/ZY-Player-Resources/raw/main/Sites/Sites.json'
|
||||
resetDefaultSitesDataURL () {
|
||||
this.setting.sitesDataURL = 'https://raw.iqiq.io/Hunlongyu/ZY-Player-Resources/main/Sites/20220713.json'
|
||||
},
|
||||
configSitesDataURL () {
|
||||
if (!this.setting.sitesDataURL) this.getDefaultdeSitesDataURL()
|
||||
if (!this.setting.sitesDataURL) this.resetDefaultSitesDataURL()
|
||||
this.d.sitesDataURL = this.setting.sitesDataURL
|
||||
this.show.configSitesDataUrlDialog = false
|
||||
this.updateSettingEvent()
|
||||
@@ -597,7 +595,7 @@ export default {
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getSites()
|
||||
// this.getSites()
|
||||
this.getSetting()
|
||||
this.getShortcut()
|
||||
this.checkUpdate()
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
<el-button @click.stop="exportFavoritesEvent" icon="el-icon-upload2" title="导出全部,自动添加扩展名">导出</el-button>
|
||||
<el-button @click.stop="importFavoritesEvent" icon="el-icon-download" title="支持同时导入多个文件">导入</el-button>
|
||||
<el-button @click.stop="removeSelectedItems" icon="el-icon-delete-solid">{{ multipleSelection.length === 0 ? "清空" : "删除所选" }}</el-button>
|
||||
<el-button @click.stop="updateAllEvent" icon="el-icon-refresh">检查更新</el-button>
|
||||
<b-button-group>
|
||||
<el-switch v-model="onlyShowItemsHasUpdate" active-text="有更新" inactive-text="全部" @change="refreshFilteredList"></el-switch>
|
||||
<el-button @click.stop="updateAllEvent" icon="el-icon-refresh">检查更新</el-button>
|
||||
</b-button-group>
|
||||
</div>
|
||||
<div class="toolbar" v-show="showToolbar">
|
||||
<el-switch v-model="onlyShowItemsHasUpdate" active-text="有更新" inactive-text="全部" @change="refreshFilteredList"></el-switch>
|
||||
<el-select v-model="selectedAreas" size="small" multiple placeholder="地区" popper-class="popper" :popper-append-to-body="false" @remove-tag="refreshFilteredList" @change="refreshFilteredList">
|
||||
<el-option
|
||||
v-for="item in areas"
|
||||
@@ -177,7 +179,7 @@
|
||||
import { mapMutations } from 'vuex'
|
||||
import { history, star, sites, setting } from '../lib/dexie'
|
||||
import zy from '../lib/site/tools'
|
||||
import { remote } from 'electron'
|
||||
const remote = require('@electron/remote')
|
||||
import fs from 'fs'
|
||||
import Sortable from 'sortablejs'
|
||||
import Waterfall from 'vue-waterfall-plugin'
|
||||
@@ -322,7 +324,7 @@ export default {
|
||||
switch (this.sortKeyword) {
|
||||
case '按上映年份':
|
||||
filteredData.sort(function (a, b) {
|
||||
return a.detail.year - b.detail.year
|
||||
return b.detail.year - a.detail.year
|
||||
})
|
||||
break
|
||||
case '按片名':
|
||||
|
||||
@@ -10,7 +10,7 @@ import Share from './Share'
|
||||
import History from './History'
|
||||
import EditSites from './EditSites'
|
||||
import IPTV from './IPTV'
|
||||
import Recommendation from './Recommendation'
|
||||
// import Recommendation from './Recommendation'
|
||||
export default {
|
||||
registerComponents () {
|
||||
Vue.component('Aside', Aside)
|
||||
@@ -24,6 +24,6 @@ export default {
|
||||
Vue.component('History', History)
|
||||
Vue.component('EditSites', EditSites)
|
||||
Vue.component('IPTV', IPTV)
|
||||
Vue.component('Recommendation', Recommendation)
|
||||
// Vue.component('Recommendation', Recommendation)
|
||||
}
|
||||
}
|
||||
|
||||
28
src/lib/dexie/cachedMovies.js
Normal file
28
src/lib/dexie/cachedMovies.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import db from './dexie'
|
||||
const { cachedMovies } = db
|
||||
export default {
|
||||
async add (doc) {
|
||||
return await cachedMovies.add(doc)
|
||||
},
|
||||
async bulkAdd (doc) {
|
||||
return await cachedMovies.bulkAdd(doc)
|
||||
},
|
||||
async find (doc) {
|
||||
return await cachedMovies.where(doc).first()
|
||||
},
|
||||
async update (id, docs) {
|
||||
return await cachedMovies.update(id, docs)
|
||||
},
|
||||
async all () {
|
||||
return await cachedMovies.toArray()
|
||||
},
|
||||
async remove (id) {
|
||||
return await cachedMovies.delete(id)
|
||||
},
|
||||
async get (id) {
|
||||
return await cachedMovies.get(id)
|
||||
},
|
||||
async clear () {
|
||||
return await cachedMovies.clear()
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
import Dexie from 'dexie'
|
||||
import { setting, sites, localKey, iptv, recommendations } from './initData'
|
||||
import { sites, localKey, iptv, recommendations, iniSetting } from './initData'
|
||||
|
||||
const db = new Dexie('zy')
|
||||
|
||||
db.version(4).stores({
|
||||
search: '++id, keywords',
|
||||
setting: 'id, theme, site, shortcut, view, volume, externalPlayer, searchGroup, excludeRootClasses, excludeR18Films, forwardTimeInSec, starViewMode, recommandationViewMode, searchViewMode, password, proxy, allowPassWhenIptvCheck, autocleanWhenIptvCheck',
|
||||
@@ -63,8 +62,55 @@ db.version(9).stores({
|
||||
history: '++id, [site+ids], name, type, year, index, time, duration, detail, onlinePlay, hasUpdate'
|
||||
})
|
||||
|
||||
db.version(10).stores({
|
||||
setting: 'id, theme, shortcut, view, volume, externalPlayer, searchGroup, excludeRootClasses, excludeR18Films, forwardTimeInSec, starViewMode, recommandationViewMode, searchViewMode, password, proxy, allowPassWhenIptvCheck, autocleanWhenIptvCheck, rootClassFilter, r18ClassFilter, classFilter'
|
||||
}).upgrade(trans => {
|
||||
trans.setting.toCollection().modify(setting => {
|
||||
delete setting.site
|
||||
setting.rootClassFilter = ['电影', '电影片', '电视剧', '连续剧', '综艺', '动漫']
|
||||
setting.r18ClassFilter = ['伦理', '论理', '倫理', '福利', '激情', '理论', '写真', '情色', '美女', '街拍', '赤足', '性感', '里番', 'VIP']
|
||||
setting.classFilter = ['电影', '电影片', '电视剧', '连续剧', '综艺', '动漫', '伦理', '论理', '倫理', '福利', '激情', '理论', '写真', '情色', '美女', '街拍', '赤足', '性感', '里番', 'VIP']
|
||||
})
|
||||
})
|
||||
|
||||
db.version(11).stores({
|
||||
setting: 'id, theme, shortcut, view, volume, externalPlayer, searchGroup, excludeRootClasses, excludeR18Films, forwardTimeInSec, starViewMode, recommandationViewMode,' +
|
||||
'searchViewMode, password, proxy, allowPassWhenIptvCheck, autocleanWhenIptvCheck, rootClassFilter, r18ClassFilter, classFilter, restoreWindowPositionAndSize, windowPositionAndSize, pauseWhenMinimize',
|
||||
cachedMovies: '++id, [key+ids], site, name, detail, index, rate, hasUpdate'
|
||||
}).upgrade(trans => {
|
||||
trans.setting.toCollection().modify(setting => {
|
||||
setting.restoreWindowPositionAndSize = false
|
||||
setting.windowPositionAndSize = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 1080,
|
||||
height: 720
|
||||
}
|
||||
setting.pauseWhenMinimize = false
|
||||
})
|
||||
})
|
||||
|
||||
db.version(11).stores({
|
||||
setting: 'id, theme, shortcut, view, volume, externalPlayer, searchGroup, excludeRootClasses, excludeR18Films, forwardTimeInSec, starViewMode, recommandationViewMode,' +
|
||||
'searchViewMode, password, proxy, allowPassWhenIptvCheck, autocleanWhenIptvCheck, rootClassFilter, r18ClassFilter, classFilter, restoreWindowPositionAndSize,' +
|
||||
'windowPositionAndSize, pauseWhenMinimize, sitesDataURL, defaultParseURL'
|
||||
}).upgrade(trans => {
|
||||
trans.setting.toCollection().modify(setting => {
|
||||
setting.sitesDataURL = 'https://raw.iqiq.io/Hunlongyu/ZY-Player-Resources/main/Sites/20220713.json'
|
||||
setting.defaultParseURL = 'https://jx.bpba.cc/?v='
|
||||
})
|
||||
})
|
||||
|
||||
db.version(12).stores({
|
||||
sites: '++id, key, name, api, download, jiexiUrl, isActive, group, reverseOrder'
|
||||
}).upgrade(trans => {
|
||||
trans.sites.toCollection().modify(site => {
|
||||
site.reverseOrder = false
|
||||
})
|
||||
})
|
||||
|
||||
db.on('populate', () => {
|
||||
db.setting.bulkAdd(setting)
|
||||
db.setting.bulkAdd(iniSetting)
|
||||
db.sites.bulkAdd(sites)
|
||||
db.shortcut.bulkAdd(localKey)
|
||||
db.iptv.bulkAdd(iptv)
|
||||
|
||||
@@ -8,6 +8,7 @@ import search from './search'
|
||||
import iptv from './iptv'
|
||||
import channelList from './channelList'
|
||||
import recommendation from './recommendation'
|
||||
import cachedMovies from './cachedMovies'
|
||||
|
||||
export {
|
||||
history,
|
||||
@@ -19,5 +20,6 @@ export {
|
||||
iptv,
|
||||
channelList,
|
||||
search,
|
||||
recommendation
|
||||
recommendation,
|
||||
cachedMovies
|
||||
}
|
||||
|
||||
82
src/lib/dexie/iniData/iniSetting.json
Normal file
82
src/lib/dexie/iniData/iniSetting.json
Normal file
@@ -0,0 +1,82 @@
|
||||
[{
|
||||
"id": 0,
|
||||
"theme": "light",
|
||||
"shortcut": true,
|
||||
"view": "picture",
|
||||
"externalPlayer": "",
|
||||
"searchGroup": "全站",
|
||||
"excludeRootClasses": true,
|
||||
"excludeR18Films": true,
|
||||
"forwardTimeInSec": 5,
|
||||
"waitingTimeInSec": 15,
|
||||
"starViewMode": "picture",
|
||||
"recommendationViewMode": "picture",
|
||||
"historyViewMode": "picture",
|
||||
"searchViewMode": "picture",
|
||||
"password": "",
|
||||
"proxy": {
|
||||
"type": "none",
|
||||
"scheme": "",
|
||||
"url": "",
|
||||
"port": ""
|
||||
},
|
||||
"allowPassWhenIptvCheck": true,
|
||||
"autocleanWhenIptvCheck": false,
|
||||
"autoChangeSourceWhenIptvStalling": true,
|
||||
"shortcutModified": false,
|
||||
"sitesDataURL": "https://raw.iqiq.io/Hunlongyu/ZY-Player-Resources/main/Sites/20220713.json",
|
||||
"rootClassFilter": [
|
||||
"电影",
|
||||
"电影片",
|
||||
"电视剧",
|
||||
"连续剧",
|
||||
"综艺",
|
||||
"动漫"
|
||||
],
|
||||
"r18ClassFilter": [
|
||||
"伦理",
|
||||
"论理",
|
||||
"倫理",
|
||||
"福利",
|
||||
"激情",
|
||||
"理论",
|
||||
"写真",
|
||||
"情色",
|
||||
"美女",
|
||||
"街拍",
|
||||
"赤足",
|
||||
"性感",
|
||||
"里番",
|
||||
"VIP"
|
||||
],
|
||||
"classFilter": [
|
||||
"电影",
|
||||
"电影片",
|
||||
"电视剧",
|
||||
"连续剧",
|
||||
"综艺",
|
||||
"动漫",
|
||||
"伦理",
|
||||
"论理",
|
||||
"倫理",
|
||||
"福利",
|
||||
"激情",
|
||||
"理论",
|
||||
"写真",
|
||||
"情色",
|
||||
"美女",
|
||||
"街拍",
|
||||
"赤足",
|
||||
"性感",
|
||||
"里番",
|
||||
"VIP"
|
||||
],
|
||||
"restoreWindowPositionAndSize": false,
|
||||
"windowPositionAndSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 1080,
|
||||
"height": 720
|
||||
},
|
||||
"pauseWhenMinimize": false
|
||||
}]
|
||||
112
src/lib/dexie/iniData/localKey.json
Normal file
112
src/lib/dexie/iniData/localKey.json
Normal file
@@ -0,0 +1,112 @@
|
||||
[
|
||||
{
|
||||
"name": "playAndPause",
|
||||
"desc": "播放或暂停",
|
||||
"key": "space"
|
||||
},
|
||||
{
|
||||
"name": "forward",
|
||||
"desc": "快进",
|
||||
"key": "right"
|
||||
},
|
||||
{
|
||||
"name": "back",
|
||||
"desc": "快退",
|
||||
"key": "left"
|
||||
},
|
||||
{
|
||||
"name": "volumeUp",
|
||||
"desc": "音量调高",
|
||||
"key": "up"
|
||||
},
|
||||
{
|
||||
"name": "volumeDown",
|
||||
"desc": "音量调低",
|
||||
"key": "down"
|
||||
},
|
||||
{
|
||||
"name": "mute",
|
||||
"desc": "静音",
|
||||
"key": "m"
|
||||
},
|
||||
{
|
||||
"name": "top",
|
||||
"desc": "置顶或退出置顶",
|
||||
"key": "t"
|
||||
},
|
||||
{
|
||||
"name": "fullscreen",
|
||||
"desc": "进入或退出全屏",
|
||||
"key": "f"
|
||||
},
|
||||
{
|
||||
"name": "escape",
|
||||
"desc": "退出全屏/精简模式",
|
||||
"key": "esc"
|
||||
},
|
||||
{
|
||||
"name": "next",
|
||||
"desc": "下一集",
|
||||
"key": "alt+right"
|
||||
},
|
||||
{
|
||||
"name": "prev",
|
||||
"desc": "上一集",
|
||||
"key": "alt+left"
|
||||
},
|
||||
{
|
||||
"name": "home",
|
||||
"desc": "跳到视频开始位置",
|
||||
"key": "home"
|
||||
},
|
||||
{
|
||||
"name": "end",
|
||||
"desc": "跳到视频结束位置",
|
||||
"key": "end"
|
||||
},
|
||||
{
|
||||
"name": "startPosition",
|
||||
"desc": "标记片头",
|
||||
"key": "ctrl+home"
|
||||
},
|
||||
{
|
||||
"name": "endPosition",
|
||||
"desc": "标记片尾",
|
||||
"key": "ctrl+end"
|
||||
},
|
||||
{
|
||||
"name": "clearPosition",
|
||||
"desc": "清除标记",
|
||||
"key": "ctrl+del"
|
||||
},
|
||||
{
|
||||
"name": "opacityUp",
|
||||
"desc": "透明度调高",
|
||||
"key": "alt+up"
|
||||
},
|
||||
{
|
||||
"name": "opacityDown",
|
||||
"desc": "透明度调低",
|
||||
"key": "alt+down"
|
||||
},
|
||||
{
|
||||
"name": "playbackRateUp",
|
||||
"desc": "播放倍速加快",
|
||||
"key": "pageup"
|
||||
},
|
||||
{
|
||||
"name": "playbackRateDown",
|
||||
"desc": "播放倍速减慢",
|
||||
"key": "pagedown"
|
||||
},
|
||||
{
|
||||
"name": "mini",
|
||||
"desc": "进入或退出mini模式",
|
||||
"key": "alt+m"
|
||||
},
|
||||
{
|
||||
"name": "resetMini",
|
||||
"desc": "重置mini窗口",
|
||||
"key": "ctrl+0"
|
||||
}
|
||||
]
|
||||
@@ -1,145 +1,3 @@
|
||||
const setting = [
|
||||
{
|
||||
id: 0,
|
||||
theme: 'light',
|
||||
shortcut: true,
|
||||
view: 'picture',
|
||||
externalPlayer: '',
|
||||
searchGroup: '全站',
|
||||
excludeRootClasses: true,
|
||||
excludeR18Films: true,
|
||||
forwardTimeInSec: 5,
|
||||
waitingTimeInSec: 15,
|
||||
starViewMode: 'picture',
|
||||
recommendationViewMode: 'picture',
|
||||
historyViewMode: 'picture',
|
||||
searchViewMode: 'picture',
|
||||
password: '',
|
||||
proxy: {
|
||||
type: 'none',
|
||||
scheme: '',
|
||||
url: '',
|
||||
port: ''
|
||||
},
|
||||
allowPassWhenIptvCheck: true,
|
||||
autocleanWhenIptvCheck: false,
|
||||
autoChangeSourceWhenIptvStalling: true
|
||||
}
|
||||
]
|
||||
|
||||
const localKey = [
|
||||
{
|
||||
name: 'playAndPause',
|
||||
desc: '播放或暂停',
|
||||
key: 'space'
|
||||
},
|
||||
{
|
||||
name: 'forward',
|
||||
desc: '快进',
|
||||
key: 'right'
|
||||
},
|
||||
{
|
||||
name: 'back',
|
||||
desc: '快退',
|
||||
key: 'left'
|
||||
},
|
||||
{
|
||||
name: 'volumeUp',
|
||||
desc: '音量调高',
|
||||
key: 'up'
|
||||
},
|
||||
{
|
||||
name: 'volumeDown',
|
||||
desc: '音量调低',
|
||||
key: 'down'
|
||||
},
|
||||
{
|
||||
name: 'mute',
|
||||
desc: '静音',
|
||||
key: 'm'
|
||||
},
|
||||
{
|
||||
name: 'top',
|
||||
desc: '置顶或退出置顶',
|
||||
key: 't'
|
||||
},
|
||||
{
|
||||
name: 'fullscreen',
|
||||
desc: '进入或退出全屏',
|
||||
key: 'f'
|
||||
},
|
||||
{
|
||||
name: 'escape',
|
||||
desc: '退出全屏/精简模式',
|
||||
key: 'esc'
|
||||
},
|
||||
{
|
||||
name: 'next',
|
||||
desc: '下一集',
|
||||
key: 'alt+right'
|
||||
},
|
||||
{
|
||||
name: 'prev',
|
||||
desc: '上一集',
|
||||
key: 'alt+left'
|
||||
},
|
||||
{
|
||||
name: 'home',
|
||||
desc: '跳到视频开始位置',
|
||||
key: 'home'
|
||||
},
|
||||
{
|
||||
name: 'end',
|
||||
desc: '跳到视频结束位置',
|
||||
key: 'end'
|
||||
},
|
||||
{
|
||||
name: 'startPosition',
|
||||
desc: '标记片头',
|
||||
key: 'ctrl+home'
|
||||
},
|
||||
{
|
||||
name: 'endPosition',
|
||||
desc: '标记片尾',
|
||||
key: 'ctrl+end'
|
||||
},
|
||||
{
|
||||
name: 'clearPosition',
|
||||
desc: '清除标记',
|
||||
key: 'ctrl+del'
|
||||
},
|
||||
{
|
||||
name: 'opacityUp',
|
||||
desc: '透明度调高',
|
||||
key: 'alt+up'
|
||||
},
|
||||
{
|
||||
name: 'opacityDown',
|
||||
desc: '透明度调低',
|
||||
key: 'alt+down'
|
||||
},
|
||||
{
|
||||
name: 'playbackRateUp',
|
||||
desc: '播放倍速加快',
|
||||
key: 'pageup'
|
||||
},
|
||||
{
|
||||
name: 'playbackRateDown',
|
||||
desc: '播放倍速减慢',
|
||||
key: 'pagedown'
|
||||
},
|
||||
{
|
||||
name: 'mini',
|
||||
desc: '进入或退出mini模式',
|
||||
key: 'alt+m'
|
||||
},
|
||||
{
|
||||
name: 'resetMini',
|
||||
desc: '重置mini窗口',
|
||||
key: 'ctrl+0'
|
||||
}
|
||||
]
|
||||
|
||||
const getSite = (key) => {
|
||||
for (const i of sites) {
|
||||
if (key === i.key) {
|
||||
@@ -151,11 +9,13 @@ const getSite = (key) => {
|
||||
const sites = require('./iniData/Sites.json')
|
||||
const iptv = require('./iniData/Iptv.json')
|
||||
const recommendations = require('./iniData/Recommendations.json')
|
||||
const iniSetting = require('./iniData/iniSetting.json')
|
||||
const localKey = require('./iniData/localKey.json')
|
||||
export {
|
||||
setting,
|
||||
sites,
|
||||
iptv,
|
||||
recommendations,
|
||||
iniSetting,
|
||||
localKey,
|
||||
getSite
|
||||
}
|
||||
|
||||
@@ -5,6 +5,12 @@ export default {
|
||||
async find () {
|
||||
return await setting.get({ id: 0 })
|
||||
},
|
||||
async bulkAdd (doc) {
|
||||
return await setting.bulkAdd(doc)
|
||||
},
|
||||
async add (doc) {
|
||||
return await setting.add(doc)
|
||||
},
|
||||
async update (docs) {
|
||||
return await setting.update(0, docs)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import Vue from 'vue'
|
||||
import { Message, Button, Table, TableColumn, Tag, Input, InputNumber, Dialog, Form, FormItem, Switch, Select, Option, Checkbox, Autocomplete, Col, Tree, Divider, Progress, MessageBox } from 'element-ui'
|
||||
import Plugin from 'v-fit-columns'
|
||||
import { ButtonGroupPlugin } from 'bootstrap-vue'
|
||||
Vue.use(ButtonGroupPlugin)
|
||||
Vue.use(Button)
|
||||
Vue.use(Col)
|
||||
Vue.use(Table)
|
||||
|
||||
@@ -11,7 +11,7 @@ import SocksProxyAgent from 'socks-proxy-agent'
|
||||
// 要在设置中添加代理设置,可参考https://stackoverflow.com/questions/37393248/how-connect-to-proxy-in-electron-webview
|
||||
const http = require('http')
|
||||
const https = require('http')
|
||||
const { remote } = require('electron')
|
||||
const remote = require('@electron/remote')
|
||||
const win = remote.getCurrentWindow()
|
||||
const session = win.webContents.session
|
||||
const ElectronProxyAgent = require('electron-proxy-agent')
|
||||
@@ -111,13 +111,16 @@ const zy = {
|
||||
axios.get(url).then(res => {
|
||||
const data = res.data
|
||||
const json = parser.parse(data, this.xmlConfig)
|
||||
const jsondata = json.rss === undefined ? json : json.rss
|
||||
const jsondata = json?.rss === undefined ? json : json.rss
|
||||
if (!jsondata?.class || !jsondata?.list) resolve()
|
||||
const arr = []
|
||||
if (jsondata.class) {
|
||||
// 有些网站返回的分类名里会含有一串包含在{}内的字符串,移除掉
|
||||
const regex = /\{.*\}/i
|
||||
for (const i of jsondata.class.ty) {
|
||||
const j = {
|
||||
tid: i._id,
|
||||
name: i._t
|
||||
name: i._t.replace(regex, '')
|
||||
}
|
||||
arr.push(j)
|
||||
}
|
||||
@@ -216,16 +219,55 @@ const zy = {
|
||||
axios.get(url, { timeout: 3000 }).then(res => {
|
||||
const data = res.data
|
||||
const json = parser.parse(data, this.xmlConfig)
|
||||
const jsondata = json.rss === undefined ? json : json.rss
|
||||
const jsondata = json?.rss === undefined ? json : json.rss
|
||||
if (json && jsondata && jsondata.list) {
|
||||
let videoList = jsondata.list.video
|
||||
if (Object.prototype.toString.call(videoList) === '[object Object]') videoList = [].concat(videoList)
|
||||
videoList = videoList.filter(e => e.name.toLowerCase().includes(wd.toLowerCase()))
|
||||
if (videoList.length) {
|
||||
videoList = videoList?.filter(e => e.name.toLowerCase().includes(wd.toLowerCase()))
|
||||
if (videoList?.length) {
|
||||
resolve(videoList)
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 搜索资源详情
|
||||
* @param {*} key 资源网 key
|
||||
* @param {*} wd 搜索关键字
|
||||
* @returns
|
||||
*/
|
||||
searchFirstDetail (key, wd) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.getSite(key).then(res => {
|
||||
const site = res
|
||||
const url = `${site.api}?wd=${encodeURI(wd)}`
|
||||
axios.get(url, { timeout: 3000 }).then(res => {
|
||||
const data = res.data
|
||||
const json = parser.parse(data, this.xmlConfig)
|
||||
const jsondata = json?.rss === undefined ? json : json.rss
|
||||
if (json && jsondata && jsondata.list) {
|
||||
let videoList = jsondata.list.video
|
||||
if (Object.prototype.toString.call(videoList) === '[object Object]') videoList = [].concat(videoList)
|
||||
videoList = videoList?.filter(e => e.name.toLowerCase().includes(wd.toLowerCase()))
|
||||
if (videoList?.length) {
|
||||
this.detail(key, videoList[0].id).then(detailRes => {
|
||||
resolve(detailRes)
|
||||
})
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
@@ -248,8 +290,9 @@ const zy = {
|
||||
axios.get(url).then(res => {
|
||||
const data = res.data
|
||||
const json = parser.parse(data, this.xmlConfig)
|
||||
const jsondata = json.rss === undefined ? json : json.rss
|
||||
const videoList = jsondata.list.video
|
||||
const jsondata = json?.rss === undefined ? json : json.rss
|
||||
const videoList = jsondata?.list?.video
|
||||
if (!videoList) resolve()
|
||||
// Parse video lists
|
||||
let fullList = []
|
||||
let index = 0
|
||||
@@ -491,17 +534,36 @@ const zy = {
|
||||
})
|
||||
})
|
||||
},
|
||||
get7kParseURL () {
|
||||
/**
|
||||
* 获取豆瓣相关视频推荐列表
|
||||
* @param {*} name 视频名称
|
||||
* @param {*} year 视频年份
|
||||
* @returns 豆瓣相关视频推荐列表
|
||||
*/
|
||||
doubanRecommendations (name, year) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios.get('https://zy.7kjx.com/').then(res => {
|
||||
const $ = cheerio.load(res.data)
|
||||
const parseURL = $('body > div.container > div > div.stui-pannel > div.col-pd > p:contains("解析接口:")').first().find('a').text()
|
||||
resolve(parseURL)
|
||||
}).catch(err => { reject(err) })
|
||||
const nameToSearch = name.replace(/\s/g, '')
|
||||
const recommendations = []
|
||||
this.doubanLink(nameToSearch, year).then(link => {
|
||||
if (link.includes('https://www.douban.com/search')) {
|
||||
resolve(recommendations)
|
||||
} else {
|
||||
axios.get(link).then(response => {
|
||||
const $ = cheerio.load(response.data)
|
||||
$('div.recommendations-bd').find('div>dl>dd>a').each(function (index, element) {
|
||||
recommendations.push($(element).text())
|
||||
})
|
||||
resolve(recommendations)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
}
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
getDefaultSites () {
|
||||
const url = 'https://gitee.com/cuiocean/ZY-Player-Resources/raw/main/Sites/Sites.json'
|
||||
getDefaultSites (url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios.get(url).then(res => {
|
||||
resolve(res.data)
|
||||
|
||||
Reference in New Issue
Block a user