Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d9122fd24e | ||
|
|
a746de8294 | ||
|
|
f56b81ab9b | ||
|
|
be784c9d60 | ||
|
|
fd715b7cfe | ||
|
|
6979d14f35 | ||
|
|
be6b4b0d78 | ||
|
|
90b466e958 | ||
|
|
4b6485a922 | ||
|
|
7e4f1f9127 | ||
|
|
f8c351aa1e | ||
|
|
65fc90819a | ||
|
|
cf634b55d7 | ||
|
|
b6acaf83e0 | ||
|
|
f21d0a6963 | ||
|
|
367bd0ebd7 | ||
|
|
8f89c3db4d | ||
|
|
c8881bec3b | ||
|
|
888e2e838a | ||
|
|
7540cee532 | ||
|
|
98a682ab82 | ||
|
|
4a6069c60f | ||
|
|
cd91bffa05 | ||
|
|
d3083a6eb6 | ||
|
|
6ba19f6f6b | ||
|
|
66a91a746f | ||
|
|
b8cd7cc30c | ||
|
|
02c5cc0f1d | ||
|
|
dba13326cd | ||
|
|
14eed868c1 | ||
|
|
f9ff6bbde9 | ||
|
|
b208dfc3b6 | ||
|
|
23d221979e | ||
|
|
b36b6bd9e4 | ||
|
|
4c8b3ae36b | ||
|
|
58f1ecdb57 | ||
|
|
b5a9d4482b | ||
|
|
8c05489b06 | ||
|
|
bf0ccef8ba | ||
|
|
0161e2ee1d | ||
|
|
9df844dbe8 | ||
|
|
e723fe0cf1 | ||
|
|
3d94ab2f6c | ||
|
|
dabf4390bd | ||
|
|
93c7392754 | ||
|
|
426bb05e1c | ||
|
|
c9f30ce42f | ||
|
|
e126beb59c | ||
|
|
851d4a7ce7 | ||
|
|
d1dd9491da | ||
|
|
36e1372f51 | ||
|
|
f05a361265 | ||
|
|
4a01550ad6 | ||
|
|
b09954ca7c | ||
|
|
ec6bc18fbf | ||
|
|
2bdaf70be1 | ||
|
|
f0ad01fe5a | ||
|
|
e9f172d1b1 | ||
|
|
6e2e8e457e | ||
|
|
87760286db | ||
|
|
d9207d6429 | ||
|
|
0e9acb2bab | ||
|
|
6fa2c1f1cc |
@@ -5,13 +5,14 @@ module.exports = {
|
||||
},
|
||||
'extends': [
|
||||
'plugin:vue/essential',
|
||||
'@vue/standard'
|
||||
'@vue/standard',
|
||||
'@vue/typescript'
|
||||
],
|
||||
rules: {
|
||||
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
|
||||
},
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint'
|
||||
parser: '@typescript-eslint/parser'
|
||||
}
|
||||
}
|
||||
|
||||
29
AppVeyor.yml
@@ -1,29 +0,0 @@
|
||||
version: 0.1.{build}
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
image: Visual Studio 2017
|
||||
platform:
|
||||
- x64
|
||||
|
||||
cache:
|
||||
- node_modules
|
||||
- '%APPDATA%\npm-cache'
|
||||
- '%USERPROFILE%\.electron'
|
||||
- '%USERPROFILE%\AppData\Local\Yarn\cache'
|
||||
|
||||
init:
|
||||
- git config --global core.autocrlf input
|
||||
|
||||
install:
|
||||
- ps: Install-Product node 8 x64
|
||||
- git reset --hard HEAD
|
||||
- yarn
|
||||
- node --version
|
||||
|
||||
build_script:
|
||||
- yarn run release
|
||||
|
||||
test: off
|
||||
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Hunlongyu
|
||||
Copyright (c) 2020 Hunlongyu
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
76
README.md
@@ -1,49 +1,45 @@
|
||||
# ZY-Player
|
||||
<p align="center">
|
||||
<img src="https://i.loli.net/2020/01/20/WEj3Yw8rPXqTcHe.png" >
|
||||
</p>
|
||||
<p align="center">
|
||||
<img src="https://forthebadge.com/images/badges/built-with-love.svg">
|
||||
<img src="https://forthebadge.com/images/badges/made-with-vue.svg">
|
||||
<p>
|
||||
<p align="center">
|
||||
<img alt="GitHub" src="https://img.shields.io/github/license/Hunlongyu/ZY-Player?style=for-the-badge">
|
||||
<img alt="GitHub All Releases" src="https://img.shields.io/github/downloads/Hunlongyu/ZY-Player/total?style=for-the-badge">
|
||||
<img alt="GitHub release (latest by date including pre-releases)" src="https://img.shields.io/github/v/release/Hunlongyu/ZY-Player?include_prereleases&style=for-the-badge">
|
||||
<p>
|
||||
|
||||
资源播放器, 提供影视资源的搜索,查看,播放,搜藏等功能.
|
||||
# ZY Player
|
||||
资源播放器, 提供影视资源的浏览,搜索,播放,收藏,查看详情等功能.
|
||||
|
||||
### 下载:
|
||||
[下载地址](https://github.com/Hunlongyu/ZY-Player/releases)
|
||||
|
||||
### 截图:
|
||||

|
||||
主界面 ⬆
|
||||

|
||||
搜索 ⬆
|
||||

|
||||
详情 ⬆
|
||||

|
||||
播放 ⬆
|
||||

|
||||
搜藏 ⬆
|
||||
主界面 ⬇
|
||||

|
||||
暗黑主题 ⬇
|
||||

|
||||
搜索 ⬇
|
||||

|
||||
搜索结果 ⬇
|
||||

|
||||
详情 ⬇
|
||||

|
||||
播放 ⬇
|
||||

|
||||
收藏 ⬇
|
||||

|
||||
|
||||
### 下载地址:
|
||||
|
||||
蓝奏云: https://www.lanzous.com/i8jnk9e
|
||||
### 开发计划:
|
||||
[第二期开发计划](https://github.com/Hunlongyu/ZY-Player/projects/2)
|
||||
|
||||
### 未完成:
|
||||
1. 主题: 暗黑主题
|
||||
2. 更新: 自动更新以及手动更新
|
||||
1. 更换图标: 求大神设计一个 zy 的logo, 256x256 像素,风格请参考:
|
||||
|
||||

|
||||
|
||||
### 重要:
|
||||
所有资源来自网上, 该软件不参与任何制作, 上传, 储存, 下载等内容. 该软件仅供学习参考, 请于安装后24小时内删除.
|
||||
|
||||
## Project setup
|
||||
```
|
||||
yarn install
|
||||
```
|
||||
|
||||
### Compiles and hot-reloads for development
|
||||
```
|
||||
yarn serve
|
||||
```
|
||||
|
||||
### Compiles and minifies for production
|
||||
```
|
||||
yarn build
|
||||
```
|
||||
|
||||
### Lints and fixes files
|
||||
```
|
||||
yarn lint
|
||||
```
|
||||
|
||||
### Customize configuration
|
||||
See [Configuration Reference](https://cli.vuejs.org/config/).
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/app'
|
||||
'presets': [
|
||||
'@vue/cli-plugin-babel/preset'
|
||||
],
|
||||
plugins: [['import', {
|
||||
'libraryName': 'view-design',
|
||||
'libraryDirectory': 'src/components'
|
||||
}]]
|
||||
'plugins': [
|
||||
[
|
||||
'component',
|
||||
{
|
||||
'libraryName': 'element-ui',
|
||||
'styleLibraryName': 'theme-chalk'
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
BIN
build/icons/1024x1024.png
Normal file
|
After Width: | Height: | Size: 93 KiB |
BIN
build/icons/128x128.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
build/icons/16x16.png
Normal file
|
After Width: | Height: | Size: 497 B |
BIN
build/icons/24x24.png
Normal file
|
After Width: | Height: | Size: 891 B |
BIN
build/icons/256x256.png
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
build/icons/32x32.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
build/icons/48x48.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
build/icons/512x512.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
build/icons/64x64.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
build/icons/icon.icns
Normal file
BIN
build/icons/icon.ico
Normal file
|
After Width: | Height: | Size: 353 KiB |
1
docs/CNAME
Normal file
@@ -0,0 +1 @@
|
||||
zy.hly120506.top
|
||||
3
docs/dist/css/style.css
vendored
Normal file
1
docs/dist/images/cta-illustration-dark.svg
vendored
Normal file
|
After Width: | Height: | Size: 23 KiB |
1
docs/dist/images/cta-illustration-light.svg
vendored
Normal file
|
After Width: | Height: | Size: 23 KiB |
1
docs/dist/images/feature-01-dark.svg
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="48" height="48" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path fill-opacity=".32" fill="#535FD7" d="M0 0h24v48H0z"/><path fill-opacity=".16" fill="#2FEAFC" d="M28 0h20v20H28z"/><path d="M14 9v4h20V9a1 1 0 0 0-1-1H15a1 1 0 0 0-1 1z" fill="#7C85E1"/><path d="M39 15H9a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h3V23h24v10h3a1 1 0 0 0 1-1V16a1 1 0 0 0-1-1zM20 40v-6h-6z" fill="#61EFFD"/><path d="M14 25v7h7a1 1 0 0 1 1 1v7h11a1 1 0 0 0 1-1V25H14z" fill="#7C85E1"/></g></svg>
|
||||
|
After Width: | Height: | Size: 500 B |
1
docs/dist/images/feature-01-light.svg
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="48" height="48" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path fill-opacity=".64" fill="#93F4FE" d="M0 0h24v48H0z"/><path fill-opacity=".64" fill="#FFCF7B" d="M28 0h20v20H28z"/><path d="M14 9v4h20V9a1 1 0 0 0-1-1H15a1 1 0 0 0-1 1z" fill="#7C85E1"/><path d="M39 15H9a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h3V23h24v10h3a1 1 0 0 0 1-1V16a1 1 0 0 0-1-1zM20 40v-6h-6z" fill="#535FD7"/><path d="M14 25v7h7a1 1 0 0 1 1 1v7h11a1 1 0 0 0 1-1V25H14z" fill="#7C85E1"/></g></svg>
|
||||
|
After Width: | Height: | Size: 500 B |
1
docs/dist/images/feature-02-dark.svg
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="48" height="48" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path fill-opacity=".32" fill="#535FD7" d="M0 0h24v48H0z"/><path fill-opacity=".16" fill="#2FEAFC" d="M28 0h20v20H28z"/><path d="M40 19v-5a2 2 0 0 0-2-2H10a2 2 0 0 0-2 2v5h32z" fill="#61EFFD"/><path d="M8 23v11a2 2 0 0 0 2 2h28a2 2 0 0 0 2-2V23H8zm13 8h-9v-2h9v2zm15 0h-4v-2h4v2z" fill="#7C85E1"/></g></svg>
|
||||
|
After Width: | Height: | Size: 405 B |
1
docs/dist/images/feature-02-light.svg
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="48" height="48" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><g fill-opacity=".64"><path fill="#93F4FE" d="M0 0h24v48H0z"/><path fill="#FFCF7B" d="M28 0h20v20H28z"/></g><path d="M40 19v-5a2 2 0 0 0-2-2H10a2 2 0 0 0-2 2v5h32z" fill="#535FD7"/><path d="M8 23v11a2 2 0 0 0 2 2h28a2 2 0 0 0 2-2V23H8zm13 8h-9v-2h9v2zm15 0h-4v-2h4v2z" fill="#7C85E1"/></g></svg>
|
||||
|
After Width: | Height: | Size: 393 B |
1
docs/dist/images/feature-03-dark.svg
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="48" height="48" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path fill-opacity=".16" fill="#2FEAFC" d="M28 0h20v20H28z"/><path fill-opacity=".32" fill="#535FD7" d="M0 0h24v48H0z"/><path d="M18 9.256l-9.287 2.786A1.001 1.001 0 0 0 8 13v26l10-3.656V9.256z" fill="#61EFFD"/><path fill="#7C85E1" d="M28 12.523l-8-3.2v26.154l8 3.2z"/><path d="M40 9l-10 3.656v26.088l9.287-2.786c.423-.127.713-.517.713-.958V9z" fill="#61EFFD"/></g></svg>
|
||||
|
After Width: | Height: | Size: 469 B |
1
docs/dist/images/feature-03-light.svg
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="48" height="48" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path fill-opacity=".64" fill="#FFCF7B" d="M28 0h20v20H28z"/><path fill-opacity=".64" fill="#93F4FE" d="M0 0h24v48H0z"/><path d="M18 9.256l-9.287 2.786A1.001 1.001 0 0 0 8 13v26l10-3.656V9.256z" fill="#535FD7"/><path fill="#7C85E1" d="M28 12.523l-8-3.2v26.154l8 3.2z"/><path d="M40 9l-10 3.656v26.088l9.287-2.786c.423-.127.713-.517.713-.958V9z" fill="#535FD7"/></g></svg>
|
||||
|
After Width: | Height: | Size: 469 B |
1
docs/dist/images/features-illustration-dark.svg
vendored
Normal file
|
After Width: | Height: | Size: 9.7 KiB |
1
docs/dist/images/features-illustration-light.svg
vendored
Normal file
|
After Width: | Height: | Size: 9.7 KiB |
1
docs/dist/images/features-illustration-top-dark.svg
vendored
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
1
docs/dist/images/features-illustration-top-light.svg
vendored
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
1
docs/dist/images/header-illustration-dark.svg
vendored
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
1
docs/dist/images/header-illustration-light.svg
vendored
Normal file
|
After Width: | Height: | Size: 10 KiB |
1
docs/dist/images/hero-media-illustration-dark.svg
vendored
Normal file
|
After Width: | Height: | Size: 21 KiB |
1
docs/dist/images/hero-media-illustration-light.svg
vendored
Normal file
|
After Width: | Height: | Size: 21 KiB |
1
docs/dist/images/logo-dark.svg
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="32" height="32" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient x1="20.313%" y1="83.13%" x2="79.211%" y2="18.665%" id="a"><stop stop-color="#93F4FE" offset="0%"/><stop stop-color="#535FD7" offset="100%"/></linearGradient><linearGradient x1="50%" y1="0%" x2="77.135%" y2="77.109%" id="b"><stop stop-color="#FFF" stop-opacity=".48" offset="0%"/><stop stop-color="#FFF" stop-opacity="0" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><path d="M16 0C7.163 0 0 7.163 0 16s7.163 16 16 16 16-7.163 16-16C31.99 7.168 24.832.01 16 0z" fill="url(#a)"/><path d="M29.012 25.313A11.98 11.98 0 0 1 25 26c-6.627 0-12-5.373-12-12 0-6.235 4.756-11.36 10.838-11.944C28.705 4.8 31.993 10.016 32 16c0 3.474-1.107 6.69-2.988 9.313z" fill="url(#b)"/></g></svg>
|
||||
|
After Width: | Height: | Size: 786 B |
1
docs/dist/images/logo-light.svg
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="32" height="32" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient x1="50%" y1="0%" x2="77.135%" y2="77.109%" id="a"><stop stop-color="#FE7E1F" offset="0%"/><stop stop-color="#FFCF7B" offset="100%"/></linearGradient><linearGradient x1="50%" y1="0%" x2="77.135%" y2="77.109%" id="b"><stop stop-color="#FFF" stop-opacity=".48" offset="0%"/><stop stop-color="#FFF" stop-opacity="0" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><path d="M16 0C7.163 0 0 7.163 0 16s7.163 16 16 16 16-7.163 16-16C31.99 7.168 24.832.01 16 0z" fill="url(#a)"/><path d="M29.012 25.313A11.98 11.98 0 0 1 25 26c-6.627 0-12-5.373-12-12 0-6.235 4.756-11.36 10.838-11.944C28.705 4.8 31.993 10.016 32 16c0 3.474-1.107 6.69-2.988 9.313z" fill="url(#b)"/></g></svg>
|
||||
|
After Width: | Height: | Size: 778 B |
1
docs/dist/js/main.min.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
!function(){const e=document,t=e.documentElement,n=e.body,i=e.getElementById("lights-toggle"),s=window.sr=ScrollReveal();function a(){let e=i.parentNode.querySelector(".label-text");i.checked?(n.classList.remove("lights-off"),e&&(e.innerHTML="dark")):(n.classList.add("lights-off"),e&&(e.innerHTML="light"))}t.classList.remove("no-js"),t.classList.add("js"),window.addEventListener("load",function(){n.classList.add("is-loaded")}),n.classList.contains("has-animations")&&window.addEventListener("load",function(){s.reveal(".feature",{duration:600,distance:"20px",easing:"cubic-bezier(0.215, 0.61, 0.355, 1)",origin:"right",viewFactor:.2})}),i&&(window.addEventListener("load",a),i.addEventListener("change",a))}();
|
||||
149
docs/index.html
Normal file
@@ -0,0 +1,149 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="no-js">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>ZY Player</title>
|
||||
<link href="https://fonts.googleapis.com/css?family=Heebo:400,700|IBM+Plex+Sans:600" rel="stylesheet">
|
||||
<link rel="stylesheet" href="dist/css/style.css">
|
||||
<script src="https://unpkg.com/scrollreveal@4.0.0/dist/scrollreveal.min.js"></script>
|
||||
</head>
|
||||
<body class="is-boxed has-animations">
|
||||
<div class="body-wrap boxed-container">
|
||||
<header class="site-header">
|
||||
<div class="container">
|
||||
<div class="site-header-inner">
|
||||
<div class="brand header-brand">
|
||||
<h1 class="m-0">
|
||||
<a href="#">
|
||||
<img class="header-logo-image asset-light" src="dist/images/logo-light.svg" alt="Logo">
|
||||
<img class="header-logo-image asset-dark" src="dist/images/logo-dark.svg" alt="Logo">
|
||||
</a>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<section class="hero">
|
||||
<div class="container">
|
||||
<div class="hero-inner">
|
||||
<div class="hero-copy">
|
||||
<h1 class="hero-title mt-0">ZY Player</h1>
|
||||
<p class="hero-paragraph">ZY Player 影视资源播放器, 可以直接浏览或者搜索影视资源,所有资源点击即可播放.软件免费,没有广告~</p>
|
||||
<div class="hero-cta">
|
||||
<a class="button button-primary" href="https://github.com/Hunlongyu/ZY-Player/releases/latest">立即下载</a>
|
||||
<div class="lights-toggle">
|
||||
<input id="lights-toggle" type="checkbox" name="lights-toggle" class="switch" checked="checked">
|
||||
<label for="lights-toggle" class="text-xs"><span>切换主题<span class="label-text">dark</span></span></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hero-media">
|
||||
<div class="header-illustration">
|
||||
<img class="header-illustration-image asset-light" src="dist/images/header-illustration-light.svg" alt="Header illustration">
|
||||
<img class="header-illustration-image asset-dark" src="dist/images/header-illustration-dark.svg" alt="Header illustration">
|
||||
</div>
|
||||
<div class="hero-media-illustration">
|
||||
<img class="hero-media-illustration-image asset-light" src="dist/images/hero-media-illustration-light.svg" alt="Hero media illustration">
|
||||
<img class="hero-media-illustration-image asset-dark" src="dist/images/hero-media-illustration-dark.svg" alt="Hero media illustration">
|
||||
</div>
|
||||
<div class="hero-media-container">
|
||||
<img class="hero-media-image asset-light" src="https://i.loli.net/2020/01/21/HfRhqXDTJMlEIaP.jpg" alt="Hero media">
|
||||
<img class="hero-media-image asset-dark" src="https://i.loli.net/2020/01/21/hGYrDKQbXZctfVs.jpg" alt="Hero media">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="features section">
|
||||
<div class="container">
|
||||
<div class="features-inner section-inner has-bottom-divider">
|
||||
<div class="features-header text-center">
|
||||
<div class="container-sm">
|
||||
<div class="features-image">
|
||||
<img class="features-illustration asset-dark" src="dist/images/features-illustration-dark.svg" alt="Feature illustration">
|
||||
<img style="transform: none;" class="features-box asset-dark" src="https://i.loli.net/2020/01/21/exXt3mfsJSGuhn5.jpg" alt="Feature box">
|
||||
<img class="features-illustration asset-dark" src="dist/images/features-illustration-top-dark.svg" alt="Feature illustration top">
|
||||
<img class="features-illustration asset-light" src="dist/images/features-illustration-light.svg" alt="Feature illustration">
|
||||
<img style="transform: none;" class="features-box asset-light" src="https://i.loli.net/2020/01/21/exXt3mfsJSGuhn5.jpg" alt="Feature box">
|
||||
<img class="features-illustration asset-light" src="dist/images/features-illustration-top-light.svg" alt="Feature illustration top">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="features-wrap">
|
||||
<div class="feature is-revealing">
|
||||
<div class="feature-inner">
|
||||
<div class="feature-icon">
|
||||
<img class="asset-light" src="dist/images/feature-01-light.svg" alt="Feature 01">
|
||||
<img class="asset-dark" src="dist/images/feature-01-dark.svg" alt="Feature 01">
|
||||
</div>
|
||||
<div class="feature-content">
|
||||
<h3 class="feature-title mt-0">开源免费</h3>
|
||||
<p class="text-sm mb-0">代码开源, 软件免费使用, 无广告, 不窃取用户信息, MIT协议.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="feature is-revealing">
|
||||
<div class="feature-inner">
|
||||
<div class="feature-icon">
|
||||
<img class="asset-light" src="dist/images/feature-02-light.svg" alt="Feature 02">
|
||||
<img class="asset-dark" src="dist/images/feature-02-dark.svg" alt="Feature 02">
|
||||
</div>
|
||||
<div class="feature-content">
|
||||
<h3 class="feature-title mt-0">资源丰富</h3>
|
||||
<p class="text-sm mb-0">所有资源都来自多个著名资源网站, 海量资源, 应有尽有.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="feature is-revealing">
|
||||
<div class="feature-inner">
|
||||
<div class="feature-icon">
|
||||
<img class="asset-light" src="dist/images/feature-03-light.svg" alt="Feature 03">
|
||||
<img class="asset-dark" src="dist/images/feature-03-dark.svg" alt="Feature 03">
|
||||
</div>
|
||||
<div class="feature-content">
|
||||
<h3 class="feature-title mt-0">功能强大</h3>
|
||||
<p class="text-sm mb-0">支持多源切换, 搜索. 支持预览详情, 支持收藏, 支持暗黑主题.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- <footer class="site-footer has-top-divider">
|
||||
<div class="container">
|
||||
<div class="site-footer-inner">
|
||||
<div class="brand footer-brand">
|
||||
<a href="#">
|
||||
<img class="asset-light" src="dist/images/logo-light.svg" alt="Logo">
|
||||
<img class="asset-dark" src="dist/images/logo-dark.svg" alt="Logo">
|
||||
</a>
|
||||
</div>
|
||||
<ul class="footer-links list-reset">
|
||||
<li>
|
||||
<a href="#">Contact</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">About us</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">FAQ's</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">Support</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</footer> -->
|
||||
</div>
|
||||
<script src="dist/js/main.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
56
docs/player/index.html
Normal file
@@ -0,0 +1,56 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>ZY Player</title>
|
||||
<style>
|
||||
*{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
html,body{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
#mse{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="mse"></div>
|
||||
<script src="//cdn.jsdelivr.net/npm/xgplayer/browser/index.js" type="text/javascript"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/xgplayer-hls.js/browser/index.js" charset="utf-8"></script>
|
||||
<script>
|
||||
function get (name) {
|
||||
var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
|
||||
var r = window.location.search.substr(1).match(reg);//search,查询?后面的参数,并匹配正则
|
||||
if(r!=null)return unescape(r[2]); return null;
|
||||
}
|
||||
let link = window.location.href
|
||||
let info = get('info')
|
||||
let time = get('time')
|
||||
let title = info.split('$')[0]
|
||||
let url = info.split('$')[1]
|
||||
let player = new window.HlsJsPlayer({
|
||||
id: 'mse',
|
||||
url: url,
|
||||
fluid: true,
|
||||
autoplay: true,
|
||||
playsinline: true,
|
||||
height: window.innerHeight,
|
||||
width: window.innerWidth,
|
||||
'x5-video-player-fullscreen': true,
|
||||
'x5-video-orientation': 'landscape'
|
||||
})
|
||||
player.on('play', function () {
|
||||
player.currentTime = time
|
||||
document.title = title
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
15183
package-lock.json
generated
56
package.json
@@ -1,46 +1,54 @@
|
||||
{
|
||||
"name": "zy-player",
|
||||
"version": "0.6.3",
|
||||
"private": false,
|
||||
"name": "zy",
|
||||
"version": "0.8.6",
|
||||
"author": "Hunlongyu",
|
||||
"description": "ZY Player 资源播放器",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint",
|
||||
"electron:build": "vue-cli-service electron:build",
|
||||
"dev": "vue-cli-service electron:serve",
|
||||
"electron:build": "vue-cli-service electron:build",
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"postuninstall": "electron-builder install-app-deps",
|
||||
"eb": "vue-cli-service electron:build -p always",
|
||||
"patch": "npm version patch && git push origin master && git push origin --tags",
|
||||
"minor": "npm version minor && git push origin master && git push origin --tags",
|
||||
"major": "npm version major && git push origin master && git push origin --tags"
|
||||
"electron:generate-icons": "electron-icon-builder --input=./public/icon.png --output=build --flatten",
|
||||
"bp": "vue-cli-service electron:build --win -p always"
|
||||
},
|
||||
"main": "background.js",
|
||||
"dependencies": {
|
||||
"axios": "^0.19.0",
|
||||
"core-js": "^2.6.5",
|
||||
"nedb": "^1.8.0",
|
||||
"view-design": "^4.0.2",
|
||||
"core-js": "^3.4.4",
|
||||
"dexie": "^2.0.4",
|
||||
"electron-updater": "^4.2.0",
|
||||
"element-ui": "^2.4.5",
|
||||
"flyio": "^0.6.14",
|
||||
"qrcanvas": "^3.0.6",
|
||||
"vue": "^2.6.10",
|
||||
"vue-router": "^3.0.3",
|
||||
"vuex": "^3.0.1",
|
||||
"xgplayer": "^2.4.1",
|
||||
"vue-class-component": "^7.0.2",
|
||||
"vue-property-decorator": "^8.3.0",
|
||||
"vuex": "^3.1.2",
|
||||
"xgplayer": "^2.4.7",
|
||||
"xgplayer-hls.js": "^2.1.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "^3.12.0",
|
||||
"@vue/cli-plugin-eslint": "^3.12.0",
|
||||
"@vue/cli-service": "^3.12.0",
|
||||
"@vue/cli-plugin-babel": "^4.1.0",
|
||||
"@vue/cli-plugin-eslint": "^4.1.0",
|
||||
"@vue/cli-plugin-router": "^4.1.0",
|
||||
"@vue/cli-plugin-typescript": "^4.1.0",
|
||||
"@vue/cli-plugin-vuex": "^4.1.0",
|
||||
"@vue/cli-service": "^4.1.0",
|
||||
"@vue/eslint-config-standard": "^4.0.0",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"babel-plugin-import": "^1.13.0",
|
||||
"electron": "7.1.7",
|
||||
"electron-updater": "^4.2.0",
|
||||
"@vue/eslint-config-typescript": "^4.0.0",
|
||||
"babel-plugin-component": "^1.1.1",
|
||||
"electron": "7.1.9",
|
||||
"electron-icon-builder": "^1.0.2",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-plugin-vue": "^5.0.0",
|
||||
"sass": "^1.19.0",
|
||||
"sass": "^1.23.7",
|
||||
"sass-loader": "^8.0.0",
|
||||
"vue-cli-plugin-electron-builder": "^1.4.2",
|
||||
"typescript": "~3.5.3",
|
||||
"vue-cli-plugin-electron-builder": "^1.4.4",
|
||||
"vue-cli-plugin-element": "^1.0.1",
|
||||
"vue-template-compiler": "^2.6.10"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
autoprefixer: {}
|
||||
}
|
||||
}
|
||||
BIN
public/app.ico
|
Before Width: | Height: | Size: 264 KiB |
BIN
public/app.png
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 91 KiB |
BIN
public/icon.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
@@ -4,12 +4,12 @@
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<link rel="icon" href="<%= BASE_URL %>icon.png">
|
||||
<title>ZY Player</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but evt doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
<strong>We're sorry but zy doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
|
||||
170
src/App.vue
@@ -1,73 +1,141 @@
|
||||
<template>
|
||||
<div id="app" :class="getTheme.color">
|
||||
<Layout class="box">
|
||||
<Sider class="sider" width="70"><ZYSider /></Sider>
|
||||
<Layout>
|
||||
<Header class="header"><ZYHeader /></Header>
|
||||
<ZYContent class="content">
|
||||
<router-view />
|
||||
</ZYContent>
|
||||
</Layout>
|
||||
</Layout>
|
||||
</div>
|
||||
<el-container id="app" :class="appTheme">
|
||||
<el-header class="Header">
|
||||
<i class="el-icon-minus" @click="clickFrameEvent('min')"></i>
|
||||
<i class="el-icon-plus" @click="clickFrameEvent('max')"></i>
|
||||
<i class="el-icon-close" @click="clickFrameEvent('close')"></i>
|
||||
<el-row class="Header-box">
|
||||
</el-row>
|
||||
</el-header>
|
||||
<el-container>
|
||||
<el-aside class="Aside" width="70px">
|
||||
<el-row class="top">
|
||||
<i title="浏览" :class="Main === 'Film' ? 'el-icon-film active' : 'el-icon-film'" @click="asideMenuClick('Film')"></i>
|
||||
<i title="搜索" :class="Main === 'Search' ? 'el-icon-search active' : 'el-icon-search'" @click="asideMenuClick('Search')"></i>
|
||||
<i title="播放" :class="Main === 'Player' ? 'el-icon-video-play active' : 'el-icon-video-play'" @click="asideMenuClick('Player')"></i>
|
||||
<i title="收藏" :class="Main === 'Star' ? 'el-icon-star-off active' : 'el-icon-star-off'" @click="asideMenuClick('Star')"></i>
|
||||
</el-row>
|
||||
<el-row class="bottom">
|
||||
<i title="设置" :class="Main === 'Setting' ? 'el-icon-setting active' : 'el-icon-setting'" @click="asideMenuClick('Setting')"></i>
|
||||
</el-row>
|
||||
</el-aside>
|
||||
<el-main class="Main">
|
||||
<Film v-show="Main === 'Film'" />
|
||||
<Search v-show="Main === 'Search'" />
|
||||
<Player v-show="Main === 'Player'" />
|
||||
<Star v-show="Main === 'Star'" />
|
||||
<Setting v-show="Main === 'Setting'" />
|
||||
</el-main>
|
||||
</el-container>
|
||||
<el-drawer class="drawer" :visible.sync="detail.show" :show-close="true" size="90%" :with-header="true" direction="btt" title="详情">
|
||||
<Detail />
|
||||
</el-drawer>
|
||||
</el-container>
|
||||
</template>
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex'
|
||||
import ZYSider from '@/components/zy_sider.vue'
|
||||
import ZYHeader from '@/components/zy_header.vue'
|
||||
import ZYContent from '@/components/zy_content.vue'
|
||||
import setting from './plugin/nedb/setting'
|
||||
export default {
|
||||
name: 'app',
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import Detail from '@/components/detail.vue'
|
||||
import { mapMutations } from 'vuex'
|
||||
const { ipcRenderer: ipc } = require('electron')
|
||||
export default Vue.extend({
|
||||
data () {
|
||||
return {}
|
||||
return {
|
||||
appTheme: 'theme-light'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'getTheme'
|
||||
])
|
||||
Main: {
|
||||
get () {
|
||||
return this.$store.getters.getMain
|
||||
},
|
||||
set (val) {
|
||||
this.SET_MAIN(val)
|
||||
}
|
||||
},
|
||||
detail: {
|
||||
get () {
|
||||
return this.$store.getters.getDetail
|
||||
},
|
||||
set (val) {
|
||||
this.SET_DETAIL(val)
|
||||
}
|
||||
},
|
||||
theme () {
|
||||
return this.$store.getters.getTheme
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
theme () {
|
||||
this.changeTheme()
|
||||
}
|
||||
},
|
||||
components: {
|
||||
ZYSider,
|
||||
ZYHeader,
|
||||
ZYContent
|
||||
Detail
|
||||
},
|
||||
methods: {
|
||||
...mapActions([
|
||||
'changeTheme'
|
||||
])
|
||||
},
|
||||
beforeCreate () {},
|
||||
created () {
|
||||
setting.find({ $or: [{ theme: 'light' }, { theme: 'dark' }] }).then(e => {
|
||||
if (e.length <= 0) {
|
||||
setting.add({ theme: 'light' }).then(res => {
|
||||
this.changeTheme({ id: res._id, color: res.theme })
|
||||
})
|
||||
} else {
|
||||
this.changeTheme({ id: e[0]._id, color: e[0].theme })
|
||||
}
|
||||
})
|
||||
...mapMutations(['SET_DETAIL', 'SET_MAIN']),
|
||||
clickFrameEvent (e:string) {
|
||||
ipc.send(e)
|
||||
},
|
||||
asideMenuClick (e:string) {
|
||||
this.Main = e
|
||||
},
|
||||
changeTheme () {
|
||||
this.appTheme = `theme-${this.theme}`
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import './assets/global/global.scss';
|
||||
@import './assets/theme/global.scss';
|
||||
@import './assets/theme/dark.scss';
|
||||
@import './assets/theme/light.scss';
|
||||
html, body, #app, .box{
|
||||
*{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
html,body{
|
||||
height: 100%;
|
||||
}
|
||||
.box{
|
||||
.header{
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
#app{
|
||||
height: 100%;
|
||||
user-select: none;
|
||||
.Header{
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
-webkit-app-region: drag;
|
||||
-webkit-user-select: none;
|
||||
padding: 0;
|
||||
i{
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
font-size: 30px;
|
||||
cursor: pointer;
|
||||
-webkit-app-region: no-drag;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
.content{
|
||||
width: 100%;
|
||||
.Aside{
|
||||
-webkit-app-region: drag;
|
||||
-webkit-user-select: none;
|
||||
text-align: center;
|
||||
i{
|
||||
-webkit-app-region: no-drag;
|
||||
font-size: 32px;
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
line-height: 70px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.Main{
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
.detail{
|
||||
padding: 10px;
|
||||
.detail-box{
|
||||
border: 1px solid #ddd;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 10px;
|
||||
flex-wrap: wrap;
|
||||
.vodImg{
|
||||
width: 200px;
|
||||
img{
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
.vodInfo{
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
margin-left: 20px;
|
||||
.vodh{
|
||||
h2{
|
||||
display: inline-block;
|
||||
}
|
||||
span{
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-left: 10px;
|
||||
}
|
||||
label{
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #f90;
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
li{
|
||||
list-style: none;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
height: 20px;
|
||||
overflow: hidden;
|
||||
a{
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
src/assets/image/dark.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
src/assets/image/light.png
Normal file
|
After Width: | Height: | Size: 78 KiB |
@@ -1,7 +1,109 @@
|
||||
.dark{
|
||||
.sider,.header,.content{
|
||||
background-color: #000;
|
||||
color: #eee;
|
||||
border: 1px solid #ccc;
|
||||
.theme-dark{
|
||||
color: var(--d-c);
|
||||
background-color: var(--d-bgc);
|
||||
.el-button, input, select, .el-select{
|
||||
color: var(--d-c);
|
||||
background-color: var(--d-bgc);
|
||||
border-color: var(--d-bdc);
|
||||
}
|
||||
.el-button--text{
|
||||
border: none;
|
||||
}
|
||||
.el-tabs__item, .el-tabs__nav-wrap::after{
|
||||
color: var(--d-c);
|
||||
background-color: var(--d-bgc);
|
||||
border-color: var(--d-dbc);
|
||||
}
|
||||
.el-table--border::after, .el-table--group::after, .el-table::before,
|
||||
.el-table, .el-table th, .el-table tr,
|
||||
.el-table--striped .el-table__body tr.el-table__row--striped td,
|
||||
.el-table--enable-row-hover .el-table__body tr:hover>td,
|
||||
.el-table td, .el-table th.is-leaf{
|
||||
color: var(--d-c);
|
||||
background-color: var(--d-bgc);
|
||||
border-color: var(--d-dbc);
|
||||
}
|
||||
.el-pagination, .el-pagination .el-pagination__total, .el-pagination .el-pagination__jump,
|
||||
.el-pagination .btn-next, .el-pagination .btn-prev, .el-pager li{
|
||||
color: var(--d-c);
|
||||
background-color: var(--d-bgc);
|
||||
}
|
||||
.el-input__inner,
|
||||
.el-input-group__append, .el-input-group__prepend{
|
||||
background-color: var(--d-bgc);
|
||||
border-color: var(--d-dbc);
|
||||
}
|
||||
.el-select-dropdown{
|
||||
color: var(--d-c);
|
||||
}
|
||||
.el-drawer{
|
||||
background-color: var(--d-bgc) !important;
|
||||
overflow: auto;
|
||||
&::-webkit-scrollbar{
|
||||
width: 0px;
|
||||
}
|
||||
}
|
||||
.el-loading-mask{
|
||||
background-color: var(--d-bgc);
|
||||
opacity: 0.9;
|
||||
}
|
||||
.Header, .Aside{
|
||||
i{
|
||||
color: var(--d-icon);
|
||||
&:hover{
|
||||
color: var(--d-icon-h);
|
||||
background-color: var(--d-bgc-h);
|
||||
}
|
||||
}
|
||||
}
|
||||
.Aside{
|
||||
i{
|
||||
&.active{
|
||||
color: var(--d-icon-h);
|
||||
background-color: var(--d-bgc-h);
|
||||
border-left: 4px solid var(--d-icon-h);
|
||||
}
|
||||
}
|
||||
}
|
||||
.Main{
|
||||
.film, .search, .star, .player{
|
||||
.table-box{
|
||||
&::-webkit-scrollbar-track {
|
||||
box-shadow: inset 0 0 6px var(--d-bdc);
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: var(--d-icon);
|
||||
outline: 1px solid var(--d-icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
.setting{
|
||||
.el-link, .card{
|
||||
color: var(--d-c);
|
||||
background-color: var(--d-bgc);
|
||||
border-color: var(--d-bdc);
|
||||
}
|
||||
}
|
||||
}
|
||||
.detail{
|
||||
color: var(--d-c);
|
||||
&::-webkit-scrollbar-track {
|
||||
box-shadow: inset 0 0 6px var(--d-bdc);
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: var(--d-icon);
|
||||
outline: 1px solid var(--d-icon);
|
||||
}
|
||||
.box, .info, .urls{
|
||||
border: 1px solid var(--d-bdc);
|
||||
}
|
||||
.vodInfo{
|
||||
li, span, a{
|
||||
color: var(--d-c);
|
||||
}
|
||||
label{
|
||||
color: #f90;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
src/assets/theme/global.scss
Normal file
@@ -0,0 +1,19 @@
|
||||
:root{
|
||||
// light
|
||||
--l-c: #808695;
|
||||
--l-c-h: #515a6e;
|
||||
--l-icon: #C0C4CC;
|
||||
--l-icon-h: #515a6e;
|
||||
--l-bgc: #ffffff;
|
||||
--l-bgc-h: #efefef;
|
||||
--l-bdc: #dcdee2;
|
||||
|
||||
// dark
|
||||
--d-c: #919191;
|
||||
--d-c-h: #454545;
|
||||
--d-icon: #919191;
|
||||
--d-icon-h: #919191;
|
||||
--d-bgc: #242424;
|
||||
--d-bgc-h: #454545;
|
||||
--d-bdc: #7a7a7a;
|
||||
}
|
||||
@@ -1,55 +1,73 @@
|
||||
.light{
|
||||
.sider,.header,.content{
|
||||
background-color: #fff;
|
||||
color: #515a6e;
|
||||
.theme-light{
|
||||
color: var(--l-c);
|
||||
background-color: var(--l-bgc);
|
||||
.el-table, .el-tabs__item, .btn-next, input{
|
||||
color: var(--l-c);
|
||||
}
|
||||
.sider{
|
||||
.sider-box{
|
||||
color: #808695;
|
||||
i{
|
||||
&:hover{
|
||||
color: #515a6e;
|
||||
background-color: #efefef;
|
||||
}
|
||||
&.active{
|
||||
color: #515a6e;
|
||||
background-color: #efefef;
|
||||
border-left: 4px solid #515a6e;
|
||||
}
|
||||
.el-pagination, .el-pagination .el-pagination__total, .el-pagination .el-pagination__jump,
|
||||
.el-pagination .btn-next, .el-pagination .btn-prev{
|
||||
color: var(--l-c);
|
||||
}
|
||||
.el-drawer{
|
||||
overflow: auto;
|
||||
&::-webkit-scrollbar{
|
||||
width: 0px;
|
||||
}
|
||||
}
|
||||
.Header, .Aside{
|
||||
i{
|
||||
color: var(--l-icon);
|
||||
&:hover{
|
||||
color: var(--l-icon-h);
|
||||
background-color: var(--l-bgc-h);
|
||||
}
|
||||
}
|
||||
}
|
||||
.header{
|
||||
.header-box{
|
||||
color: #808695;
|
||||
i{
|
||||
&:hover{
|
||||
color: #515a6e;
|
||||
background-color: #efefef;
|
||||
border-bottom: 1px solid #808695;
|
||||
}
|
||||
.Aside{
|
||||
i{
|
||||
&.active{
|
||||
color: var(--l-icon-h);
|
||||
background-color: var(--l-bgc-h);
|
||||
border-left: 4px solid var(--l-icon-h);
|
||||
}
|
||||
}
|
||||
}
|
||||
.content{
|
||||
border: 1px solid #dcdee2;
|
||||
}
|
||||
.search{
|
||||
.search-middle{
|
||||
.ivu-table-cell{
|
||||
button{
|
||||
margin: 0 4px;
|
||||
.Main{
|
||||
.film, .search, .star, .player, .setting{
|
||||
.table-box{
|
||||
&::-webkit-scrollbar-track {
|
||||
box-shadow: inset 0 0 6px var(--l-bdc);
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: var(--l-icon);
|
||||
outline: 1px solid var(--l-icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
.search-bottom{
|
||||
border-top: 1px solid #f0f0f0;
|
||||
.setting{
|
||||
.el-link, .card{
|
||||
color: var(--l-c);
|
||||
}
|
||||
}
|
||||
}
|
||||
.collection{
|
||||
.ivu-table-cell{
|
||||
button{
|
||||
margin: 0 4px;
|
||||
.detail{
|
||||
color: var(--l-c);
|
||||
&::-webkit-scrollbar-track {
|
||||
box-shadow: inset 0 0 6px var(--l-bdc);
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: var(--l-icon);
|
||||
outline: 1px solid var(--l-icon);
|
||||
}
|
||||
.box, .info, .urls{
|
||||
border: 1px solid var(--l-bdc);
|
||||
}
|
||||
.vodInfo{
|
||||
li, span, a{
|
||||
color: var(--l-c);
|
||||
}
|
||||
label{
|
||||
color: #f90;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,16 @@
|
||||
|
||||
import { app, protocol, ipcMain, BrowserWindow } from 'electron'
|
||||
import {
|
||||
createProtocol
|
||||
createProtocol,
|
||||
installVueDevtools
|
||||
} from 'vue-cli-plugin-electron-builder/lib'
|
||||
import path from 'path'
|
||||
import { autoUpdater } from 'electron-updater'
|
||||
|
||||
const isDevelopment = process.env.NODE_ENV !== 'production'
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let win
|
||||
let win: BrowserWindow | null
|
||||
|
||||
// Scheme must be registered before the app is ready
|
||||
protocol.registerSchemesAsPrivileged([{ scheme: 'app', privileges: { secure: true, standard: true } }])
|
||||
@@ -24,12 +25,14 @@ function createWindow () {
|
||||
webPreferences: {
|
||||
webSecurity: false,
|
||||
nodeIntegration: true
|
||||
}
|
||||
},
|
||||
// @ts-ignore
|
||||
icon: path.join(__static, 'icon.png')
|
||||
})
|
||||
|
||||
if (process.env.WEBPACK_DEV_SERVER_URL) {
|
||||
// Load the url of the dev server if in development mode
|
||||
win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
|
||||
win.loadURL(process.env.WEBPACK_DEV_SERVER_URL as string)
|
||||
if (!process.env.IS_TEST) win.webContents.openDevTools()
|
||||
} else {
|
||||
createProtocol('app')
|
||||
@@ -60,35 +63,79 @@ app.on('activate', () => {
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('min', e => win.minimize())
|
||||
ipcMain.on('max', e => {
|
||||
if (win.isMaximized()) {
|
||||
win.unmaximize()
|
||||
} else {
|
||||
win.maximize()
|
||||
ipcMain.on('min', () => {
|
||||
if (win) {
|
||||
win.minimize()
|
||||
}
|
||||
})
|
||||
ipcMain.on('close', e => win.close())
|
||||
ipcMain.on('max', e => {
|
||||
if (win) {
|
||||
if (win.isMaximized()) {
|
||||
win.unmaximize()
|
||||
} else {
|
||||
win.maximize()
|
||||
}
|
||||
}
|
||||
})
|
||||
ipcMain.on('close', e => {
|
||||
if (win) {
|
||||
win.close()
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('opacity', (e, arg) => {
|
||||
if (win) {
|
||||
win.setOpacity(arg)
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('top', () => {
|
||||
if (win) {
|
||||
if (win.isAlwaysOnTop()) {
|
||||
win.setAlwaysOnTop(false)
|
||||
} else {
|
||||
win.setAlwaysOnTop(true)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const gotTheLock = app.requestSingleInstanceLock()
|
||||
if (!gotTheLock) {
|
||||
app.quit()
|
||||
} else {
|
||||
app.on('second-instance', (event, commandLine, workingDirectory) => {
|
||||
// 当运行第二个实例时,将会聚焦到win这个窗口
|
||||
if (win) {
|
||||
if (win.isMinimized()) win.restore()
|
||||
win.focus()
|
||||
}
|
||||
})
|
||||
|
||||
// 创建 win, 加载应用的其余部分, etc...
|
||||
app.on('ready', () => {
|
||||
createWindow()
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.on('ready', async () => {
|
||||
if (isDevelopment && !process.env.IS_TEST) {
|
||||
// Install Vue Devtools
|
||||
// Devtools extensions are broken in Electron 6.0.0 and greater
|
||||
// See https://github.com/nklayman/vue-cli-plugin-electron-builder/issues/378 for more info
|
||||
// Electron will not launch with Devtools extensions installed on Windows 10 with dark mode
|
||||
// If you are not using Windows 10 dark mode, you may uncomment these lines
|
||||
// In addition, if the linked issue is closed, you can upgrade electron and uncomment these lines
|
||||
// try {
|
||||
// await installVueDevtools()
|
||||
// } catch (e) {
|
||||
// console.error('Vue Devtools failed to install:', e.toString())
|
||||
// }
|
||||
}
|
||||
createWindow()
|
||||
})
|
||||
// app.on('ready', async () => {
|
||||
// if (isDevelopment && !process.env.IS_TEST) {
|
||||
// // Install Vue Devtools
|
||||
// // Devtools extensions are broken in Electron 6.0.0 and greater
|
||||
// // See https://github.com/nklayman/vue-cli-plugin-electron-builder/issues/378 for more info
|
||||
// // Electron will not launch with Devtools extensions installed on Windows 10 with dark mode
|
||||
// // If you are not using Windows 10 dark mode, you may uncomment these lines
|
||||
// // In addition, if the linked issue is closed, you can upgrade electron and uncomment these lines
|
||||
// try {
|
||||
// await installVueDevtools()
|
||||
// } catch (e) {
|
||||
// console.error('Vue Devtools failed to install:', e.toString())
|
||||
// }
|
||||
// }
|
||||
// createWindow()
|
||||
// })
|
||||
|
||||
// Exit cleanly on request from parent process in development mode.
|
||||
if (isDevelopment) {
|
||||
159
src/components/detail.vue
Normal file
@@ -0,0 +1,159 @@
|
||||
<template>
|
||||
<el-row class="detail">
|
||||
<el-row class="detail-box" v-loading="loading">
|
||||
<el-row v-html="detail.box" class="box"></el-row>
|
||||
<el-row v-html="detail.info" class="info"></el-row>
|
||||
<el-row class="urls">
|
||||
<el-button size="mini" v-for="(i, j) in detail.urls" :key="j" @click="playBtn(i, j)">{{i | ftLink}}</el-button>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import zy from '@/lib/util.zy'
|
||||
import { mapMutations } from 'vuex'
|
||||
export default Vue.extend({
|
||||
name: 'detail',
|
||||
data () {
|
||||
return {
|
||||
detail: {},
|
||||
loading: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
d () {
|
||||
return this.$store.getters.getDetail
|
||||
},
|
||||
video: {
|
||||
get () {
|
||||
return this.$store.getters.getVideo
|
||||
},
|
||||
set (val) {
|
||||
this.SET_VIDEO(val)
|
||||
}
|
||||
},
|
||||
Main: {
|
||||
get () {
|
||||
return this.$store.getters.getMain
|
||||
},
|
||||
set (val) {
|
||||
this.SET_MAIN(val)
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
d () {
|
||||
this.getDetailEvent()
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
ftLink (e: string) {
|
||||
let name = e.split('$')[0]
|
||||
return name
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SET_MAIN', 'SET_VIDEO']),
|
||||
getDetailEvent () {
|
||||
let url = this.d.video.detail
|
||||
this.detail = {}
|
||||
this.loading = true
|
||||
zy.detail(url).then((res: any) => {
|
||||
this.detail = res
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
playBtn (i: string, j: number) {
|
||||
if (this.Main !== 'Player') {
|
||||
this.d.video.index = j
|
||||
this.video = this.d.video
|
||||
this.Main = 'Player'
|
||||
} else {
|
||||
this.d.video.index = j
|
||||
this.video = this.d.video
|
||||
}
|
||||
this.d.show = false
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getDetailEvent()
|
||||
},
|
||||
mounted () {}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.detail{
|
||||
box-sizing: border-box;
|
||||
padding: 0 60px;
|
||||
.detail-box{
|
||||
width: 100%;
|
||||
.box{
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
.vodImg{
|
||||
width: 200px;
|
||||
img{
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
.vodAd{
|
||||
display: none;
|
||||
}
|
||||
.vodInfo{
|
||||
flex: 1;
|
||||
margin-left: 20px;
|
||||
.vodh{
|
||||
h2{
|
||||
display: inline-block;
|
||||
}
|
||||
span{
|
||||
font-size: 12px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
label{
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
.cont, .tags{
|
||||
display: none;
|
||||
}
|
||||
li{
|
||||
list-style: none;
|
||||
font-size: 14px;
|
||||
height: 20px;
|
||||
overflow: hidden;
|
||||
a{
|
||||
display: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
span{
|
||||
word-wrap:break-word
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.info, .urls{
|
||||
padding: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.info{
|
||||
font-size: 14px;
|
||||
}
|
||||
.urls{
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 0;
|
||||
button{
|
||||
margin: 0 10px 10px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,13 +0,0 @@
|
||||
<template>
|
||||
<router-view />
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'zy_content',
|
||||
methods: {
|
||||
switchTheme (e) {
|
||||
this.theme = e
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,39 +0,0 @@
|
||||
<template>
|
||||
<Row class="header-box">
|
||||
<Icon type="md-remove" @click="clickFrameEvent('min')" />
|
||||
<Icon type="md-add" @click="clickFrameEvent('max')" />
|
||||
<Icon type="md-close" @click="clickFrameEvent('close')" />
|
||||
</Row>
|
||||
</template>
|
||||
<script>
|
||||
const { ipcRenderer: ipc } = require('electron')
|
||||
export default {
|
||||
name: 'zy_header',
|
||||
methods: {
|
||||
clickFrameEvent (e) {
|
||||
ipc.send(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.header-box{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 70px;
|
||||
width: calc(100% - 70px);
|
||||
height: 50px;
|
||||
-webkit-app-region: drag;
|
||||
-webkit-user-select: none;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
i{
|
||||
font-size: 20px;
|
||||
width:50px;
|
||||
height:50px;
|
||||
line-height:50px;
|
||||
cursor: pointer;
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,52 +0,0 @@
|
||||
<template>
|
||||
<Row class="sider-box">
|
||||
<div class="top">
|
||||
<Icon title="搜索" :class="iconActive === 'search' ? 'active': ''" type="md-search" @click="iconClickEvent('search')"/>
|
||||
<Icon title="详情" v-show="Object.keys(video).length !== 0" :class="iconActive === 'detail' ? 'active': ''" type="md-list" @click="iconClickEvent('detail')"/>
|
||||
<Icon title="播放" v-show="Object.keys(video).length !== 0" :class="iconActive === 'play' ? 'active': ''" type="md-play" @click="iconClickEvent('play')"/>
|
||||
<Icon title="收藏" :class="iconActive === 'collection' ? 'active': ''" type="md-star" @click="iconClickEvent('collection')"/>
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<Icon title="设置" :class="iconActive === 'settings' ? 'active': ''" type="md-settings" @click="iconClickEvent('settings')"/>
|
||||
</div>
|
||||
</Row>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'zy-sider',
|
||||
computed: {
|
||||
iconActive () {
|
||||
return this.$store.getters.getIconActive
|
||||
},
|
||||
video () {
|
||||
return this.$store.getters.getVideo
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
iconClickEvent (e) {
|
||||
this.$router.push({ name: e })
|
||||
this.$store.commit('SET_ICON_ACTIVE', e)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.sider-box{
|
||||
height: 100%;
|
||||
position: relative;
|
||||
-webkit-app-region: drag;
|
||||
-webkit-user-select: none;
|
||||
.bottom{
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
i{
|
||||
-webkit-app-region: no-drag;
|
||||
font-size: 32px;
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
line-height: 70px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,29 +0,0 @@
|
||||
const sites = [
|
||||
{
|
||||
id: 'okzy',
|
||||
name: 'OK资源网',
|
||||
url: 'https://www.okzy.co'
|
||||
},
|
||||
{
|
||||
id: 'zuidazy',
|
||||
name: '最大资源网',
|
||||
url: 'http://www.zuidazy1.com'
|
||||
},
|
||||
{
|
||||
id: 'subo',
|
||||
name: '速播资源站',
|
||||
url: 'https://www.subo988.com'
|
||||
},
|
||||
{
|
||||
id: 'zuixinzy',
|
||||
name: '最新资源网',
|
||||
url: 'http://www.zuixinzy.cc'
|
||||
},
|
||||
{
|
||||
id: '123ku',
|
||||
name: '123资源网',
|
||||
url: 'https://www.123ku.com'
|
||||
}
|
||||
]
|
||||
|
||||
export default sites
|
||||
41
src/lib/sites.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
interface Site {
|
||||
id: string
|
||||
name: string
|
||||
url: string
|
||||
type: Array<any>
|
||||
}
|
||||
|
||||
const sites:Array<Site> = [
|
||||
{
|
||||
id: 'okzy',
|
||||
name: 'OK资源网',
|
||||
url: 'https://www.okzy.co',
|
||||
type: [[ '最新', '0' ], [ '电影', '1' ], [ '电视剧', '2' ], [ '综艺', '3' ], [ '动漫', '4' ], [ '伦理', '21' ], [ '福利', '22' ], [ '解说', '33' ]]
|
||||
},
|
||||
{
|
||||
id: 'zuidazy',
|
||||
name: '最大资源网',
|
||||
url: 'http://www.zuidazy1.com',
|
||||
type: [[ '最新', '0' ], [ '电影', '1' ], [ '电视剧', '2' ], [ '综艺', '3' ], [ '动漫', '4' ], [ '福利', '16' ], [ '伦理', '17' ], [ '音乐', '18' ]]
|
||||
},
|
||||
{
|
||||
id: 'subo',
|
||||
name: '速播资源站',
|
||||
url: 'https://www.subo988.com',
|
||||
type: [[ '最新', '0' ], [ '电影', '1' ], [ '电视剧', '2' ], [ '综艺', '3' ], [ '动漫', '4' ], [ '伦理', '16' ], [ '音乐', '20' ]]
|
||||
},
|
||||
{
|
||||
id: 'zuixinzy',
|
||||
name: '最新资源网',
|
||||
url: 'http://www.zuixinzy.cc',
|
||||
type: [[ '最新', '0' ], [ '电影', '1' ], [ '电视剧', '2' ], [ '综艺', '3' ], [ '动漫', '4' ], ['伦理', '21'], ['情色', '23'], [ '福利', '30' ], [ '解说', '34' ]]
|
||||
},
|
||||
{
|
||||
id: '123ku',
|
||||
name: '123资源网',
|
||||
url: 'https://www.123ku.com',
|
||||
type: [[ '最新', '0' ], [ '电影', '1' ], [ '电视剧', '2' ], [ '综艺', '3' ], [ '动漫', '4' ], [ '伦理', '16' ]]
|
||||
}
|
||||
]
|
||||
|
||||
export default sites
|
||||
@@ -1,94 +0,0 @@
|
||||
import axios from 'axios'
|
||||
import sites from './sites'
|
||||
const zy = {
|
||||
num: 0,
|
||||
page: 1,
|
||||
key: '',
|
||||
site: {},
|
||||
list: [],
|
||||
getInfoRequire () {
|
||||
return new Promise((resolve, reject) => {
|
||||
const key = encodeURI(this.key)
|
||||
const params = `${this.site.url}/index.php?m=vod-search-pg-${this.page}-wd-${key}.html`
|
||||
axios.get(params).then(res => {
|
||||
this.getInfoHtml(res.data).then(res => {
|
||||
resolve(res)
|
||||
})
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
getInfoHtml (txt) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const parser = new DOMParser()
|
||||
const html = parser.parseFromString(txt, 'text/html')
|
||||
const list = html.querySelectorAll('.xing_vb li')
|
||||
let d = {
|
||||
list: [],
|
||||
num: 0
|
||||
}
|
||||
for (let i = 1; i < list.length - 1; i++) {
|
||||
let info = {
|
||||
name: list[i].childNodes[1].innerText,
|
||||
detail: this.site.url + list[i].childNodes[1].childNodes[0].getAttribute('href'),
|
||||
category: list[i].childNodes[3].innerText,
|
||||
time: list[i].childNodes[5].innerText,
|
||||
index: 0,
|
||||
urls: [],
|
||||
check: false
|
||||
}
|
||||
d.list.push(info)
|
||||
}
|
||||
let num = html.querySelectorAll('.nvc dd span')[1].innerText
|
||||
num = parseInt(num)
|
||||
d.num = num
|
||||
resolve(d)
|
||||
})
|
||||
},
|
||||
info (n = 0, p = 1, k = null) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.page = p
|
||||
this.key = k
|
||||
this.num = n
|
||||
this.site = sites[this.num]
|
||||
this.getInfoRequire().then(res => {
|
||||
resolve(res)
|
||||
})
|
||||
})
|
||||
},
|
||||
detail (url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios.get(url).then(res => {
|
||||
resolve(this.getDetailUrls(res.data))
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
getDetailUrls (txt) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const parser = new DOMParser()
|
||||
let html = parser.parseFromString(txt, 'text/html')
|
||||
let data = {
|
||||
box: null,
|
||||
info: null,
|
||||
urls: []
|
||||
}
|
||||
data.box = html.querySelector('.vodBox').innerHTML
|
||||
data.info = html.querySelector('.vodplayinfo').innerHTML
|
||||
let urls = html.querySelectorAll('.vodplayinfo li')
|
||||
let arr = []
|
||||
for (let i in urls) {
|
||||
let j = urls[i].innerText
|
||||
if (j !== undefined && j.indexOf('.m3u8') !== -1) {
|
||||
arr.push(urls[i].innerText)
|
||||
}
|
||||
}
|
||||
data.urls = arr
|
||||
resolve(data)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default zy
|
||||
173
src/lib/util.zy.ts
Normal file
@@ -0,0 +1,173 @@
|
||||
import fly from 'flyio'
|
||||
import sites from './sites'
|
||||
import { TimeSelect } from 'element-ui'
|
||||
|
||||
interface ZY {
|
||||
num: number
|
||||
page: number
|
||||
key: string
|
||||
site: any
|
||||
list: Array<string>
|
||||
getInfoRequire: any
|
||||
getInfoHtml: any
|
||||
info: any
|
||||
detail: any
|
||||
films: any
|
||||
}
|
||||
|
||||
interface info {
|
||||
name?: string
|
||||
type?: string
|
||||
time?: string
|
||||
detail?: string
|
||||
urls?: Array<string>
|
||||
index?: number
|
||||
}
|
||||
|
||||
interface detail {
|
||||
box?: any
|
||||
info?: any
|
||||
urls?: Array<string>
|
||||
}
|
||||
|
||||
fly.config.timeout = 10000
|
||||
|
||||
const zy: ZY = {
|
||||
num: 0,
|
||||
page: 1,
|
||||
key: '',
|
||||
site: {},
|
||||
list: [],
|
||||
getInfoRequire () {
|
||||
return new Promise((resolve, reject) => {
|
||||
let key = encodeURI(this.key)
|
||||
const params = `${this.site.url}/index.php?m=vod-search-pg-${this.page}-wd-${key}.html`
|
||||
fly.get(params).then(res => {
|
||||
this.getInfoHtml(res.data).then((data: any) => {
|
||||
resolve(data)
|
||||
})
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
getInfoHtml (txt: string): any {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const parser = new DOMParser()
|
||||
const html = parser.parseFromString(txt, 'text/html')
|
||||
const list: any = html.querySelectorAll('.xing_vb li')
|
||||
let d: any = { list: [], total: 0 }
|
||||
for (let i = 1; i < list.length - 1; i++) {
|
||||
let info: info = {
|
||||
name: list[i].childNodes[1].innerText,
|
||||
type: list[i].childNodes[3].innerText,
|
||||
time: list[i].childNodes[5].innerText,
|
||||
detail: this.site.url + list[i].childNodes[1].childNodes[0].getAttribute('href'),
|
||||
index: 0,
|
||||
urls: []
|
||||
}
|
||||
d.list.push(info)
|
||||
}
|
||||
let num: any = (<HTMLImageElement>html.querySelectorAll('.nvc dd span')[1]).innerText
|
||||
num = parseInt(num)
|
||||
d.total = num
|
||||
resolve(d)
|
||||
} catch (err) {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
},
|
||||
info (n: number = 0, p: number = 1, k: string = '') {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.num = n
|
||||
this.page = p
|
||||
this.key = k
|
||||
this.site = sites[n]
|
||||
this.getInfoRequire().then((res: any) => {
|
||||
resolve(res)
|
||||
}).catch((err: any) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
detail (url: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!url) return
|
||||
fly.get(url).then(res => {
|
||||
const parser = new DOMParser()
|
||||
let html = parser.parseFromString(res.data, 'text/html')
|
||||
let data: detail = {
|
||||
box: '',
|
||||
info: '',
|
||||
urls: []
|
||||
}
|
||||
let vodBox = html.querySelector('.vodBox')
|
||||
if (vodBox) {
|
||||
data.box = vodBox.innerHTML
|
||||
}
|
||||
let vodInfo = {}
|
||||
if (url.indexOf('123ku') !== -1 || url.indexOf('subo988') !== -1) {
|
||||
vodInfo = html.querySelectorAll('.vodplayinfo')[1]
|
||||
} else {
|
||||
vodInfo = <HTMLImageElement>html.querySelector('.vodplayinfo')
|
||||
}
|
||||
data.info = (<HTMLImageElement>vodInfo).innerText
|
||||
let urls = html.querySelectorAll('.vodplayinfo li')
|
||||
let arr = []
|
||||
for (let i in urls) {
|
||||
let j = (<HTMLImageElement>urls[i]).innerText
|
||||
if (j !== undefined && j.indexOf('.m3u8') !== -1) {
|
||||
arr.push((<HTMLImageElement>urls[i]).innerText)
|
||||
}
|
||||
}
|
||||
data.urls = arr
|
||||
resolve(data)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
films (n: number = 0, p: number = 1, type: string = '0') {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.site = sites[n]
|
||||
let url: string = sites[n].url
|
||||
let params: string = ''
|
||||
if (type === '0') {
|
||||
params = `${url}/?m=vod-index-pg-${p}.html`
|
||||
} else {
|
||||
params = `${url}/?m=vod-type-id-${type}-pg-${p}.html`
|
||||
}
|
||||
fly.get(params).then(res => {
|
||||
const parser = new DOMParser()
|
||||
const html = parser.parseFromString(res.data, 'text/html')
|
||||
const list: any = html.querySelectorAll('.xing_vb li')
|
||||
let d: any = { list: [], total: 0 }
|
||||
for (let i = 1; i < list.length - 1; i++) {
|
||||
let info: info = {
|
||||
name: list[i].childNodes[1].innerText,
|
||||
type: list[i].childNodes[3].innerText,
|
||||
time: list[i].childNodes[5].innerText,
|
||||
detail: this.site.url + list[i].querySelector('a').getAttribute('href'),
|
||||
index: 0,
|
||||
urls: []
|
||||
}
|
||||
d.list.push(info)
|
||||
}
|
||||
let num: any = html.querySelectorAll('.pages')
|
||||
if (num) {
|
||||
let n = num[0].innerText
|
||||
n = n.split('条')[0]
|
||||
n = n.split('共')[1]
|
||||
n = parseInt(n)
|
||||
d.total = n
|
||||
}
|
||||
resolve(d)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default zy
|
||||
@@ -1,13 +1,14 @@
|
||||
import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
import store from './store'
|
||||
import '@/plugin/iview/'
|
||||
import './plugins/element.ts'
|
||||
import Register from './page/register'
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
Register.registerComponents()
|
||||
|
||||
new Vue({
|
||||
router,
|
||||
store,
|
||||
render: h => h(App)
|
||||
}).$mount('#app')
|
||||
176
src/page/film.vue
Normal file
@@ -0,0 +1,176 @@
|
||||
<template>
|
||||
<el-row class="film">
|
||||
<el-row class="film-tabs">
|
||||
<el-tabs v-model="tabs" @tab-click="tabClick">
|
||||
<el-tab-pane class="film-tabpane" v-for="(i, j) in sites[site].type" :key="j" :label="i[0]" :name="i[1]"></el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-row>
|
||||
<el-row class="film-table-box table-box">
|
||||
<el-table :data="filmData" stripe class="film-table" v-loading="loading" size="mini">
|
||||
<el-table-column prop="name" label="影片名称"></el-table-column>
|
||||
<el-table-column prop="type" label="影片类别" width="120"></el-table-column>
|
||||
<el-table-column prop="time" label="更新时间" width="180"></el-table-column>
|
||||
<el-table-column label="操作" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="small" type="text" @click="tableBtnClick('detail', scope.row)">详情</el-button>
|
||||
<el-button size="small" type="text" @click="tableBtnClick('star', scope.row)">收藏</el-button>
|
||||
<el-button size="small" type="text" @click="tableBtnClick('play', scope.row)">播放</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-row>
|
||||
<el-row class="film-bottom" type="flex" justify="space-between">
|
||||
<el-select v-model="site" placeholder="请选择" size="small" @change="selectSite">
|
||||
<el-option
|
||||
v-for="(i, j) in sites"
|
||||
:key="i.id"
|
||||
:label="i.name"
|
||||
:value="j">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-pagination
|
||||
small
|
||||
layout="total, prev, pager, next, jumper"
|
||||
:current-page="filmPage"
|
||||
@current-change="pageChange"
|
||||
:page-size="50"
|
||||
:total="filmTotal">
|
||||
</el-pagination>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import zy from '@/lib/util.zy'
|
||||
import sites from '@/lib/sites'
|
||||
import { mapMutations } from 'vuex'
|
||||
import video from '@/plugins/dexie/video'
|
||||
export default Vue.extend({
|
||||
data () {
|
||||
return {
|
||||
sites: sites,
|
||||
tabs: '0',
|
||||
filmPage: 1,
|
||||
filmTotal: 0,
|
||||
filmData: [],
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
video: {
|
||||
get () {
|
||||
return this.$store.getters.getVideo
|
||||
},
|
||||
set (val) {
|
||||
this.SET_VIDEO(val)
|
||||
}
|
||||
},
|
||||
site: {
|
||||
get () {
|
||||
return this.$store.getters.getSite
|
||||
},
|
||||
set (val) {
|
||||
this.SET_SITE(val)
|
||||
}
|
||||
},
|
||||
Main: {
|
||||
get () {
|
||||
return this.$store.getters.getMain
|
||||
},
|
||||
set (val) {
|
||||
this.SET_MAIN(val)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SET_SITE', 'SET_DETAIL', 'SET_MAIN', 'SET_VIDEO']),
|
||||
tabClick (tab:any) {
|
||||
this.filmPage = 1
|
||||
this.getFilmList(this.site, this.filmPage, tab.name)
|
||||
},
|
||||
selectSite (e:any) {
|
||||
this.site = e
|
||||
this.tabs = '0'
|
||||
this.filmPage = 1
|
||||
this.getFilmList(e, 1, '0')
|
||||
},
|
||||
pageChange (e:number) {
|
||||
this.filmPage = e
|
||||
this.getFilmList(this.site, this.filmPage, this.tabs)
|
||||
},
|
||||
getFilmList (n: number = 0, p: number = 1, type: string = '0') {
|
||||
this.loading = true
|
||||
this.filmData = []
|
||||
this.tabs = type
|
||||
zy.films(n, p, type).then((res: any) => {
|
||||
this.filmTotal = res.total
|
||||
this.filmData = res.list
|
||||
this.filmPage = p
|
||||
this.loading = false
|
||||
}).catch((err: any) => {
|
||||
if (err.status === 1) {
|
||||
this.$message.warning('获取资源超时,请切换分类,或者切换源。')
|
||||
}
|
||||
})
|
||||
},
|
||||
tableBtnClick (type: string, e: any) {
|
||||
if (type === 'detail') {
|
||||
let d = {
|
||||
show: true,
|
||||
video: e
|
||||
}
|
||||
this.SET_DETAIL(d)
|
||||
}
|
||||
if (type === 'star') {
|
||||
video.find({ detail: e.detail }).then(res => {
|
||||
if (res) {
|
||||
this.$message.warning('已存在')
|
||||
} else {
|
||||
video.add(e).then(res => {
|
||||
this.$message.success('收藏成功')
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
if (type === 'play') {
|
||||
this.Main = 'Player'
|
||||
this.video = e
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getFilmList()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.film{
|
||||
height: 100%;
|
||||
position: relative;
|
||||
.film-tabs{
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
}
|
||||
.film-table-box{
|
||||
position: absolute;
|
||||
top: 54px;
|
||||
width: 100%;
|
||||
height: calc(100% - 100px);
|
||||
overflow: auto;
|
||||
&::-webkit-scrollbar{
|
||||
width: 6px;
|
||||
}
|
||||
}
|
||||
.film-bottom{
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
270
src/page/player.vue
Normal file
@@ -0,0 +1,270 @@
|
||||
<template>
|
||||
<el-row class="player">
|
||||
<el-row class="player-show" v-if="Object.keys(video).length > 0">
|
||||
<el-row class="player-title">
|
||||
<el-row class="player-title-box" type="flex" justify="space-between">
|
||||
<span>
|
||||
<span>{{video.name ? video.name + ' -- ' : '' }}</span>
|
||||
<span>{{ num }}</span>
|
||||
</span>
|
||||
<span>
|
||||
<el-button size="mini" @click="topEvent('top')" icon="el-icon-place" title="置顶" circle></el-button>
|
||||
<el-button size="mini" @click="openDetail" icon="el-icon-document" title="查看详情" circle></el-button>
|
||||
<el-button size="mini" v-show="!star" @click="starEvent" icon="el-icon-star-off" title="添加收藏" circle></el-button>
|
||||
<el-button size="mini" v-show="star" @click="starEvent" icon="el-icon-star-on" title="取消收藏" circle></el-button>
|
||||
<el-popover placement="bottom" width="150" trigger="click">
|
||||
<el-row id="qrcode"></el-row>
|
||||
<el-button v-show="xg !== null" size="mini" @click="mobileEvent" icon="el-icon-mobile-phone" title="手机观看" circle slot="reference" style="margin-left: 10px;"></el-button>
|
||||
</el-popover>
|
||||
</span>
|
||||
</el-row>
|
||||
</el-row>
|
||||
<el-row class="player-box">
|
||||
<div id="xg"></div>
|
||||
</el-row>
|
||||
<el-row class="player-films table-box">
|
||||
<el-row class="player-films-box">
|
||||
<el-button :type="j === video.index ? 'primary' : ''" size="mini" v-for="(i, j) in urls" :key="j" @click="playBtnClick(i, j)" plain>{{i | ftLink}}</el-button>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</el-row>
|
||||
<el-row class="player-none" v-if="Object.keys(video).length <= 0">
|
||||
<el-row class="tips">
|
||||
浏览或者搜索资源, 点击播放视频, 即可观看~
|
||||
</el-row>
|
||||
<el-row class="btns">
|
||||
<el-button size="small" @click="goView('Film')" icon="el-icon-film">浏览</el-button>
|
||||
<el-button size="small" @click="goView('Search')" icon="el-icon-search">搜索</el-button>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import { mapMutations } from 'vuex'
|
||||
import zy from '@/lib/util.zy'
|
||||
import 'xgplayer'
|
||||
// @ts-ignore
|
||||
import Hls from 'xgplayer-hls.js'
|
||||
import video from '@/plugins/dexie/video'
|
||||
import { qrcanvas } from 'qrcanvas'
|
||||
const { ipcRenderer: ipc } = require('electron')
|
||||
export default Vue.extend({
|
||||
data () {
|
||||
return {
|
||||
xg: null,
|
||||
config: {
|
||||
id: 'xg',
|
||||
url: '',
|
||||
cssFullscreen: true,
|
||||
fluid: false,
|
||||
autoplay: true,
|
||||
videoInit: true,
|
||||
keyShortcut: 'on',
|
||||
defaultPlaybackRate: 1,
|
||||
playbackRate: [0.5, 0.75, 1, 1.5, 2]
|
||||
},
|
||||
urls: [],
|
||||
num: '',
|
||||
star: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
d () {
|
||||
return this.$store.getters.getDetail
|
||||
},
|
||||
video: {
|
||||
get () {
|
||||
return this.$store.getters.getVideo
|
||||
},
|
||||
set (val) {
|
||||
this.SET_VIDEO(val)
|
||||
}
|
||||
},
|
||||
Main: {
|
||||
get () {
|
||||
return this.$store.getters.getMain
|
||||
},
|
||||
set (val) {
|
||||
this.SET_MAIN(val)
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
video: {
|
||||
handler () {
|
||||
this.getUrls()
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
ftLink (e: string) {
|
||||
let name = e.split('$')[0]
|
||||
return name
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SET_DETAIL', 'SET_VIDEO', 'SET_MAIN']),
|
||||
topEvent (e:string) {
|
||||
ipc.send(e)
|
||||
},
|
||||
goView (e: string) {
|
||||
this.Main = e
|
||||
},
|
||||
openDetail () {
|
||||
let d = {
|
||||
show: true,
|
||||
video: this.video
|
||||
}
|
||||
this.SET_DETAIL(d)
|
||||
},
|
||||
getUrls () {
|
||||
if (this.xg) {
|
||||
// @ts-ignore
|
||||
this.xg.destroy(true)
|
||||
this.xg = null
|
||||
}
|
||||
this.checkStar()
|
||||
zy.detail(this.video.detail).then((res: any) => {
|
||||
this.urls = res.urls
|
||||
if (this.xg === null) {
|
||||
let info: any = this.urls[this.video.index]
|
||||
let url = info.split('$')[1]
|
||||
this.num = info.split('$')[0]
|
||||
this.config.url = url
|
||||
this.$nextTick(() => {
|
||||
this.xg = new Hls(this.config)
|
||||
// @ts-ignore
|
||||
this.xg.on('ended', () => {
|
||||
if (this.urls.length > 1 && (this.urls.length - 1 > this.video.index)) {
|
||||
this.$message.success('自动播放下一集')
|
||||
this.video.index++
|
||||
let v: any = this.urls[this.video.index]
|
||||
let url = v.split('$')[1]
|
||||
this.num = v.split('$')[0]
|
||||
// @ts-ignore
|
||||
this.xg.src = url
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
checkStar () {
|
||||
video.find({ detail: this.video.detail }).then(res => {
|
||||
if (res) {
|
||||
this.star = true
|
||||
} else {
|
||||
this.star = false
|
||||
}
|
||||
})
|
||||
},
|
||||
starEvent () {
|
||||
video.find({ detail: this.video.detail }).then(res => {
|
||||
if (res) {
|
||||
video.remove(res.id).then(res => {
|
||||
if (!res) {
|
||||
this.$message.success('删除成功')
|
||||
this.star = false
|
||||
} else {
|
||||
this.$message.warning('删除失败, 请重试~')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
video.add(this.video).then(res => {
|
||||
this.star = true
|
||||
this.$message.success('收藏成功')
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
mobileEvent () {
|
||||
let info = this.urls[this.video.index]
|
||||
// @ts-ignore
|
||||
let time = this.xg.currentTime
|
||||
const canvas = qrcanvas({
|
||||
size: 120,
|
||||
data: `http://zy.hly120506.top/player/index.html?info=${info}&time=${time}`
|
||||
})
|
||||
const dom = document.getElementById('qrcode')
|
||||
if (dom) {
|
||||
dom.innerHTML = ''
|
||||
dom.appendChild(canvas)
|
||||
}
|
||||
},
|
||||
playBtnClick (i: string, j: number) {
|
||||
if (this.video.index !== j) {
|
||||
let url = i.split('$')[1]
|
||||
this.num = i.split('$')[0]
|
||||
this.video.index = j
|
||||
// @ts-ignore
|
||||
this.xg.src = url
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.player{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
.player-show{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
.player-none{
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
.tips{
|
||||
font-size: 14px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
.player-title{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
.player-title-box{
|
||||
width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
.player-box{
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 350px;
|
||||
#xg{
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
.player-films{
|
||||
position: absolute;
|
||||
top: 400px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: calc(100% - 400px);
|
||||
overflow: auto;
|
||||
button{
|
||||
margin: 0 10px 10px 0;
|
||||
}
|
||||
&::-webkit-scrollbar{
|
||||
width: 6px;
|
||||
}
|
||||
.player-films-box{
|
||||
width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
16
src/page/register.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import Vue from 'vue'
|
||||
import Film from './film.vue'
|
||||
import Search from './search.vue'
|
||||
import Player from './player.vue'
|
||||
import Star from './star.vue'
|
||||
import Setting from './setting.vue'
|
||||
|
||||
export default {
|
||||
registerComponents () {
|
||||
Vue.component('Film', Film)
|
||||
Vue.component('Search', Search)
|
||||
Vue.component('Player', Player)
|
||||
Vue.component('Star', Star)
|
||||
Vue.component('Setting', Setting)
|
||||
}
|
||||
}
|
||||
200
src/page/search.vue
Normal file
@@ -0,0 +1,200 @@
|
||||
<template>
|
||||
<el-row class="search">
|
||||
<el-row class="search-box" :class="table === true ? 'search-box hasTable' : 'search-box'">
|
||||
<el-input class="search-input" size="medium" clearable placeholder="请输入内容" v-model.trim="keywords" @change="searchEvent" @clear="clearEvent">
|
||||
<el-select v-model="site" slot="prepend" placeholder="请选择" @change="selectSite" style="width: 130px;">
|
||||
<el-option v-for="(i, j) in sites" :key="i.id" :label="i.name" :value="j"></el-option>
|
||||
</el-select>
|
||||
<el-button slot="append" icon="el-icon-search" @click="searchEvent"></el-button>
|
||||
</el-input>
|
||||
</el-row>
|
||||
<el-row v-show="table" class="search-table-box table-box">
|
||||
<el-table :data="filmData" stripe class="search-table" size="mini" v-loading="loading">
|
||||
<el-table-column prop="name" label="影片名称"></el-table-column>
|
||||
<el-table-column prop="type" label="影片类别" width="120"></el-table-column>
|
||||
<el-table-column prop="time" label="更新时间" width="180"></el-table-column>
|
||||
<el-table-column label="操作" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="small" type="text" @click="tableBtnClick('detail', scope.row)">详情</el-button>
|
||||
<el-button size="small" type="text" @click="tableBtnClick('star', scope.row)">收藏</el-button>
|
||||
<el-button size="small" type="text" @click="tableBtnClick('play', scope.row)">播放</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-row>
|
||||
<el-row v-show="table" class="search-bottom" type="flex" justify="end">
|
||||
<el-pagination
|
||||
small
|
||||
layout="total, prev, pager, next, jumper"
|
||||
:current-page="filmPage"
|
||||
:page-size="50"
|
||||
@current-change="pageChange"
|
||||
:total="filmTotal">
|
||||
</el-pagination>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import sites from '@/lib/sites'
|
||||
import zy from '@/lib/util.zy'
|
||||
import { mapMutations } from 'vuex'
|
||||
import video from '@/plugins/dexie/video'
|
||||
export default Vue.extend({
|
||||
data () {
|
||||
return {
|
||||
table: false,
|
||||
sites: sites,
|
||||
keywords: '',
|
||||
filmData: [],
|
||||
filmPage: 1,
|
||||
filmTotal: 0,
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
video: {
|
||||
get () {
|
||||
return this.$store.getters.getVideo
|
||||
},
|
||||
set (val) {
|
||||
this.SET_VIDEO(val)
|
||||
}
|
||||
},
|
||||
site: {
|
||||
get () {
|
||||
return this.$store.getters.getSite
|
||||
},
|
||||
set (val) {
|
||||
this.SET_SITE(val)
|
||||
}
|
||||
},
|
||||
Main: {
|
||||
get () {
|
||||
return this.$store.getters.getMain
|
||||
},
|
||||
set (val) {
|
||||
this.SET_MAIN(val)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SET_SITE', 'SET_DETAIL', 'SET_MAIN', 'SET_VIDEO']),
|
||||
selectSite (e:number) {
|
||||
this.site = e
|
||||
this.filmData = []
|
||||
this.filmPage = 1
|
||||
this.filmTotal = 0
|
||||
this.searchEvent()
|
||||
},
|
||||
searchEvent () {
|
||||
if (this.keywords !== '') {
|
||||
this.loading = true
|
||||
this.table = true
|
||||
zy.info(this.site, this.filmPage, this.keywords).then((res: any) => {
|
||||
this.filmData = res.list
|
||||
this.filmTotal = res.total
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
clearEvent () {
|
||||
this.loading = false
|
||||
this.filmData = []
|
||||
this.filmTotal = 0
|
||||
this.filmPage = 1
|
||||
this.table = false
|
||||
},
|
||||
pageChange (e:number) {
|
||||
this.filmPage = e
|
||||
this.searchEvent()
|
||||
},
|
||||
tableBtnClick (type: string, e: any) {
|
||||
if (type === 'detail') {
|
||||
let d = {
|
||||
show: true,
|
||||
video: e
|
||||
}
|
||||
this.SET_DETAIL(d)
|
||||
}
|
||||
if (type === 'star') {
|
||||
video.find({ detail: e.detail }).then(res => {
|
||||
if (res) {
|
||||
this.$message.warning('已存在')
|
||||
} else {
|
||||
video.add(e).then(res => {
|
||||
this.$message.success('收藏成功')
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
if (type === 'play') {
|
||||
this.Main = 'Player'
|
||||
this.video = e
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.search{
|
||||
height: 100%;
|
||||
position: relative;
|
||||
.search-box{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
animation: slideDown 0.6s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
height: 40px;
|
||||
}
|
||||
to{
|
||||
height: 90%;
|
||||
}
|
||||
}
|
||||
&.hasTable{
|
||||
animation: slideUp 0.2s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
|
||||
}
|
||||
@keyframes slideUp {
|
||||
from {
|
||||
height: 90%;
|
||||
opacity: 0;
|
||||
}
|
||||
to{
|
||||
height: 40px;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
.search-table-box{
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
width: 100%;
|
||||
height: calc(100% - 100px);
|
||||
overflow: auto;
|
||||
&::-webkit-scrollbar{
|
||||
width: 6px;
|
||||
}
|
||||
.search-table{
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.search-bottom{
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
229
src/page/setting.vue
Normal file
@@ -0,0 +1,229 @@
|
||||
<template>
|
||||
<el-row class="setting">
|
||||
<el-row class="setting-box table-box">
|
||||
<el-row class="item site">
|
||||
<el-row class="title"><i class="el-icon-set-up"></i><span>默认资源</span></el-row>
|
||||
<el-row class="info">
|
||||
<el-select v-model="dbSite" placeholder="请选择" size="small" @change="selectSite">
|
||||
<el-option
|
||||
v-for="(i, j) in sites"
|
||||
:key="i.id"
|
||||
:label="i.name"
|
||||
:value="j">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-row>
|
||||
</el-row>
|
||||
<el-row class="item opacity">
|
||||
<el-row class="title"><i class="el-icon-stopwatch"></i><span>透明度</span></el-row>
|
||||
<el-row class="info">
|
||||
<el-slider v-model="opacity" :min="50" :max="100" @input="setOpacity"></el-slider>
|
||||
</el-row>
|
||||
</el-row>
|
||||
<el-row class="item theme">
|
||||
<el-row class="title"><i class="el-icon-picture-outline-round"></i><span>主题</span></el-row>
|
||||
<el-row class="card-box">
|
||||
<el-card shadow="hover" class="card">
|
||||
<img src="@/assets/image/light.png" class="image" @click="selectTheme('light')">
|
||||
<span size="mini">Light</span>
|
||||
</el-card>
|
||||
<el-card shadow="hover" class="card">
|
||||
<img src="@/assets/image/dark.png" class="image" @click="selectTheme('dark')">
|
||||
<span size="mini">Dark</span>
|
||||
</el-card>
|
||||
</el-row>
|
||||
</el-row>
|
||||
<el-row class="item update">
|
||||
<el-row class="title"><i class="el-icon-refresh"></i><span>更新</span></el-row>
|
||||
<el-row class="info">
|
||||
<ul>
|
||||
<li>当前版本: {{oldVersion}}</li>
|
||||
<li>最新版本: {{newVersion}}</li>
|
||||
</ul>
|
||||
</el-row>
|
||||
<el-row class="btns">
|
||||
<el-button v-show="download" size="small" @click="linkOpen('https://github.com/Hunlongyu/ZY-Player/releases/latest')">下载更新</el-button>
|
||||
</el-row>
|
||||
</el-row>
|
||||
<el-row class="item about">
|
||||
<el-row class="title"><i class="el-icon-view"></i><span>关于</span></el-row>
|
||||
<el-row class="info">
|
||||
<ul>
|
||||
<li><el-link :underline="false" @click="linkOpen('http://zy.hly120506.top')">官网: ZY Player</el-link></li>
|
||||
<li><el-link :underline="false" @click="linkOpen('https://github.com/Hunlongyu/ZY-Player/issues')">反馈: Issues</el-link></li>
|
||||
</ul>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import sites from '@/lib/sites'
|
||||
import { mapMutations } from 'vuex'
|
||||
import { shell } from 'electron'
|
||||
import site from '@/plugins/dexie/site'
|
||||
import theme from '@/plugins/dexie/theme'
|
||||
import fly from 'flyio'
|
||||
const { ipcRenderer: ipc } = require('electron')
|
||||
export default Vue.extend({
|
||||
name: 'setting',
|
||||
data () {
|
||||
return {
|
||||
sites: sites,
|
||||
dbSite: 0,
|
||||
opacity: 100,
|
||||
oldVersion: 'v0.8.6',
|
||||
newVersion: '',
|
||||
download: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
site: {
|
||||
get () {
|
||||
return this.$store.getters.getSite
|
||||
},
|
||||
set (val) {
|
||||
this.SET_SITE(val)
|
||||
}
|
||||
},
|
||||
theme: {
|
||||
get () {
|
||||
return this.$store.getters.getTheme
|
||||
},
|
||||
set (val) {
|
||||
this.SET_THEME(val)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SET_SITE', 'SET_THEME']),
|
||||
linkOpen (e:string) {
|
||||
if (e) {
|
||||
shell.openExternal(e)
|
||||
}
|
||||
},
|
||||
initSetting () {
|
||||
site.find().then(res => {
|
||||
if (!res) {
|
||||
site.add({ site: 0 })
|
||||
} else {
|
||||
this.dbSite = res.site
|
||||
this.site = res.site
|
||||
}
|
||||
})
|
||||
theme.find().then(res => {
|
||||
if (!res) {
|
||||
theme.add({ theme: 'light' })
|
||||
} else {
|
||||
this.theme = res.theme
|
||||
}
|
||||
})
|
||||
},
|
||||
selectSite () {
|
||||
site.update({ site: this.dbSite }).then(res => {
|
||||
this.site = this.dbSite
|
||||
this.$message.success('设置默认资源成功~')
|
||||
}).catch(() => {
|
||||
this.$message.warning('设置默认资源失败~')
|
||||
})
|
||||
},
|
||||
selectTheme (e: string) {
|
||||
theme.update({ theme: e }).then(res => {
|
||||
this.theme = e
|
||||
this.$message.success('切换主题成功~')
|
||||
}).catch(() => {
|
||||
this.$message.warning('切换主题失败~')
|
||||
})
|
||||
},
|
||||
checkUpdate () {
|
||||
fly.get('https://api.github.com/repos/Hunlongyu/ZY-Player/releases/latest').then(res => {
|
||||
this.newVersion = res.data.tag_name
|
||||
if (res.data.tag_name !== this.oldVersion) {
|
||||
this.download = true
|
||||
} else {
|
||||
this.download = false
|
||||
}
|
||||
})
|
||||
},
|
||||
setOpacity () {
|
||||
ipc.send('opacity', this.opacity / 100)
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.initSetting()
|
||||
this.checkUpdate()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.setting{
|
||||
height: 100%;
|
||||
position: relative;
|
||||
.setting-box{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
&::-webkit-scrollbar{
|
||||
width: 6px;
|
||||
}
|
||||
}
|
||||
.item{
|
||||
margin-bottom: 20px;
|
||||
.title{
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
i{
|
||||
font-size: 24px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.about{
|
||||
ul{
|
||||
list-style: none;
|
||||
li{
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.update{
|
||||
ul{
|
||||
list-style: none;
|
||||
li{
|
||||
height: 30px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.opacity{
|
||||
.info{
|
||||
width: 196px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
}
|
||||
.theme{
|
||||
.card-box{
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
.card{
|
||||
width: 160px;
|
||||
margin-right: 20px;
|
||||
text-align: center;
|
||||
img{
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
}
|
||||
span{
|
||||
font-size: 14px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
128
src/page/star.vue
Normal file
@@ -0,0 +1,128 @@
|
||||
<template>
|
||||
<el-row class="star">
|
||||
<el-row class="star-table-box table-box">
|
||||
<el-table :data="filmData" stripe class="film-table" size="mini" empty-text="收藏夹里空空的~快去填满我吧~">
|
||||
<el-table-column prop="name" label="影片名称"></el-table-column>
|
||||
<el-table-column prop="type" label="影片类别" width="120"></el-table-column>
|
||||
<el-table-column prop="time" label="更新时间" width="180"></el-table-column>
|
||||
<el-table-column label="操作" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="small" type="text" @click="tableBtnClick('detail', scope.row)">详情</el-button>
|
||||
<el-button size="small" type="text" @click="tableBtnClick('delete', scope.row)">删除</el-button>
|
||||
<el-button size="small" type="text" @click="tableBtnClick('play', scope.row)">播放</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-row>
|
||||
<el-row class="star-bottom">
|
||||
<el-pagination
|
||||
small
|
||||
layout="total, prev, pager, next, jumper"
|
||||
:current-page="filmPage"
|
||||
:page-size="50"
|
||||
:total="filmTotal">
|
||||
</el-pagination>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import video from '@/plugins/dexie/video'
|
||||
import { mapMutations } from 'vuex'
|
||||
export default Vue.extend({
|
||||
data () {
|
||||
return {
|
||||
filmData: [],
|
||||
filmPage: 1,
|
||||
filmTotal: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
video: {
|
||||
get () {
|
||||
return this.$store.getters.getVideo
|
||||
},
|
||||
set (val) {
|
||||
this.SET_VIDEO(val)
|
||||
}
|
||||
},
|
||||
Main: {
|
||||
get () {
|
||||
return this.$store.getters.getMain
|
||||
},
|
||||
set (val) {
|
||||
this.SET_MAIN(val)
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
Main: {
|
||||
handler () {
|
||||
this.getAllStar()
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SET_DETAIL', 'SET_VIDEO', 'SET_MAIN']),
|
||||
getAllStar () {
|
||||
video.all().then(res => {
|
||||
this.filmData = res
|
||||
this.filmTotal = res.length
|
||||
})
|
||||
},
|
||||
tableBtnClick (type: string, e: any) {
|
||||
if (type === 'detail') {
|
||||
let d = {
|
||||
show: true,
|
||||
video: e
|
||||
}
|
||||
this.SET_DETAIL(d)
|
||||
}
|
||||
if (type === 'delete') {
|
||||
video.remove(e.id).then(res => {
|
||||
if (!res) {
|
||||
this.$message.success('删除成功')
|
||||
} else {
|
||||
this.$message.warning('删除失败, 请重试~')
|
||||
}
|
||||
this.getAllStar()
|
||||
})
|
||||
}
|
||||
if (type === 'play') {
|
||||
this.Main = 'Player'
|
||||
this.video = e
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getAllStar()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.star{
|
||||
height: 100%;
|
||||
position: relative;
|
||||
.star-table-box{
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
width: 100%;
|
||||
height: calc(100% - 40px);
|
||||
overflow: auto;
|
||||
&::-webkit-scrollbar{
|
||||
width: 6px;
|
||||
}
|
||||
}
|
||||
.star-bottom{
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,27 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
import 'view-design/dist/styles/iview.css'
|
||||
import {
|
||||
Layout, Sider, Header, Content, Row, Col,
|
||||
Icon, Button, Input, Select, Option, Table,
|
||||
Message, Notice, Page
|
||||
} from 'view-design'
|
||||
|
||||
Vue.component('Layout', Layout)
|
||||
Vue.component('Sider', Sider)
|
||||
Vue.component('Header', Header)
|
||||
Vue.component('Content', Content)
|
||||
Vue.component('Row', Row)
|
||||
Vue.component('Col', Col)
|
||||
Vue.component('Icon', Icon)
|
||||
Vue.component('Button', Button)
|
||||
Vue.component('Input', Input)
|
||||
Vue.component('Select', Select)
|
||||
Vue.component('Option', Option)
|
||||
Vue.component('Table', Table)
|
||||
Vue.component('Page', Page)
|
||||
|
||||
Vue.prototype.$Message = Message
|
||||
Vue.prototype.$Notice = Notice
|
||||
Vue.prototype.$Notice.config({
|
||||
top: 60
|
||||
})
|
||||
@@ -1,36 +0,0 @@
|
||||
import Nedb from 'nedb'
|
||||
|
||||
export default class {
|
||||
constructor () {
|
||||
this.db = null
|
||||
}
|
||||
|
||||
create (db) {
|
||||
const name = process.env.NODE_ENV === 'development' ? 'ZY-dev' : 'ZY'
|
||||
const database = {}
|
||||
|
||||
database.setting = new Nedb({
|
||||
filename: name + db.setting,
|
||||
autoload: true
|
||||
})
|
||||
database.video = new Nedb({
|
||||
filename: name + db.video,
|
||||
autoload: true
|
||||
})
|
||||
|
||||
return database
|
||||
}
|
||||
|
||||
init () {
|
||||
if (this.db) {
|
||||
return this.db
|
||||
}
|
||||
|
||||
this.db = this.create({
|
||||
setting: '-setting',
|
||||
video: '-video'
|
||||
})
|
||||
|
||||
return this.db
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import DB from './index'
|
||||
|
||||
const db = new DB()
|
||||
const connect = db.init()
|
||||
const setting = connect.setting
|
||||
|
||||
export default {
|
||||
add (data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
setting.insert(data, (err, docs) => {
|
||||
if (err) { reject(err) }
|
||||
resolve(docs)
|
||||
})
|
||||
})
|
||||
},
|
||||
find (data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
setting.find(data, (err, docs) => {
|
||||
if (err) { reject(err) }
|
||||
resolve(docs)
|
||||
})
|
||||
})
|
||||
},
|
||||
update (id, data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
setting.update({ _id: id }, { $set: data }, (err, docs) => {
|
||||
if (err) { reject(err) }
|
||||
resolve(docs)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
// import DB from './index'
|
||||
import DB from './index'
|
||||
|
||||
const db = new DB()
|
||||
const connect = db.init()
|
||||
const video = connect.video
|
||||
|
||||
export default {
|
||||
add (data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
video.insert(data, (err, docs) => {
|
||||
if (err) { reject(err) }
|
||||
resolve(docs)
|
||||
})
|
||||
})
|
||||
},
|
||||
find (data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
video.find(data, (err, docs) => {
|
||||
if (err) { reject(err) }
|
||||
resolve(docs)
|
||||
})
|
||||
})
|
||||
},
|
||||
update (id, data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
video.find({ _id: id }, { $set: data }, (err, docs) => {
|
||||
if (err) { reject(err) }
|
||||
resolve(docs)
|
||||
})
|
||||
})
|
||||
},
|
||||
remove (id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
video.remove({ _id: id }, {}, (err, docs) => {
|
||||
if (err) { reject(err) }
|
||||
resolve(docs)
|
||||
})
|
||||
})
|
||||
},
|
||||
removeAll () {
|
||||
return new Promise((resolve, reject) => {
|
||||
video.remove({}, { multi: true }, (err, docs) => {
|
||||
if (err) { reject(err) }
|
||||
resolve(docs)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
42
src/plugins/dexie/index.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import Dexie from 'dexie'
|
||||
|
||||
class ZYDB extends Dexie {
|
||||
theme: Dexie.Table<theme, number>
|
||||
site: Dexie.Table<site, number>
|
||||
video: Dexie.Table<video, number>
|
||||
|
||||
constructor () {
|
||||
super('ZYDB')
|
||||
this.version(1).stores({
|
||||
theme: '++id, theme',
|
||||
site: '++id, site',
|
||||
video: '++id, name, type, time, detail, urls, index'
|
||||
})
|
||||
|
||||
this.theme = this.table('theme')
|
||||
this.site = this.table('site')
|
||||
this.video = this.table('video')
|
||||
}
|
||||
}
|
||||
|
||||
export interface theme {
|
||||
id: number
|
||||
theme?: string
|
||||
}
|
||||
|
||||
export interface site {
|
||||
id: number
|
||||
site?: number
|
||||
}
|
||||
|
||||
export interface video {
|
||||
id?: number
|
||||
name?: string
|
||||
type?: string
|
||||
time?: string
|
||||
detail?: string
|
||||
urls?: Array<string>
|
||||
index?: number
|
||||
}
|
||||
|
||||
export default new ZYDB()
|
||||
33
src/plugins/dexie/site.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import db from './index'
|
||||
|
||||
export default {
|
||||
add (data: any): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.site.add(data).then(res => {
|
||||
resolve(res)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
find (): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.site.get(1).then((res: any) => {
|
||||
resolve(res)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
update (data: any): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.site.update(1, data).then(updated => {
|
||||
if (updated) {
|
||||
resolve(updated)
|
||||
} else {
|
||||
reject(updated)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
33
src/plugins/dexie/theme.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import db from './index'
|
||||
|
||||
export default {
|
||||
add (data: any): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.theme.add(data).then(res => {
|
||||
resolve(res)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
find (): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.theme.get(1).then((res: any) => {
|
||||
resolve(res)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
update (data: any): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.theme.update(1, data).then(updated => {
|
||||
if (updated) {
|
||||
resolve(updated)
|
||||
} else {
|
||||
reject(updated)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
69
src/plugins/dexie/video.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import db from './index'
|
||||
|
||||
export default {
|
||||
add (data: any): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.video.add(data).then(res => {
|
||||
resolve(res)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
find (data: any): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.video.get(data).then(res => {
|
||||
resolve(res)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
all (): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.video.toArray().then(res => {
|
||||
resolve(res)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
update (id: number, data: any): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.video.update(id, data).then(updated => {
|
||||
if (updated) {
|
||||
resolve(updated)
|
||||
} else {
|
||||
reject(updated)
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
count (): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.video.count().then(res => {
|
||||
resolve(res)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
remove (id: number) {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.video.delete(id).then(res => {
|
||||
resolve(res)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
clear () {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.video.clear().then(res => {
|
||||
resolve(res)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
32
src/plugins/element.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import Vue from 'vue'
|
||||
import {
|
||||
Container, Row, Col, Header, Aside, Main, Drawer,
|
||||
Tabs, TabPane, Button, Select, Option, Pagination,
|
||||
Table, TableColumn, Input, Card, Link, Loading,
|
||||
Notification, Message, Slider, Popover
|
||||
} from 'element-ui'
|
||||
|
||||
Vue.use(Container)
|
||||
Vue.use(Row)
|
||||
Vue.use(Col)
|
||||
Vue.use(Header)
|
||||
Vue.use(Aside)
|
||||
Vue.use(Main)
|
||||
Vue.use(Drawer)
|
||||
Vue.use(Tabs)
|
||||
Vue.use(TabPane)
|
||||
Vue.use(Button)
|
||||
Vue.use(Select)
|
||||
Vue.use(Option)
|
||||
Vue.use(Pagination)
|
||||
Vue.use(Table)
|
||||
Vue.use(TableColumn)
|
||||
Vue.use(Input)
|
||||
Vue.use(Card)
|
||||
Vue.use(Link)
|
||||
Vue.use(Loading)
|
||||
Vue.use(Slider)
|
||||
Vue.use(Popover)
|
||||
|
||||
Vue.prototype.$notify = Notification
|
||||
Vue.prototype.$message = Message
|
||||
@@ -1,37 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
import Router from 'vue-router'
|
||||
import Search from './views/Search.vue'
|
||||
|
||||
Vue.use(Router)
|
||||
|
||||
export default new Router({
|
||||
// mode: 'history',
|
||||
// base: process.env.BASE_URL,
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
name: 'search',
|
||||
component: Search
|
||||
},
|
||||
{
|
||||
path: '/detail',
|
||||
name: 'detail',
|
||||
component: () => import(/* webpackChunkName: "about" */ './views/Detail.vue')
|
||||
},
|
||||
{
|
||||
path: '/settings',
|
||||
name: 'settings',
|
||||
component: () => import(/* webpackChunkName: "about" */ './views/Settings.vue')
|
||||
},
|
||||
{
|
||||
path: '/play',
|
||||
name: 'play',
|
||||
component: () => import(/* webpackChunkName: "about" */ './views/Player.vue')
|
||||
},
|
||||
{
|
||||
path: '/collection',
|
||||
name: 'collection',
|
||||
component: () => import(/* webpackChunkName: "about" */ './views/Collection.vue')
|
||||
}
|
||||
]
|
||||
})
|
||||
13
src/shims-tsx.d.ts
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import Vue, { VNode } from 'vue'
|
||||
|
||||
declare global {
|
||||
namespace JSX {
|
||||
// tslint:disable no-empty-interface
|
||||
interface Element extends VNode {}
|
||||
// tslint:disable no-empty-interface
|
||||
interface ElementClass extends Vue {}
|
||||
interface IntrinsicElements {
|
||||
[elem: string]: any
|
||||
}
|
||||
}
|
||||
}
|
||||
4
src/shims-vue.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
declare module '*.vue' {
|
||||
import Vue from 'vue'
|
||||
export default Vue
|
||||
}
|
||||
57
src/store.js
@@ -1,57 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import setting from '@/plugin/nedb/setting'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
export default new Vuex.Store({
|
||||
state: {
|
||||
site: 0,
|
||||
theme: {
|
||||
id: '',
|
||||
color: 'light'
|
||||
},
|
||||
iconActive: 'search',
|
||||
video: {}
|
||||
},
|
||||
getters: {
|
||||
getSite: state => {
|
||||
return state.site
|
||||
},
|
||||
getTheme: state => {
|
||||
return state.theme
|
||||
},
|
||||
getIconActive: state => {
|
||||
return state.iconActive
|
||||
},
|
||||
getVideo: state => {
|
||||
return state.video
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
SET_SITE: (state, payload) => {
|
||||
state.site = payload
|
||||
},
|
||||
SET_THEME: (state, payload) => {
|
||||
state.theme = payload
|
||||
},
|
||||
SET_ICON_ACTIVE: (state, payload) => {
|
||||
state.iconActive = payload
|
||||
},
|
||||
SET_VIDEO: (state, payload) => {
|
||||
state.video = payload
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
changeTheme: ({ commit }, payload) => {
|
||||
setting.update(payload.id, { theme: payload.color }).then(res => {
|
||||
commit('SET_THEME', payload)
|
||||
})
|
||||
},
|
||||
changeSite: ({ commit }, payload) => {
|
||||
setting.update(payload.id, { site: payload.site }).then(res => {
|
||||
commit('SET_SITE', payload)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
54
src/store/index.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
export default new Vuex.Store({
|
||||
state: {
|
||||
Main: 'Film',
|
||||
site: 0,
|
||||
theme: 'light',
|
||||
detail: {
|
||||
show: false,
|
||||
video: ''
|
||||
},
|
||||
dUrl: '',
|
||||
video: {}
|
||||
},
|
||||
getters: {
|
||||
getMain: state => {
|
||||
return state.Main
|
||||
},
|
||||
getSite: state => {
|
||||
return state.site
|
||||
},
|
||||
getTheme: state => {
|
||||
return state.theme
|
||||
},
|
||||
getDetail: state => {
|
||||
return state.detail
|
||||
},
|
||||
getVideo: state => {
|
||||
return state.video
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
SET_MAIN: (state, payload) => {
|
||||
state.Main = payload
|
||||
},
|
||||
SET_SITE: (state, payload) => {
|
||||
state.site = payload
|
||||
},
|
||||
SET_THEME: (state, payload) => {
|
||||
state.theme = payload
|
||||
},
|
||||
SET_DETAIL: (state, payload) => {
|
||||
state.detail = payload
|
||||
},
|
||||
SET_VIDEO: (state, payload) => {
|
||||
state.video = payload
|
||||
}
|
||||
},
|
||||
actions: {},
|
||||
modules: {}
|
||||
})
|
||||
@@ -1,90 +0,0 @@
|
||||
<template>
|
||||
<Row class="collection">
|
||||
<div class="collectionBox">
|
||||
<Table stripe :columns="columns" :data="data" :loading="loading">
|
||||
<template slot-scope="{ row }" slot="action" >
|
||||
<Button size="small" @click="play(row)">Play</Button>
|
||||
<Button size="small" type="info" ghost @click="detailShow(row)">Detail</Button>
|
||||
<Button size="small" type="error" ghost @click="deleteLi(row)">Delete</Button>
|
||||
</template>
|
||||
</Table>
|
||||
</div>
|
||||
</Row>
|
||||
</template>
|
||||
<script>
|
||||
import db from '@/plugin/nedb/video'
|
||||
export default {
|
||||
name: 'collection',
|
||||
data () {
|
||||
return {
|
||||
columns: [
|
||||
{
|
||||
title: 'Name',
|
||||
key: 'name',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
title: 'Category',
|
||||
key: 'category',
|
||||
width: 120,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: 'Time',
|
||||
key: 'time',
|
||||
width: 180,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: 'Action',
|
||||
slot: 'action',
|
||||
align: 'center',
|
||||
width: 260
|
||||
}
|
||||
],
|
||||
data: [],
|
||||
loading: false,
|
||||
detail: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getList () {
|
||||
db.find().then(res => {
|
||||
this.data = res
|
||||
})
|
||||
},
|
||||
play (e) {
|
||||
this.$router.push({ name: 'play' })
|
||||
this.$store.commit('SET_ICON_ACTIVE', 'play')
|
||||
this.$store.commit('SET_VIDEO', e)
|
||||
},
|
||||
detailShow (e) {
|
||||
this.$store.commit('SET_ICON_ACTIVE', 'detail')
|
||||
this.$store.commit('SET_VIDEO', e)
|
||||
this.$router.push({ name: 'detail' })
|
||||
},
|
||||
deleteLi (e) {
|
||||
db.remove(e._id).then(res => {
|
||||
this.getList()
|
||||
})
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getList()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.collection{
|
||||
height: 100%;
|
||||
position: relative;
|
||||
.collectionBox{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
top: 0px;
|
||||
height: 100%;
|
||||
overflow: scroll;
|
||||
&::-webkit-scrollbar { display: none }
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,71 +0,0 @@
|
||||
<template>
|
||||
<div class="detail">
|
||||
<div v-show="box" class="detail-box" v-html="data.box"></div>
|
||||
<div v-show="box" class="detail-box" v-html="data.info"></div>
|
||||
<div v-show="box" class="detail-box">
|
||||
<Button v-for="(i, j) in data.urls" :key="j" @click="playBtn(i, j, video)">{{i | ftLink}}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import zy from '@/lib/util.zy'
|
||||
import { mapMutations } from 'vuex'
|
||||
export default {
|
||||
name: 'detail',
|
||||
data () {
|
||||
return {
|
||||
data: {
|
||||
box: null,
|
||||
info: null,
|
||||
m3u8: null
|
||||
},
|
||||
box: false
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
ftLink (e) {
|
||||
let name = e.split('$')[0]
|
||||
return name
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
video () {
|
||||
return this.$store.getters.getVideo
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations([
|
||||
'SET_VIDEO'
|
||||
]),
|
||||
async getDetail () {
|
||||
this.box = false
|
||||
let url = this.video.detail
|
||||
this.data = await zy.detail(url)
|
||||
this.video.urls = this.data.urls
|
||||
this.video.check = true
|
||||
this.box = true
|
||||
},
|
||||
playBtn (i, j, e) {
|
||||
this.video.index = j
|
||||
this.$store.commit('SET_VIDEO', this.video)
|
||||
this.$router.push({ name: 'play' })
|
||||
this.$store.commit('SET_ICON_ACTIVE', 'play')
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getDetail()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.detail{
|
||||
.btns{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.detail-box{
|
||||
button{
|
||||
margin: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,121 +0,0 @@
|
||||
<template>
|
||||
<Row class="player">
|
||||
<div class="title">{{ video.name }} -- {{ info }}</div>
|
||||
<div class="playerBox">
|
||||
<div id="xg"></div>
|
||||
</div>
|
||||
<div class="list">
|
||||
<Button v-for="(i, j) in video.urls" :key="j" @click="playBtn(i, j, video)">{{i | ftLink}}</Button>
|
||||
</div>
|
||||
</Row>
|
||||
</template>
|
||||
<script>
|
||||
import 'xgplayer'
|
||||
import Hls from 'xgplayer-hls.js'
|
||||
import zy from '@/lib/util.zy'
|
||||
// import haku from '@/lib/util.666zy'
|
||||
export default {
|
||||
name: 'player',
|
||||
data () {
|
||||
return {
|
||||
data: {},
|
||||
url: null,
|
||||
xg: null,
|
||||
info: '',
|
||||
config: {
|
||||
id: 'xg',
|
||||
url: null,
|
||||
fluid: true,
|
||||
autoplay: true,
|
||||
keyShortcut: 'on',
|
||||
defaultPlaybackRate: 1,
|
||||
playbackRate: [0.5, 0.75, 1, 1.5, 2]
|
||||
}
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
ftLink (e) {
|
||||
let name = e.split('$')[0]
|
||||
return name
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
video () {
|
||||
return this.$store.getters.getVideo
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
if (this.video.check) {
|
||||
let url = this.video.urls[this.video.index].split('$')[1]
|
||||
this.info = this.video.urls[this.video.index].split('$')[0]
|
||||
this.$nextTick(() => {
|
||||
this.playEvent(url)
|
||||
})
|
||||
} else {
|
||||
this.getDetail()
|
||||
}
|
||||
},
|
||||
async getDetail () {
|
||||
let d = this.video.detail
|
||||
let index = this.video.index
|
||||
this.data = await zy.detail(d)
|
||||
let urls = this.data.urls
|
||||
this.video.urls = urls
|
||||
this.video.check = true
|
||||
let playUrl = urls[index].split('$')[1]
|
||||
this.info = urls[index].split('$')[0]
|
||||
this.$nextTick(() => {
|
||||
this.playEvent(playUrl)
|
||||
})
|
||||
},
|
||||
playEvent (e) {
|
||||
this.config.url = e
|
||||
this.xg = new Hls(this.config)
|
||||
},
|
||||
playBtn (i, j, e) {
|
||||
this.video.index = j
|
||||
let url = this.video.urls[this.video.index].split('$')[1]
|
||||
this.info = this.video.urls[this.video.index].split('$')[0]
|
||||
this.xg.src = url
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.init()
|
||||
},
|
||||
destroyed () {
|
||||
this.xg.destroy()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.player{
|
||||
padding: 10px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
.title{
|
||||
margin-bottom: 8px;
|
||||
font-size: 18px;
|
||||
text-align: left;
|
||||
width: 800px;
|
||||
}
|
||||
.playerBox{
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
border: 1px solid #000;
|
||||
}
|
||||
.list{
|
||||
margin-top: 10px;
|
||||
width: 800px;
|
||||
text-align: left;
|
||||
button{
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,221 +0,0 @@
|
||||
<template>
|
||||
<div class="search">
|
||||
<div :class="active ? 'search-top haveList': 'search-top'" >
|
||||
<Input class="search-input" v-model.trim="txt" size="large" search placeholder="输入需要搜索的资源名称..." @on-search="searchEvent" clearable @on-clear="searchClear">
|
||||
<Select slot="prepend" v-model="site" style="width: 120px;">
|
||||
<Option v-for="(i, j) in sites" :key="j" :value="j">{{i.name}}</Option>
|
||||
</Select>
|
||||
<!-- eslint-disable-next-line -->
|
||||
</Input>
|
||||
</div>
|
||||
<div class="search-middle" v-if="active">
|
||||
<Table stripe :columns="columns" :data="data" :loading="loading">
|
||||
<template slot-scope="{ row }" slot="action" >
|
||||
<Button size="small" @click="play(row)">Play</Button>
|
||||
<Button size="small" @click="collection(row)">Star</Button>
|
||||
<Button size="small" @click="detail(row)">Detail</Button>
|
||||
</template>
|
||||
</Table>
|
||||
</div>
|
||||
<div class="search-bottom" v-if="active">
|
||||
<Page :total="num" :current.sync="page" :page-size="50" show-total @on-change="onChange" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import db from '@/plugin/nedb/video'
|
||||
import zy from '@/lib/util.zy'
|
||||
import sites from '@/lib/sites'
|
||||
import { mapGetters, mapMutations } from 'vuex'
|
||||
export default {
|
||||
name: 'search',
|
||||
data () {
|
||||
return {
|
||||
sites: sites,
|
||||
txt: '',
|
||||
active: false,
|
||||
columns: [
|
||||
{
|
||||
title: 'Name',
|
||||
key: 'name',
|
||||
minWidth: 240
|
||||
},
|
||||
{
|
||||
title: 'Category',
|
||||
key: 'category',
|
||||
width: 100,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: 'Time',
|
||||
key: 'time',
|
||||
width: 110,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: 'Action',
|
||||
slot: 'action',
|
||||
align: 'center',
|
||||
width: 260
|
||||
}
|
||||
],
|
||||
data: [],
|
||||
page: 1,
|
||||
num: 0,
|
||||
loading: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['getVideo']),
|
||||
...mapGetters({
|
||||
getSite: 'getSite'
|
||||
}),
|
||||
site: {
|
||||
get () {
|
||||
return this.getSite
|
||||
},
|
||||
set (val) {
|
||||
this.SET_SITE(val)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SET_SITE']),
|
||||
async searchEvent () {
|
||||
if (this.txt !== '') {
|
||||
this.active = true
|
||||
this.loading = true
|
||||
this.page = 1
|
||||
let z = await zy.info(this.site, this.page, this.txt)
|
||||
this.data = z.list
|
||||
this.num = z.num
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
searchClear () {
|
||||
this.txt = ''
|
||||
this.active = false
|
||||
this.loading = true
|
||||
},
|
||||
async onChange () {
|
||||
let z = await zy.info(this.site, this.page, this.txt)
|
||||
this.data = z.list
|
||||
this.num = z.num
|
||||
},
|
||||
play (e) {
|
||||
if (this.getVideo.detail !== e.detail) {
|
||||
this.$store.commit('SET_VIDEO', e)
|
||||
}
|
||||
this.$store.commit('SET_ICON_ACTIVE', 'play')
|
||||
this.$router.push({ name: 'play' })
|
||||
},
|
||||
async collection (e) {
|
||||
let d = await zy.detail(e.detail)
|
||||
let data = {
|
||||
category: e.category,
|
||||
detail: e.detail,
|
||||
name: e.name,
|
||||
time: e.time,
|
||||
type: 'single',
|
||||
index: 0,
|
||||
urls: [],
|
||||
check: false
|
||||
}
|
||||
data.urls = d.urls
|
||||
data.check = true
|
||||
this.$store.commit('SET_VIDEO', data)
|
||||
db.find({ detail: data.detail }).then(res => {
|
||||
if (res.length >= 1) {
|
||||
this.$Notice.warning({
|
||||
title: '资源已存在',
|
||||
backgroud: true
|
||||
})
|
||||
} else {
|
||||
db.add(data).then(res => {
|
||||
this.$Notice.success({
|
||||
title: '收藏成功',
|
||||
backgroud: true
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
detail (e) {
|
||||
this.$store.commit('SET_VIDEO', e)
|
||||
this.$store.commit('SET_ICON_ACTIVE', 'detail')
|
||||
this.$router.push({ name: 'detail' })
|
||||
}
|
||||
},
|
||||
created () {
|
||||
// this.sites = sites
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.search{
|
||||
height: 100%;
|
||||
position: relative;
|
||||
.search-top{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 60px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
animation: slideDown 0.6s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
|
||||
.search-input{
|
||||
width: 80%;
|
||||
}
|
||||
&.haveList{
|
||||
animation: slideUp 0.4s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
|
||||
}
|
||||
@keyframes slideUp {
|
||||
from {
|
||||
height: 100%;
|
||||
}
|
||||
to{
|
||||
height: 60px;
|
||||
}
|
||||
}
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
height: 60px;
|
||||
}
|
||||
to{
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.search-middle{
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
width: 100%;
|
||||
height: calc(100% - 120px);
|
||||
padding: 10px;
|
||||
overflow: scroll;
|
||||
&::-webkit-scrollbar { display: none }
|
||||
animation: fade-in 1.4s cubic-bezier(0.390, 0.575, 0.565, 1.000) both;
|
||||
}
|
||||
@keyframes fade-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.search-bottom{
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
padding: 0 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,62 +0,0 @@
|
||||
<template>
|
||||
<Row class="setting">
|
||||
<div class="item about">
|
||||
<div class="title">关于:</div>
|
||||
<ul>
|
||||
<li>作者: <a href="https://github.com/Hunlongyu">Hunlongyu</a></li>
|
||||
<li>官网: <a href="https://zy_player.hunlongyu.fun">ZY Player</a></li>
|
||||
<li>反馈: <a href="https://github.com/Hunlongyu/ZY-Player/issues">Issues</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="item upgrade">
|
||||
<div class="title">更新:</div>
|
||||
<div class="btns">版本: v0.6.3</div>
|
||||
<div class="btns"><Button @click="checkUpgrade">检查更新</Button></div>
|
||||
</div>
|
||||
<div class="item theme">
|
||||
<div class="title">主题:</div>
|
||||
<div class="btns">
|
||||
<Button @click="changeTheme({ id: getTheme.id, color: 'light' })">light</Button>
|
||||
<Button @click="changeTheme({ id: getTheme.id, color: 'dark' })">Dark</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Row>
|
||||
</template>
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex'
|
||||
export default {
|
||||
name: 'settings',
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'getTheme'
|
||||
])
|
||||
},
|
||||
methods: {
|
||||
...mapActions([
|
||||
'changeTheme'
|
||||
]),
|
||||
checkUpgrade () {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.setting{
|
||||
padding: 10px;
|
||||
.item{
|
||||
margin-bottom: 10px;
|
||||
.title{
|
||||
font-size: 16px;
|
||||
}
|
||||
ul{
|
||||
margin-left: 10px;
|
||||
list-style: none;
|
||||
}
|
||||
.btns{
|
||||
margin-left: 10px;
|
||||
button{
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
39
tsconfig.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
"importHelpers": true,
|
||||
"moduleResolution": "node",
|
||||
"experimentalDecorators": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"sourceMap": true,
|
||||
"baseUrl": ".",
|
||||
"types": [
|
||||
"webpack-env"
|
||||
],
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
},
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"scripthost"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.vue",
|
||||
"tests/**/*.ts",
|
||||
"tests/**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
@@ -3,10 +3,7 @@ module.exports = {
|
||||
electronBuilder: {
|
||||
builderOptions: {
|
||||
win: {
|
||||
icon: './public/app.ico'
|
||||
},
|
||||
mac: {
|
||||
icon: './public/app.png'
|
||||
icon: './build/icons/icon.ico'
|
||||
},
|
||||
productName: 'ZY Player',
|
||||
publish: ['github']
|
||||
|
||||