Compare commits

...

90 Commits

Author SHA1 Message Date
buvta
27773be1c7 v2.6.9 2020-12-08 18:26:05 +08:00
buvta
fadb50a28b film调整areas刷新策略 2020-12-08 18:14:21 +08:00
buvta
518a9c3492 播放视频开始时重置片头片尾输入框数据 2020-12-08 17:36:33 +08:00
buvta
d5eb4dc49f film搜索不加载工具栏开关 2020-12-08 16:48:27 +08:00
buvta
e76bee574f film避免列表模式下加载图片 2020-12-08 16:46:02 +08:00
buvta
b7779a3e6f 疑似el-select弹窗bug,临时性修补 2020-12-08 15:45:25 +08:00
buvta
4cb5b48985 收起工具栏时重置列表 2020-12-08 15:37:21 +08:00
buvta
b2128113ba 调整工具栏refreshFilteredList触发方式 2020-12-08 15:24:36 +08:00
buvta
58d0ae6da1 工具栏"语言"替换为"排序" 2020-12-08 13:03:58 +08:00
buvta
2bd821f59d 调整工具栏打开方式 2020-12-08 12:20:12 +08:00
haiyangcui
8d002225fd 添加'过滤器'按钮,控制过滤选项按钮组的显示 2020-12-07 16:47:45 +01:00
haiyangcui
0243c2f0fe Fix: 切换类型时,总是调用refreshFilteredList 2020-12-07 16:28:30 +01:00
buvta
b8edd7f440 Revert "fix:海报模式切换分类时偶尔空白页"
This reverts commit 1df6726a3b.
2020-12-07 20:22:22 +08:00
buvta
4683aecf7b fix:上层弹窗被过滤工具栏遮蔽 2020-12-07 20:22:22 +08:00
buvta
16d38ba2b4 调整相应样式 2020-12-07 19:43:36 +08:00
buvta
fe7fe06d48 film添加过滤工具栏 2020-12-07 19:43:36 +08:00
buvta
c1220ef752 手动设置跳过片头片尾时间长度 2020-12-07 07:01:22 +08:00
buvta
f0c221a863 修复福利屏蔽 2020-12-06 18:40:18 +08:00
buvta
1df6726a3b fix:海报模式切换分类时偶尔空白页 2020-12-06 18:29:45 +08:00
buvta
1a9e939f9c 更新直播源 2020-12-06 15:53:55 +08:00
buvta
39cb188604 调整iptv分组命名规则 2020-12-06 15:53:13 +08:00
buvta
aba4d12302 确保不会意外引入代理 2020-12-05 23:54:29 +08:00
buvta
17c77fd48a 禁止xgplayer显示重播 2020-12-05 23:48:24 +08:00
buvta
1cfc12ec19 fix:确保不会跳过多集 2020-12-05 23:46:03 +08:00
buvta
b0aa1dc28a 视频多集时可通过快捷键设置跳过片头片尾,保存在相应的历史记录中 2020-12-05 19:10:05 +08:00
haiyangcui
0c12b394a7 视频列表页,支持按地区过滤数据 2020-12-04 14:06:30 +01:00
haiyangcui
9e468bc82e 在类型框内显示视频数信息 2020-12-04 13:48:31 +01:00
haiyangcui
973a15b593 统一downloadEvent函数 2020-12-02 15:19:50 +01:00
Hunlongyu
253c1e7723 分享的网址改为 gitee, 国内用户打开更快 2020-12-02 10:21:54 +08:00
Hunlongyu
7b44051190 更新官网截图,, 修改部分描述 2020-12-02 10:19:12 +08:00
Hunlongyu
a25ac77ebc 更新 README 2020-12-02 10:02:42 +08:00
haiyangcui
d187167fbe 解决换源时视频类型不正常更新的问题 2020-12-01 16:01:47 +01:00
haiyangcui
b34347cf43 添加视频数信息 2020-12-01 13:20:50 +01:00
haiyangcui
829d9447a4 删除重复和不可用的源站 2020-12-01 13:07:11 +01:00
haiyangcui
39067c6a35 缓存视频列表信息 2020-12-01 00:24:38 +01:00
haiyangcui
6dbb64a4f2 重构 2020-11-30 23:58:12 +01:00
haiyangcui
f8041290d2 无需定义getPage函数 2020-11-30 23:49:56 +01:00
haiyangcui
f772ac2e9d 从搜索界面返回时,无需再重新加载数据 2020-11-30 17:13:10 +01:00
haiyangcui
ef485ef64a 删除无用代码 2020-11-30 16:48:43 +01:00
haiyangcui
b164d5e83e Revert "降级xgplayer回2.13.1,新版居然不支持缓冲了."
This reverts commit 8cd2b920c8.
2020-11-30 15:48:13 +01:00
haiyangcui
8a5800df93 v2.6.8 2020-11-30 12:37:40 +01:00
haiyangcui
8cd2b920c8 降级xgplayer回2.13.1,新版居然不支持缓冲了. 2020-11-30 11:37:13 +01:00
haiyangcui
5b4cb43aa5 如果源站返回多个视频列表的话, 仅获取m3u8列表 2020-11-30 11:21:55 +01:00
haiyangcui
de1472e668 升级依赖 2020-11-30 10:56:24 +01:00
haiyangcui
0f846b996b 设置播放器默认预加载300秒 2020-11-29 20:11:23 +01:00
cuiocean
2bd5e31a28 Merge pull request #362 from Hunlongyu/dependabot/npm_and_yarn/highlight.js-9.18.5
Bump highlight.js from 9.18.1 to 9.18.5
2020-11-29 20:04:32 +01:00
haiyangcui
9d8dc9ecb1 删除不工作的cctv蓝光源 2020-11-29 16:53:24 +01:00
haiyangcui
2a073e4092 v2.6.7 2020-11-29 16:26:37 +01:00
haiyangcui
b1daa73afe 更新推荐 2020-11-29 16:23:15 +01:00
haiyangcui
18940ff9f7 Revert "更新视频源,删除无效源,添加需要解析的腾讯,搜狐视频等源"
This reverts commit 76d4d68401.
2020-11-29 13:27:20 +01:00
haiyangcui
76d4d68401 更新视频源,删除无效源,添加需要解析的腾讯,搜狐视频等源 2020-11-28 13:00:29 +01:00
haiyangcui
f91200e609 非m3u8视频,使用在线解析网站播放 2020-11-28 12:46:10 +01:00
haiyangcui
b64f500710 Download函数内解析m3u8List,改进downloadEvent函数 2020-11-28 12:30:43 +01:00
haiyangcui
cf1cfe9f77 支持某些源返回json数据不包含rss层 2020-11-28 11:47:48 +01:00
Hunlongyu
da4fe162f6 Merge branch 'master' of https://github.com/Hunlongyu/ZY-Player into master 2020-11-28 09:44:37 +08:00
Hunlongyu
d949c52020 代码优化 2020-11-28 09:44:32 +08:00
buvta
1ce9e0525b Merge branch 'master' into master 2020-11-25 23:38:06 +08:00
dependabot[bot]
4ebf82eae0 Bump highlight.js from 9.18.1 to 9.18.5
Bumps [highlight.js](https://github.com/highlightjs/highlight.js) from 9.18.1 to 9.18.5.
- [Release notes](https://github.com/highlightjs/highlight.js/releases)
- [Changelog](https://github.com/highlightjs/highlight.js/blob/9.18.5/CHANGES.md)
- [Commits](https://github.com/highlightjs/highlight.js/compare/9.18.1...9.18.5)

Signed-off-by: dependabot[bot] <support@github.com>
2020-11-25 06:15:54 +00:00
buvta
e0b1a5332d iptv优化 2020-11-24 22:27:49 +08:00
buvta
3ecb4302ba iptv优化 2020-11-24 16:46:29 +08:00
buvta
5c39db8ca6 iptv恢复"播放",避免行点击时误操作 2020-11-23 16:34:53 +08:00
buvta
4f45045d18 精简模式alt+m切换进入退出 2020-11-23 16:34:53 +08:00
buvta
b7733179f2 导入直播源时允许网址带参数 2020-11-23 16:34:53 +08:00
haiyangcui
e1f7044ae0 数据更新后,刷新页面 2020-11-22 20:57:27 +01:00
buvta
93e76db444 恢复记录mini窗口状态
This reverts commit bedd1339df.
2020-11-22 23:48:50 +08:00
buvta
6eaa281e4a 直播主窗口隐藏退出mini图标 2020-11-22 23:31:30 +08:00
buvta
490d34e1fb 移除iptvSearch数据库 2020-11-22 22:39:42 +08:00
buvta
0d0d6bd90f iptv移除iptvSearch 2020-11-22 22:35:48 +08:00
buvta
ecdc96d2f3 Play样式相应调整 2020-11-22 22:35:48 +08:00
buvta
234f6dd069 Play频道搜索用el-input替代 2020-11-22 22:35:38 +08:00
haiyangcui
f80fe7ecf1 添加退出精简模式按钮 2020-11-22 14:37:30 +01:00
haiyangcui
6876721567 进入精简模式,无需设置大小位置,直接调用getCssFullscreen即可 2020-11-22 12:41:22 +01:00
haiyangcui
bedd1339df Revert "记录mini窗口大小" 2020-11-22 12:09:36 +01:00
hunlongyu
0a3a7a4d57 Merge branch 'master' of https://github.com/Hunlongyu/ZY-Player 2020-11-22 16:38:49 +08:00
hunlongyu
786e23f5a2 删除冗余代码 2020-11-22 16:38:43 +08:00
buvta
418f14bcc1 调整Ctrl+0描述(弹窗容不下) 2020-11-22 11:20:00 +08:00
buvta
a9e4a34e4f 精简模式添加快捷键Ctrl+0用于恢复默认 2020-11-22 10:56:30 +08:00
buvta
fede7e4ef2 Revert "mini模式,大小直接设置为当前窗口大小,无需记录到数据库中"
This reverts commit f92af48a4e.
2020-11-22 10:41:19 +08:00
buvta
956ebbf8b8 调整Play页面channelList加载策略 2020-11-22 10:32:26 +08:00
haiyangcui
014dac0b64 排序源站,把可用的放上面 2020-11-21 23:37:05 +01:00
haiyangcui
5fc1020e79 升级所有依赖到最新版 2020-11-21 22:48:44 +01:00
haiyangcui
aca487f796 升级依赖 2020-11-21 22:41:09 +01:00
haiyangcui
429eb4aac0 移动getChannelList到if里,避免不必要的开销 2020-11-21 22:27:26 +01:00
haiyangcui
e032f86d3d 切换视图时,无需更新页面和改变infiniteId 2020-11-21 22:16:06 +01:00
haiyangcui
f92af48a4e mini模式,大小直接设置为当前窗口大小,无需记录到数据库中 2020-11-21 19:07:05 +01:00
haiyangcui
eff69db063 infiniteId会在classClick里更新 2020-11-21 18:52:33 +01:00
haiyangcui
a5c8d20635 更新麻花资源的api链接 2020-11-21 18:39:33 +01:00
haiyangcui
da22abd25d 避免不必要的资源访问 2020-11-21 18:38:53 +01:00
haiyangcui
2dd91f78c9 牛牛资源已失效,删除 2020-11-21 18:38:51 +01:00
buvta
a8b0e7e6a8 fix:直播时上下切换频道时的bug 2020-11-21 23:20:17 +08:00
46 changed files with 4613 additions and 2371 deletions

View File

@@ -46,6 +46,17 @@
- 🍉 [蓝奏云 -- 快速下载](https://www.lanzoux.com/b04s6a3re) 密码:95px
- 🍒 适用于32位操作系统的x86软件,在蓝奏云网盘里, 后缀名: ZY Player * 32位.exe
### 🎠 平台
| 平台 | 链接 |
| :------------------------------------ | :---------------------------------------------------------- |
| 🖥️ 电脑端 ( Windows & Mac & Linux ) | [ZY Player](https://github.com/Hunlongyu/ZY-Player) |
| 📱 手机端 ( Android & IOS ) | [ZY Player APP](https://github.com/Hunlongyu/ZY-Player-APP) |
| 📺 电视端 ( Android & Mac ) ( 进行中 ) | [ZY Player TV](https://github.com/cuiocean/ZY-Player-TV) |
| 🌐 浏览器 ( Web ) | [ZY Player Web](https://github.com/Hunlongyu/ZY-Player-Web) |
### 🚀 快捷键
播放窗口 和 Mini窗口
@@ -81,7 +92,8 @@
### 🍭 开发者
| [Hunlongyu](https://github.com/Hunlongyu) | [cuiocean](https://github.com/cuiocean) |
| :----------------------------------------------------------: | :----------------------------------------------------------: |
| <img width="120" src="https://avatars2.githubusercontent.com/u/15273630?s=460&u=48cf3299e2a842c0252233d8be42ef4c5d792138&v=4"/> | <img width="120" src="https://avatars0.githubusercontent.com/u/5760235?s=460&u=9d969dd8d83f069ce7ebd60516770c93ac07a330&v=4" /> |
| 💻 🎨 🐛 | 💻 🐛 |
| [Hunlongyu](https://github.com/Hunlongyu) | [cuiocean](https://github.com/cuiocean) | [buvta](https://github.com/buvta) |
| :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: |
| <img width="120" src="https://avatars2.githubusercontent.com/u/15273630?s=460&u=48cf3299e2a842c0252233d8be42ef4c5d792138&v=4"/> | <img width="120" src="https://avatars0.githubusercontent.com/u/5760235?s=460&u=9d969dd8d83f069ce7ebd60516770c93ac07a330&v=4" /> | <img width="120" src="https://avatars3.githubusercontent.com/u/12312540?s=400&v=4" /> |
| 💻 🎨 🐛 | 💻 🐛 | 💻 🐛 |

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 944 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 927 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 691 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@@ -89,7 +89,7 @@
<div class="section-title">
<h2>软件特色</h2>
<p>经过三个大版本更迭, 软件功能丰富, 操作简单.</p>
<p>软件功能丰富, 操作简单.</p>
</div>
<div class="row no-gutters">
@@ -99,7 +99,7 @@
<div class="col-md-6 icon-box" data-aos="fade-up">
<i class="bx bx-receipt"></i>
<h4>浏览</h4>
<p>浏览全网热门视频, 支持切换视频源. 详细的电影分类.支持搜索电影名和演员名称. </p>
<p>浏览全网热门视频, 支持切换视频源. 详细的电影分类. </p>
</div>
<div class="col-md-6 icon-box" data-aos="fade-up" data-aos-delay="100">
<i class="icofont-play-alt-3"></i>
@@ -124,7 +124,7 @@
<div class="col-md-6 icon-box" data-aos="fade-up" data-aos-delay="500">
<i class="icofont-cubes"></i>
<h4>其他</h4>
<p>多主题, 多语言, 自动更新</p>
<p>多主题, 自动更新</p>
</div>
</div>
</div>
@@ -146,14 +146,14 @@
</div>
<div class="owl-carousel gallery-carousel" data-aos="fade-up">
<a href="assets/img/gallery/001.png" class="venobox" data-gall="gallery-carousel"><img src="assets/img/gallery/001.png" alt=""></a>
<a href="assets/img/gallery/002.png" class="venobox" data-gall="gallery-carousel"><img src="assets/img/gallery/002.png" alt=""></a>
<a href="assets/img/gallery/003.png" class="venobox" data-gall="gallery-carousel"><img src="assets/img/gallery/003.png" alt=""></a>
<a href="assets/img/gallery/004.png" class="venobox" data-gall="gallery-carousel"><img src="assets/img/gallery/004.png" alt=""></a>
<a href="assets/img/gallery/005.png" class="venobox" data-gall="gallery-carousel"><img src="assets/img/gallery/005.png" alt=""></a>
<a href="assets/img/gallery/006.png" class="venobox" data-gall="gallery-carousel"><img src="assets/img/gallery/006.png" alt=""></a>
<a href="assets/img/gallery/007.png" class="venobox" data-gall="gallery-carousel"><img src="assets/img/gallery/007.png" alt=""></a>
<a href="assets/img/gallery/008.png" class="venobox" data-gall="gallery-carousel"><img src="assets/img/gallery/008.png" alt=""></a>
<a href="assets/img/gallery/01.png" class="venobox" data-gall="gallery-carousel"><img src="assets/img/gallery/01.png" alt=""></a>
<a href="assets/img/gallery/02.png" class="venobox" data-gall="gallery-carousel"><img src="assets/img/gallery/02.png" alt=""></a>
<a href="assets/img/gallery/03.png" class="venobox" data-gall="gallery-carousel"><img src="assets/img/gallery/03.png" alt=""></a>
<a href="assets/img/gallery/04.png" class="venobox" data-gall="gallery-carousel"><img src="assets/img/gallery/04.png" alt=""></a>
<a href="assets/img/gallery/05.png" class="venobox" data-gall="gallery-carousel"><img src="assets/img/gallery/05.png" alt=""></a>
<a href="assets/img/gallery/06.png" class="venobox" data-gall="gallery-carousel"><img src="assets/img/gallery/06.png" alt=""></a>
<a href="assets/img/gallery/07.png" class="venobox" data-gall="gallery-carousel"><img src="assets/img/gallery/07.png" alt=""></a>
<a href="assets/img/gallery/08.png" class="venobox" data-gall="gallery-carousel"><img src="assets/img/gallery/08.png" alt=""></a>
</div>
</div>
@@ -193,7 +193,7 @@
<i class="bx bx-help-circle icon-help"></i> <a data-toggle="collapse" href="#accordion-list-3" class="collapsed">跨平台<i class="bx bx-chevron-down icon-show"></i><i class="bx bx-chevron-up icon-close"></i></a>
<div id="accordion-list-3" class="collapse" data-parent=".accordion-list">
<p>
目前支持 Windows, Mac, Linux 桌面系统. 暂不支持手机端或者电视端. 未来会考虑实现全平台.
目前支持 Windows, Mac, Linux, Android, IOS, TV, Web 全平台.
</p>
</div>
</li>

View File

@@ -1,6 +1,6 @@
{
"name": "zy",
"version": "2.6.6",
"version": "2.6.9",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
@@ -19,13 +19,13 @@
"dependencies": {
"axios": "^0.21.0",
"cheerio": "^1.0.0-rc.3",
"core-js": "^3.7.0",
"core-js": "^3.8.0",
"cors": "^2.8.5",
"dexie": "^3.0.2",
"dexie": "^3.0.3",
"electron-localshortcut": "^3.2.1",
"electron-proxy-agent": "^1.2.0",
"electron-updater": "^4.3.5",
"element-ui": "^2.14.0",
"element-ui": "^2.14.1",
"express": "^4.17.1",
"fast-xml-parser": "^3.17.4",
"html2canvas": "^1.0.0-rc.7",
@@ -46,29 +46,29 @@
"vue-infinite-loading": "^2.4.5",
"vue-waterfall-plugin": "^1.1.0",
"vuedraggable": "^2.24.3",
"vuex": "^3.5.1",
"xgplayer": "^2.13.0",
"vuex": "^3.6.0",
"xgplayer": "^2.13.2",
"xgplayer-hls.js": "^2.2.5"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.4.0",
"@vue/cli-plugin-eslint": "~4.4.0",
"@vue/cli-plugin-vuex": "~4.4.0",
"@vue/cli-service": "~4.4.0",
"@vue/cli-plugin-babel": "~4.5.9",
"@vue/cli-plugin-eslint": "~4.5.9",
"@vue/cli-plugin-vuex": "~4.5.9",
"@vue/cli-service": "~4.5.9",
"@vue/eslint-config-standard": "^5.1.2",
"babel-eslint": "^10.1.0",
"babel-plugin-component": "^1.1.1",
"electron": "^10.1.5",
"electron-devtools-installer": "^3.1.0",
"eslint": "^6.7.2",
"electron": "^11.0.3",
"electron-devtools-installer": "^3.1.1",
"eslint": "^7.14.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.2",
"eslint-plugin-vue": "^6.2.2",
"eslint-plugin-standard": "^4.1.0",
"eslint-plugin-vue": "^7.1.0",
"sass": "^1.29.0",
"sass-loader": "^8.0.2",
"vue-cli-plugin-electron-builder": "2.0.0-rc.4",
"sass-loader": "^10.1.0",
"vue-cli-plugin-electron-builder": "2.0.0-rc.5",
"vue-template-compiler": "^2.6.12"
}
}

View File

@@ -111,16 +111,6 @@
}
}
.play{
.popper {
font-size: 1rem;;
border: none;
li {
font-size: 1rem;
border: none;
}
}
}
// Page of list using el-table
.listpage{
position: absolute;
@@ -133,7 +123,7 @@
border-radius: 5px;
display: flex;
flex-direction: column;
.listpage-header{
.listpage-header, .toolbar{
height: 60px;
width: 100%;
display: flex;
@@ -185,7 +175,35 @@
font-size: 1rem;
border: none;
}
.el-select-dropdown__item.selected.hover{ //是上游的bug吗临时性修补
background-color: transparent;
}
}
> span{
.el-input-number{
width:120px;
.el-input{
width: 100px;
}
.el-input__inner{
padding-left: 5px;
padding-right: 5px;
width: 88px;
}
.el-input-number__increase, .el-input-number__decrease {
background-color: inherit;
border: none;
}
}
}
}
.el-divider{
.el-divider--horizontal{
margin: 12px 0;
}
}
.toolbar{
z-index: 5;
}
.listpage-body{
height: calc(100% - 60px);

View File

@@ -139,6 +139,13 @@
.play{
background-color: var(--d-bgc-1);
box-shadow: var(--d-bsc);
.el-input{
input{
background-color: var(--d-bgc-1);
border: 1px solid var(--d-bgc-1);
color: var(--d-fc-2);
}
}
.title{
color: var(--d-fc-1);
.right {
@@ -309,34 +316,10 @@
box-shadow: var(--d-bsc);
}
.play{
.el-input{
input{
background-color: var(--d-bgc-1);
border: 1px solid var(--d-bgc-1);
color: var(--d-fc-2);
}
}
.popper {
color: var(--d-fc-1);
background-color: var(--d-bgc-1);
box-shadow: var(--d-bsc);
li {
color: var(--d-fc-1);
background-color: var(--d-bgc-1);
&:hover{
background-color: var(--d-bgc-2);
}
}
.popper__arrow, .popper__arrow::after{
border-bottom-color: var(--d-bgc-1);
}
}
}
// Page of list using table and picture
.listpage{
color: var(--d-fc-2);
.listpage-header{
.listpage-header, .toolbar{
border-bottom-color: var(--d-c-3);
.btn{
&:hover{

View File

@@ -139,6 +139,13 @@
.play{
background-color: var(--g-bgc-1);
box-shadow: var(--g-bsc);
.el-input{
input{
background-color: var(--g-bgc-1);
border: 1px solid var(--g-bgc-1);
color: var(--g-fc-2);
}
}
.title{
color: var(--g-fc-1);
.right {
@@ -309,34 +316,10 @@
box-shadow: var(--g-bsc);
}
.play{
.el-input{
input{
background-color: var(--g-bgc-1);
border: 1px solid var(--g-bgc-1);
color: var(--g-fc-2);
}
}
.popper {
color: var(--g-fc-1);
background-color: var(--g-bgc-1);
box-shadow: var(--g-bsc);
li {
color: var(--g-fc-1);
background-color: var(--g-bgc-1);
&:hover{
background-color: var(--g-bgc-2);
}
}
.popper__arrow, .popper__arrow::after{
border-bottom-color: var(--g-bgc-1);
}
}
}
// Page of list using table and picture
.listpage{
color: var(--g-fc-2);
.listpage-header{
.listpage-header, .toolbar{
border-bottom-color: var(--g-c-3);
.btn{
&:hover{

View File

@@ -139,6 +139,13 @@
.play{
background-color: var(--l-bgc-1);
box-shadow: var(--l-bsc);
.el-input{
input{
background-color: var(--l-bgc-1);
border: 1px solid var(--l-bgc-1);
color: var(--l-fc-2);
}
}
.title{
color: var(--l-fc-1);
.right {
@@ -309,34 +316,10 @@
box-shadow: var(--l-bsc);
}
.play{
.el-input{
input{
background-color: var(--l-bgc-1);
border: 1px solid var(--l-bgc-1);
color: var(--l-fc-2);
}
}
.popper {
color: var(--l-fc-1);
background-color: var(--l-bgc-1);
box-shadow: var(--l-bsc);
li {
color: var(--l-fc-1);
background-color: var(--l-bgc-1);
&:hover{
background-color: var(--l-bgc-2);
}
}
.popper__arrow, .popper__arrow::after{
border-bottom-color: var(--l-bgc-1);
}
}
}
// Page of list using table and picture
.listpage{
color: var(--l-fc-2);
.listpage-header{
.listpage-header, .toolbar{
border-bottom-color: var(--l-c-3);
.btn{
&:hover{

View File

@@ -139,6 +139,13 @@
.play{
background-color: var(--p-bgc-1);
box-shadow: var(--p-bsc);
.el-input{
input{
background-color: var(--p-bgc-1);
border: 1px solid var(--p-bgc-1);
color: var(--p-fc-2);
}
}
.title{
color: var(--p-fc-1);
.right {
@@ -309,34 +316,10 @@
box-shadow: var(--p-bsc);
}
.play{
.el-input{
input{
background-color: var(--p-bgc-1);
border: 1px solid var(--p-bgc-1);
color: var(--p-fc-2);
}
}
.popper {
color: var(--p-fc-1);
background-color: var(--p-bgc-1);
box-shadow: var(--p-bsc);
li {
color: var(--p-fc-1);
background-color: var(--p-bgc-1);
&:hover{
background-color: var(--p-bgc-2);
}
}
.popper__arrow, .popper__arrow::after{
border-bottom-color: var(--p-bgc-1);
}
}
}
// Page of list using table and picture
.listpage{
color: var(--p-fc-2);
.listpage-header{
.listpage-header, .toolbar{
border-bottom-color: var(--p-c-3);
.btn{
&:hover{

View File

@@ -1,7 +1,7 @@
'use strict'
import './lib/site/server'
import { app, protocol, BrowserWindow, globalShortcut, ipcMain } from 'electron'
import { app, protocol, BrowserWindow, globalShortcut } from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
import { initUpdater } from './lib/update/update'
@@ -34,7 +34,7 @@ function createWindow () {
createProtocol('app')
win.loadURL('app://./index.html')
}
initUpdater(win)
win.on('closed', () => {

View File

@@ -211,30 +211,29 @@ export default {
}
},
downloadEvent () {
zy.download(this.detail.key, this.info.id).then(res => {
if (res && res.dl && res.dl.dd) {
const text = res.dl.dd._t
if (text) {
const list = text.split('#')
let downloadUrl = res.name + '\n'
for (const i of list) {
const url = encodeURI(i.split('$')[1])
downloadUrl += (url + '\n')
}
clipboard.writeText(downloadUrl)
this.$message.success('『MP4』格式的链接已复制, 快去下载吧!')
} else {
this.$message.warning('没有查询到下载链接.')
}
} else {
const list = [...this.m3u8List]
let downloadUrl = this.detail.info.name + '\n'
const key = this.detail.key
const id = this.info.id
zy.download(key, id).then(res => {
if (res && res.m3u8List) {
const list = res.m3u8List.split('#')
let downloadUrl = ''
for (const i of list) {
const url = encodeURI(i.split('$')[1])
downloadUrl += (url + '\n')
}
clipboard.writeText(downloadUrl)
this.$message.success('『M3U8』格式的链接已复制, 快去下载吧!')
this.$message.success('『MP4』格式的链接已复制, 快去下载吧!')
} else {
zy.detail(key, id).then(res => {
const list = [...res.m3u8List]
let downloadUrl = ''
for (const i of list) {
const url = encodeURI(i.split('$')[1])
downloadUrl += (url + '\n')
}
clipboard.writeText(downloadUrl)
this.$message.success('『M3U8』格式的链接已复制, 快去下载吧!')
})
}
})
},

View File

@@ -10,7 +10,8 @@
</el-option>
</el-select>
<el-switch v-model="searchViewMode" active-text="海报" active-value="picture" inactive-text="列表" inactive-value="table" @change="updateSearchViewMode"
v-if="show.find"></el-switch>
v-if="show.find">
</el-switch>
<el-select v-model="selectedClassName" size="small" placeholder="类型" :popper-append-to-body="false" popper-class="popper" @change="classClick" v-show="show.class">
<el-option
v-for="item in classList"
@@ -47,9 +48,36 @@
<el-button icon="el-icon-search" @click.stop="searchEvent" slot="append" />
</el-autocomplete>
</div>
<div class="toolbar" v-if="!show.find && showToolbar">
<el-select v-model="selectedAreas" size="small" multiple collapse-tags placeholder="地区" popper-class="popper" :popper-append-to-body="false" @remove-tag="refreshFilteredList" @visible-change="refreshFilteredList($event)">
<el-option
v-for="item in areas"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select>
<el-select v-model="sortKeyword" size="small" placeholder="排序" popper-class="popper" :popper-append-to-body="false" @change="refreshFilteredList">
<el-option
v-for="item in sortKeywords"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select>
<span>
上映区间
<el-input-number size="small" v-model="selectedYears.start" :min=0 :max="new Date().getFullYear()" controls-position="right" step-strictly @change="refreshFilteredList"></el-input-number>
<el-input-number size="small" v-model="selectedYears.end" :min=0 :max="new Date().getFullYear()" controls-position="right" step-strictly @change="refreshFilteredList"></el-input-number>
</span>
</div>
<el-divider content-position="center" v-if="!show.find">
<el-button type="text" size="mini" @click='() => { showToolbar = !showToolbar; if (!showToolbar) this.refreshFilteredList() }'>{{ showToolbar ? '隐藏工具栏' : '显示工具栏' }}</el-button>
</el-divider>
<div class="listpage-body" id="film-body" infinite-wrapper>
<div class="show-picture" v-if="setting.view === 'picture' && !show.find">
<Waterfall ref="filmWaterfall" :list="list" :gutter="20" :width="240"
<Waterfall ref="filmWaterfall" :list="filteredList" :gutter="20" :width="240"
:breakpoints="{
1200: { //当屏幕宽度小于等于1200
rowPerView: 4,
@@ -64,7 +92,7 @@
animationEffect="fadeIn"
backgroundColor="rgba(0, 0, 0, 0)">
<template slot="item" slot-scope="props">
<div class="card" v-show="!setting.excludeR18Films || !containsR18Keywords(props.data.type)">
<div class="card">
<div class="img">
<img style="width: 100%" :src="props.data.pic" alt="" @load="$refs.filmWaterfall.refresh()" @click="detailEvent(site, props.data)">
<div class="operate">
@@ -90,7 +118,7 @@
<div class="show-table" v-if="setting.view === 'table' && !show.find">
<el-table
size="mini"
:data="list.filter(res => !setting.excludeR18Films || !containsR18Keywords(res.type))"
:data="filteredList"
height="100%"
:empty-text="statusText"
@row-click="(row) => detailEvent(site, row)"
@@ -152,7 +180,7 @@
</infinite-loading>
</el-table>
</div>
<div class="show-table" v-show="searchViewMode=== 'table' && show.find">
<div class="show-table" v-if="searchViewMode=== 'table' && show.find">
<el-table size="mini"
ref="searchResultTable"
:data="searchContents.filter(res => !setting.excludeR18Films || (res.type !== undefined && !containsR18Keywords(res.type)))"
@@ -226,7 +254,7 @@
</el-table-column>
</el-table>
</div>
<div class="show-picture" v-show="searchViewMode === 'picture' && show.find">
<div class="show-picture" v-if="searchViewMode === 'picture' && show.find">
<Waterfall ref="filmSearchWaterfall" :list="searchContents.filter(res => !setting.excludeR18Films || (res.type !== undefined && !containsR18Keywords(res.type)))" :gutter="20" :width="240"
:breakpoints="{
1200: { //当屏幕宽度小于等于1200
@@ -277,6 +305,7 @@ import zy from '../lib/site/tools'
import Waterfall from 'vue-waterfall-plugin'
import InfiniteLoading from 'vue-infinite-loading'
const { clipboard } = require('electron')
const FILM_DATA_CACHE = {} // key = site.key, value = classList; key = site.key + '@' + type.tid, value = {list, pageCount}
export default {
name: 'film',
data () {
@@ -292,9 +321,10 @@ export default {
site: {},
classList: [],
type: {},
selectedClassName: '最新',
selectedSiteName: '',
selectedClassName: '',
pagecount: 0,
recordcount: 0,
list: [],
statusText: ' ',
infiniteId: +new Date(),
@@ -307,7 +337,14 @@ export default {
searchGroups: [],
// 福利片关键词
r18KeyWords: ['伦理', '论理', '倫理', '福利', '激情', '理论', '写真', '情色', '美女', '街拍', '赤足', '性感', '里番'],
searchViewMode: 'picture'
searchViewMode: 'picture',
filteredList: [],
areas: [],
selectedAreas: [],
sortKeyword: '',
sortKeywords: ['按片名', '按上映年份', '按更新时间'],
selectedYears: { start: 0, end: new Date().getFullYear() },
showToolbar: false
}
},
components: {
@@ -378,10 +415,50 @@ export default {
},
filterSettings () {
this.siteClick(this.site.name)
},
list: {
handler (list) {
this.areas = [...new Set(list.map(ele => ele.area))].filter(x => x)
this.refreshFilteredList()
},
deep: true
}
},
methods: {
...mapMutations(['SET_VIEW', 'SET_DETAIL', 'SET_VIDEO', 'SET_SHARE', 'SET_SETTING']),
refreshFilteredList (popperVisible) {
if (popperVisible === true) return
if (!this.showToolbar) {
this.sortKeyword = ''
this.selectedYears.start = 0
this.selectedYears.end = new Date().getFullYear()
}
let filteredData = this.list.filter(x => (this.selectedAreas.length === 0) || this.selectedAreas.includes(x.area))
filteredData = filteredData.filter(res => !this.setting.excludeR18Films || !this.containsR18Keywords(res.type))
filteredData = filteredData.filter(res => res.year >= this.selectedYears.start)
filteredData = filteredData.filter(res => res.year <= this.selectedYears.end)
this.selectedClassName = this.type.name + ' ' + filteredData.length + '/' + this.recordcount
switch (this.sortKeyword) {
case '按上映年份':
filteredData.sort(function (a, b) {
return a.year - b.year
})
break
case '按片名':
filteredData.sort(function (a, b) {
return a.name.localeCompare(b.name, 'zh')
})
break
case '按更新时间':
filteredData.sort(function (a, b) {
return new Date(b.last) - new Date(a.last)
})
break
default:
break
}
this.filteredList = filteredData
},
updateSearchViewMode () {
setting.find().then(res => {
res.searchViewMode = this.searchViewMode
@@ -417,16 +494,22 @@ export default {
siteClick (siteName) {
this.list = []
this.site = this.sites.find(x => x.name === siteName)
if (this.searchTxt.length > 0 && this.searchGroup === '站内') {
this.searchEvent()
this.searchTxt = ''
this.show.find = false
this.classList = []
if (FILM_DATA_CACHE[this.site.key]) {
this.classList = FILM_DATA_CACHE[this.site.key].classList
this.show.class = true
this.classClick(this.type.name)
} else {
this.searchTxt = ''
this.show.find = false
this.classList = []
this.type = {}
this.getClass().then(res => {
this.infiniteId += 1
this.classClick(this.classList[0].name)
this.classList = res
this.show.class = true
// cache classList data
FILM_DATA_CACHE[this.site.key] = {
classList: this.classList
}
this.classClick(this.type.name)
})
}
},
@@ -434,11 +517,22 @@ export default {
this.show.classList = false
this.list = []
this.type = this.classList.find(x => x.name === className)
this.getPage().then(res => {
if (res) {
if (!this.type) {
this.type = this.classList[0]
}
const cacheKey = this.site.key + '@' + this.type.tid
if (FILM_DATA_CACHE[cacheKey]) {
this.pagecount = FILM_DATA_CACHE[cacheKey].pagecount
this.recordcount = FILM_DATA_CACHE[cacheKey].recordcount
this.list = FILM_DATA_CACHE[cacheKey].list
this.areas = FILM_DATA_CACHE[cacheKey].areas
} else {
zy.page(this.site.key, this.type.tid).then(res => {
this.pagecount = res.pagecount
this.recordcount = res.recordcount
this.infiniteId += 1
}
})
})
}
},
getClass () {
return new Promise((resolve, reject) => {
@@ -459,11 +553,7 @@ export default {
}
}
})
this.classList = allClass
this.show.class = true
this.pagecount = res.pagecount
this.type = this.classList[0]
resolve(true)
resolve(allClass)
}).catch(err => {
reject(err)
})
@@ -476,30 +566,17 @@ export default {
}
return this.r18KeyWords.some(v => name.includes(v))
},
getPage () {
return new Promise((resolve, reject) => {
const key = this.site.key
const type = this.type.tid
zy.page(key, type).then(res => {
this.pagecount = res.pagecount
this.show.body = true
resolve(true)
}).catch(err => {
reject(err)
})
})
},
infiniteHandler ($state) {
const key = this.site.key
const type = this.type.tid
const typeTid = this.type.tid
const page = this.pagecount
this.statusText = ' '
if (key && page < 1) { // OK资源前几类硬是去不掉
if (key === undefined || page < 1 || typeTid === undefined) {
$state.complete()
this.statusText = '暂无数据'
return false
}
zy.list(key, page, type).then(res => {
zy.list(key, page, typeTid).then(res => {
if (res) {
this.pagecount -= 1
const type = Object.prototype.toString.call(res)
@@ -514,9 +591,17 @@ export default {
this.list.push(res)
}
$state.loaded()
} else {
$state.complete()
this.statusText = '暂无数据'
// 数据更新后,刷新页面
if (this.setting.view === 'picture' && this.$refs.filmWaterfall) {
this.$refs.filmWaterfall.refresh()
}
// 更新缓存数据
const cacheKey = this.site.key + '@' + typeTid
FILM_DATA_CACHE[cacheKey] = {
pagecount: this.pagecount,
recordcount: this.recordcount,
list: this.list
}
}
})
},
@@ -567,41 +652,29 @@ export default {
}
},
downloadEvent (site, row) {
zy.download(site.key, row.id).then(res => {
if (res && res.length > 0) {
const text = res.dl.dd._t
if (text) {
const list = text.split('#')
let downloadUrl = res.name + '\n'
const key = site.key
const id = row.id
zy.download(key, id).then(res => {
if (res && res.m3u8List) {
const list = res.m3u8List.split('#')
let downloadUrl = ''
for (const i of list) {
const url = encodeURI(i.split('$')[1])
downloadUrl += (url + '\n')
}
clipboard.writeText(downloadUrl)
this.$message.success('『MP4』格式的链接已复制, 快去下载吧!')
} else {
zy.detail(key, id).then(res => {
const list = [...res.m3u8List]
let downloadUrl = ''
for (const i of list) {
const url = encodeURI(i.split('$')[1])
downloadUrl += (url + '\n')
}
clipboard.writeText(downloadUrl)
this.$message.success('『MP4』格式的链接已复制, 快去下载吧!')
} else {
this.$message.warning('没有查询到下载链接.')
}
} else {
let m3u8List = []
const dd = row.dl.dd
const type = Object.prototype.toString.call(dd)
if (type === '[object Array]') {
for (const i of dd) {
if (i._flag.indexOf('m3u8') >= 0) {
m3u8List = i._t.split('#')
}
}
} else {
m3u8List = dd._t.split('#')
}
let downloadUrl = row.name + '\n'
for (const i of m3u8List) {
const url = encodeURI(i.split('$')[1])
downloadUrl += (url + '\n')
}
clipboard.writeText(downloadUrl)
this.$message.success('『M3U8』格式的链接已复制, 快去下载吧!')
this.$message.success('『M3U8』格式的链接已复制, 快去下载吧!')
})
}
})
},
@@ -612,9 +685,6 @@ export default {
if (this.$refs.filmWaterfall) {
this.$refs.filmWaterfall.refresh()
}
this.getPage().then(() => {
this.infiniteId += 1
})
}
}
},
@@ -666,7 +736,6 @@ export default {
searchSites = this.sites.filter(site => site.group === this.searchGroup)
}
this.searchContents = []
this.pagecount = 0
this.show.find = true
this.show.class = false
this.statusText = ' '
@@ -717,12 +786,6 @@ export default {
this.show.find = false
if (this.setting.view === 'picture' && this.$refs.filmWaterfall) {
this.$refs.filmWaterfall.refresh()
} else {
this.getClass().then(res => {
if (res) {
this.infiniteId += 1
}
})
}
}
},

View File

@@ -196,36 +196,21 @@ export default {
}
},
downloadEvent (e) {
zy.download(e.site, e.ids).then(res => {
if (res && res.dl && res.dl.dd) {
const text = res.dl.dd._t
if (text) {
const list = text.split('#')
let downloadUrl = ''
for (const i of list) {
const url = encodeURI(i.split('$')[1])
downloadUrl += (url + '\n')
}
clipboard.writeText(downloadUrl)
this.$message.success('『MP4』格式的链接已复制, 快去下载吧!')
} else {
this.$message.warning('没有查询到下载链接.')
const key = e.site
const id = e.ids
zy.download(key, id).then(res => {
if (res && res.m3u8List) {
const list = res.m3u8List.split('#')
let downloadUrl = ''
for (const i of list) {
const url = encodeURI(i.split('$')[1])
downloadUrl += (url + '\n')
}
clipboard.writeText(downloadUrl)
this.$message.success('『MP4』格式的链接已复制, 快去下载吧!')
} else {
var m3u8List = {}
zy.detail(e.site, e.ids).then(res => {
const dd = res.dl.dd
const type = Object.prototype.toString.call(dd)
if (type === '[object Array]') {
for (const i of dd) {
if (i._flag.indexOf('m3u8') >= 0) {
m3u8List = i._t.split('#')
}
}
} else {
m3u8List = dd._t.split('#')
}
const list = [...m3u8List]
zy.detail(key, id).then(res => {
const list = [...res.m3u8List]
let downloadUrl = ''
for (const i of list) {
const url = encodeURI(i.split('$')[1])

View File

@@ -25,7 +25,6 @@
:load="(row, treeNode, resolve) => resolve(row.channels)"
:tree-props="{hasChildren: 'hasChildren'}"
@expand-change="expandChange"
@row-click="playEvent"
@select="selectionCellClick"
@selection-change="handleSelectionChange"
@sort-change="handleSortChange">
@@ -95,6 +94,7 @@
</template>
<template slot-scope="scope">
<el-button @click.stop="moveToTopEvent(scope.row)" type="text" v-if="scope.row.channels">置顶</el-button>
<el-button @click.stop="playEvent(scope.row)" type="text">播放</el-button>
<!-- 检测时先强制批量检测一遍,如果不强制直接单个检测时第一次不会显示“检测中”-->
<el-button size="mini" v-if="iptvList.every(channel => channel.status)" v-show="!checkAllChannelsLoading" @click.stop="checkChannel(scope.row)" type="text">检测</el-button>
<el-button @click.stop="removeEvent(scope.row)" type="text">删除</el-button>
@@ -107,7 +107,7 @@
</template>
<script>
import { mapMutations } from 'vuex'
import { iptv, iptvSearch, channelList } from '../lib/dexie'
import { iptv, channelList } from '../lib/dexie'
import { iptv as defaultChannels } from '../lib/dexie/initData'
import zy from '../lib/site/tools'
import { remote } from 'electron'
@@ -120,7 +120,6 @@ export default {
iptvList: [],
channelList: [],
searchTxt: '',
searchRecordList: [],
enableBatchEdit: false,
inputContent: '',
batchIsActive: true,
@@ -132,10 +131,7 @@ export default {
checkAllChannelsLoading: false,
checkProgress: 0,
stopFlag: false,
sortableTable: '',
show: {
search: false
}
sortableTable: ''
}
},
computed: {
@@ -180,7 +176,7 @@ export default {
},
watch: {
view () {
if (this.view === 'IPTV') {
if (this.view === 'IPTV' && !this.checkAllChannelsLoading) {
this.getChannelList()
}
},
@@ -293,6 +289,7 @@ export default {
ele.channels.splice(ele.channels.findIndex(e => e.id === row.id), 1)
channelList.remove(row.channelID)
if (ele.channels.length) {
if (ele.channels.length === 1) ele.hasChildren = false
channelList.add(ele)
this.$set(this.$refs.iptvTable.store.states.lazyTreeNodeMap, ele.id, ele.channels)
}
@@ -348,21 +345,25 @@ export default {
result.filePaths.forEach(file => {
if (file.endsWith('m3u') || file.endsWith('m3u8')) {
const docs = []
const URL = require('url')
let id = this.channelList.length ? this.channelList.slice(-1)[0].id + 1 : 1
const parser = require('iptv-playlist-parser')
const playlist = fs.readFileSync(file, { encoding: 'utf-8' })
const result = parser.parse(playlist)
result.items.forEach(ele => {
if (ele.name && ele.url && ele.url.endsWith('.m3u8')) {
var doc = {
id: id,
name: ele.name,
url: ele.url,
isActive: true
const urls = ele.url.split('#').filter(e => e.startsWith('http')) // 网址带#时自动分割
urls.forEach(url => {
if (ele.name && url && new URL.URL(url).pathname.endsWith('.m3u8')) { // 网址可能带参数
var doc = {
id: id,
name: ele.name,
url: url,
isActive: true
}
id += 1
docs.push(doc)
}
id += 1
docs.push(doc)
}
})
})
// 获取url不重复的列表
const uniqueList = [...new Map(docs.map(item => [item.url, item])).values()]
@@ -393,14 +394,12 @@ export default {
})
},
determineGroup (name) {
if (name.toLowerCase().includes('cctv') && (name.includes('蓝光') || name.includes('高清'))) {
return '央视高清'
} else if (name.toLowerCase().includes('cctv')) {
if (name.toLowerCase().includes('cctv') || name.toLowerCase().includes('cgtn')) {
return '央视'
} else if (name.includes('香港') || name.includes('澳门') || name.includes('台湾') || name.includes('凤凰') || name.includes('翡翠')) {
return '港澳台'
} else if (name.includes('卫视')) {
return '卫视'
} else if (name.includes('香港') || name.includes('澳门') || name.includes('台湾') || name.includes('凤凰')) {
return '港澳台'
} else if (name.includes('高清') || name.includes('蓝光') || name.includes('1080P')) {
return '高清'
} else {
@@ -468,8 +467,8 @@ export default {
iptv.clear() // iptv默认清空状态
})
},
getChannelList () {
channelList.all().then(res => {
async getChannelList () {
await channelList.all().then(res => {
this.channelList = res
this.getIptvList()
})
@@ -477,28 +476,6 @@ export default {
getIptvList () {
this.iptvList = this.channelList.reduce((result, item) => { item.channels.forEach(e => { e.channelID = item.id }); return result.concat(item.channels) }, [])
},
getSearchRecordList () {
iptvSearch.all().then(res => {
this.searchRecordList = res.reverse()
})
},
clearSearch () {
iptvSearch.clear().then(res => {
this.getSearchRecordList()
})
},
searchEvent (wd) {
this.searchTxt = wd
this.show.search = false
if (wd) {
iptvSearch.find({ keywords: wd }).then(res => {
if (!res) {
iptvSearch.add({ keywords: wd })
}
this.getSearchRecordList()
})
}
},
moveToTopEvent (row) {
if (this.checkAllChannelsLoading) {
this.$message.info('正在检测, 请勿操作.')
@@ -537,6 +514,11 @@ export default {
ele.channels.forEach((e, index) => { e.id = embedChannelID + index }) // 为避免混杂给内置iptv重起id
if (prefer) ele.prefer = prefer.id
})
if (ele.channels.length === 1) {
ele.hasChildren = false
} else {
ele.hasChildren = true
}
})
},
rowDrop () {
@@ -562,6 +544,7 @@ export default {
channelList.remove(row.channelID)
channelList.add(ele)
} else {
if (row.channels.length === 1) row.channels[0].isActive = row.isActive
channelList.remove(row.id)
channelList.add(row)
}
@@ -570,13 +553,13 @@ export default {
this.checkAllChannelsLoading = true
this.stopFlag = false
this.checkProgress = 0
this.channelList.forEach(e => { e.status = ' '; e.hasCheckedNum = 0 })
this.channelList.filter(e => e.channels.length).forEach(e => { e.status = ' '; e.hasCheckedNum = 0 })
const uncheckedList = this.iptvList.filter(e => e.status === undefined || e.status === ' ') // 未检测过的优先
const other = this.iptvList.filter(e => !uncheckedList.includes(e))
await this.checkChannelsBySite(uncheckedList)
await this.checkChannelsBySite(other).then(res => {
this.checkAllChannelsLoading = false
this.updateChannelList()
this.getChannelList()
})
},
async checkChannelsBySite (channels) {
@@ -598,6 +581,10 @@ export default {
}
},
async checkSingleChannel (channel) {
if (this.setting.allowPassWhenIptvCheck && !channel.isActive) {
this.checkProgress += 1
return
}
channel.status = ' '
const ele = this.channelList.find(e => e.id === channel.channelID)
if (this.stopFlag) {
@@ -612,12 +599,17 @@ export default {
} else {
channel.status = '失效'
channel.isActive = false
if (this.setting.autocleanWhenIptvCheck) {
ele.channels.splice(ele.channels.findIndex(e => e.id === channel.id), 1)
ele.hasCheckedNum--
}
}
if (ele.hasCheckedNum === ele.channels.length) {
ele.status = ele.channels.some(channel => channel.status === '可用') ? '可用' : '失效'
if (ele.status === '失效') ele.isActive = false
channelList.remove(channel.channelID)
channelList.add(ele)
if (ele.channels.length === 1) ele.hasChildren = false
if (ele.channels.length) channelList.add(ele)
}
return channel.status
},
@@ -635,10 +627,9 @@ export default {
addEventListener('keydown', code => { if (code.keyCode === 16) this.shiftDown = true })
addEventListener('keyup', code => { if (code.keyCode === 16) this.shiftDown = false })
},
created () {
this.getChannelList()
async created () {
await this.getChannelList()
if (!this.channelList.length) this.resetChannelsEvent()
this.getSearchRecordList()
}
}
</script>

View File

@@ -98,6 +98,21 @@
<circle cx="12" cy="12" r="10"></circle>
</svg>
</span>
<span class="timespan" v-if="right.list.length > 1">
<label>片头长度</label>
<input type="number" v-model="startPosition.min" style="width:45px" min="00" max="59" placeholder="00" required>
<label>:</label>
<input type="number" v-model="startPosition.sec" style="width:45px" min="00" max="59" placeholder="00" required>
<span></span>
<label>片尾长度</label>
<input type="number" v-model="endPosition.min" style="width:45px" min="00" max="59" placeholder="00" required>
<label>:</label>
<input type="number" v-model="endPosition.sec" style="width:45px" min="00" max="59" placeholder="00" required>
<span></span>
<input type="button" value="确定" @click="setProgressDotByInput" title="还可以通过快捷键设置">
<span></span>
<input type="button" value="重置" @click="() => { startPosition.min = startPosition.sec = endPosition.min = endPosition.sec = '00'; this.clearPosition() }">
</span>
<span class="last-tip" v-if="!video.key && right.history.length > 0" @click="historyItemEvent(right.history[0])">上次播放到{{right.history[0].site}}{{right.history[0].name}} {{right.history[0].index+1}}</span>
</div>
<div class="more" v-if="video.iptv" :key="Boolean(video.iptv)">
@@ -195,18 +210,13 @@
</span>
</div>
<div class="list-body zy-scroll" :style="{overflowY:scroll? 'auto' : 'hidden',paddingRight: scroll ? '0': '5px' }" @mouseenter="scroll = true" @mouseleave="scroll = false">
<el-autocomplete
<el-input
clearable
size="small"
v-model.trim="searchTxt"
value-key="keywords"
:fetch-suggestions="querySearch"
:popper-append-to-body="false"
popper-class="popper"
placeholder="搜索"
@keyup.enter.native="searchAndRecord">
placeholder="搜索">
<i slot="prefix" class="el-input__icon el-icon-search"></i>
</el-autocomplete>
</el-input>
<el-tree ref="channelTree"
:data="channelListForShow"
:props="defaultProps"
@@ -221,7 +231,7 @@
</template>
<script>
import { mapMutations } from 'vuex'
import { star, history, setting, shortcut, mini, channelList, iptvSearch, sites } from '../lib/dexie'
import { star, history, setting, shortcut, mini, channelList, sites } from '../lib/dexie'
import zy from '../lib/site/tools'
import Player from 'xgplayer'
import HlsJsPlayer from 'xgplayer-hls.js'
@@ -309,10 +319,12 @@ export default {
videoStop: true,
showList: true,
showHistory: true,
quitMiniMode: true,
videoTitle: true,
airplay: true,
closeVideoTouch: true,
ignores: ['cssFullscreen']
ignores: ['cssFullscreen', 'replay'],
preloadTime: 300
},
state: {
showList: false,
@@ -327,14 +339,15 @@ export default {
miniMode: false,
mainWindowBounds: {},
searchTxt: '',
searchRecordList: [],
channelList: [],
channelListForShow: [],
channelListShow: false,
defaultProps: {
label: 'label',
children: 'children'
}
},
startPosition: { min: '00', sec: '00' },
endPosition: { min: '00', sec: '00' }
}
},
filters: {
@@ -401,7 +414,9 @@ export default {
this.right.type = ''
if (this.view === 'Play') {
this.getChannelList()
if (this.video.key === '' && !this.video.iptv) this.channelListShow = true
if (this.video.key === '' && !this.video.iptv) {
this.channelListShow = true
}
}
},
video: {
@@ -428,15 +443,35 @@ export default {
}
},
searchTxt () {
if (this.searchTxt === '清除历史记录...') {
this.clearSearchRecords()
this.searchTxt = ''
}
this.searchEvent()
this.$refs.channelTree.filter(this.searchTxt)
},
startPosition: {
handler (time) {
this.leadingZero(time)
},
deep: true
},
endPosition: {
handler (time) {
this.leadingZero(time)
},
deep: true
}
},
methods: {
...mapMutations(['SET_VIEW', 'SET_DETAIL', 'SET_VIDEO', 'SET_SHARE', 'SET_APPSTATE']),
leadingZero (time) {
Object.keys(time).forEach(key => {
if (time[key] > 59 || time[key] < 0) {
time[key] = '00'
} else if (time[key].length > 2) {
time[key] = '' + parseInt(time[key])
// time[key] = time[key].replace(/^0+/, '')
} else if (time[key] < 10 && time[key].length === 1) {
time[key] = '0' + time[key]
}
})
},
handleNodeClick (node) {
if (node.channel) {
this.playChannel(node.channel)
@@ -444,47 +479,7 @@ export default {
},
filterNode (value, data) {
if (!value) return true
return data.label.toLowerCase().includes(value.toLowerCase()) || PinyinMatch.match(data.label, value)
},
querySearch (queryString, cb) {
var searchRecordList = this.searchRecordList.slice(0, -1)
var results = queryString ? searchRecordList.filter(this.createFilter(queryString)) : this.searchRecordList
// 调用 callback 返回建议列表的数据
cb(results)
},
createFilter (queryString) {
return (item) => {
return (item.keywords.toLowerCase().indexOf(queryString.toLowerCase()) === 0)
}
},
getSearchRecordList () {
iptvSearch.all().then(res => {
this.searchRecordList = res.reverse()
this.searchRecordList.push({ id: this.searchRecordList.length + 1, keywords: '清除历史记录...' })
})
},
addSearchRecord () {
const wd = this.searchTxt
if (wd) {
iptvSearch.find({ keywords: wd }).then(res => {
if (!res) {
iptvSearch.add({ keywords: wd })
}
this.getSearchRecordList()
})
}
},
clearSearchRecords () {
iptvSearch.clear().then(res => {
this.getSearchRecordList()
})
},
searchEvent () {
this.$refs.channelTree.filter(this.searchTxt)
},
searchAndRecord () {
this.addSearchRecord()
this.searchEvent()
return PinyinMatch.match(data.label, value)
},
async getUrls () {
if (this.video.key === '') {
@@ -505,15 +500,24 @@ export default {
this.playChannel(this.video.iptv)
} else {
this.channelListShow = false
const index = this.video.info.index | 0
const index = this.video.info.index || 0
const db = await history.find({ site: this.video.key, ids: this.video.info.id })
const key = this.video.key + '@' + this.video.info.id
var time = this.video.info.time
if (!time) {
// 如果video.info.time没有设定的话从历史中读取时间进度
const db = await history.find({ site: this.video.key, ids: this.video.info.id })
if (db) {
if (db.index === index) {
time = db.time
}
this.xg.removeAllProgressDot()
this.startPosition = this.endPosition = { min: '00', sec: '00' }
if (db) {
if (!time && db.index === index) { // 如果video.info.time没有设定的话从历史中读取时间进度
time = db.time
}
if (!VIDEO_DETAIL_CACHE[key]) VIDEO_DETAIL_CACHE[key] = {}
if (db.startPosition) {
VIDEO_DETAIL_CACHE[key].startPosition = db.startPosition
this.startPosition = { min: '' + parseInt(db.startPosition / 60), sec: '' + parseInt(db.startPosition % 60) }
}
if (db.endPosition) {
VIDEO_DETAIL_CACHE[key].endPosition = db.endPosition
this.endPosition = { min: '' + parseInt(db.endPosition / 60), sec: '' + parseInt(db.endPosition % 60) }
}
}
this.playVideo(index, time)
@@ -528,7 +532,6 @@ export default {
ele.isActive = ele.channels.some(e => e.isActive)
channelList.remove(ele.id)
channelList.add(ele)
this.getChannelList()
},
playChannel (channel) {
if (channel.channels) {
@@ -539,69 +542,65 @@ export default {
ele.prefer = channel.id
channelList.remove(ele.id)
channelList.add(ele)
this.getChannelList()
this.right.sources = ele.channels.filter(e => e.isActive)
}
this.video.iptv = channel
this.name = channel.name
this.xg.src = channel.url
this.xg.play()
document.querySelector('xg-btn-quitMiniMode').style.display = 'none'
document.querySelector('xg-btn-showhistory').style.display = 'none'
document.querySelector('.xgplayer-playbackrate').style.display = 'none'
},
playVideo (index = 0, time = 0) {
document.querySelector('xg-btn-quitMiniMode').style.display = 'none'
document.querySelector('xg-btn-showhistory').style.display = 'block'
document.querySelector('.xgplayer-playbackrate').style.display = 'inline-block'
this.fetchM3u8List().then(m3u8Arr => {
this.xg.src = m3u8Arr[index]
if (time !== 0) {
const url = m3u8Arr[index]
if (!m3u8Arr[index].endsWith('.m3u8')) {
const onlineUrl = 'https://www.1717yun.com/jiexi/?url=' + url
const open = require('open')
open(onlineUrl)
} else {
this.xg.src = m3u8Arr[index]
const key = this.video.key + '@' + this.video.info.id
const startTime = VIDEO_DETAIL_CACHE[key].startPosition || 0
this.xg.play()
this.xg.once('playing', () => {
this.xg.currentTime = time
this.xg.currentTime = time > startTime ? time : startTime
if (VIDEO_DETAIL_CACHE[key].startPosition) this.xg.addProgressDot(VIDEO_DETAIL_CACHE[key].startPosition, '片头')
if (VIDEO_DETAIL_CACHE[key].endPosition) this.xg.addProgressDot(this.xg.duration - VIDEO_DETAIL_CACHE[key].endPosition, '片尾')
})
this.videoPlaying()
VIDEO_DETAIL_CACHE[key].skipend = false
this.xg.once('ended', () => {
if (m3u8Arr.length > 1 && (m3u8Arr.length - 1 > index)) {
this.video.info.time = 0
this.video.info.index++
}
this.xg.off('ended')
})
} else {
this.xg.play()
}
this.videoPlaying()
this.xg.once('ended', () => {
if (m3u8Arr.length > 1 && (m3u8Arr.length - 1 > index)) {
this.video.info.time = 0
this.video.info.index++
}
this.xg.off('ended')
})
})
},
fetchM3u8List () {
return new Promise((resolve) => {
const cacheKey = this.video.key + '@' + this.video.info.id
if (VIDEO_DETAIL_CACHE[cacheKey]) {
if (VIDEO_DETAIL_CACHE[cacheKey] && VIDEO_DETAIL_CACHE[cacheKey].list && VIDEO_DETAIL_CACHE[cacheKey].list.length) {
this.name = VIDEO_DETAIL_CACHE[cacheKey].name
resolve(VIDEO_DETAIL_CACHE[cacheKey].list)
}
zy.detail(this.video.key, this.video.info.id).then(res => {
this.name = res.name
const dd = res.dl.dd
const type = Object.prototype.toString.call(dd)
let m3u8Txt = []
if (type === '[object Array]') {
for (const i of dd) {
if (i._t.indexOf('m3u8') >= 0) {
m3u8Txt = i._t.split('#')
}
}
} else {
m3u8Txt = dd._t.split('#')
}
const m3u8Txt = res.m3u8List
this.right.list = m3u8Txt
const m3u8Arr = []
for (const i of m3u8Txt) {
const j = i.split('$')
if (j.length > 1) {
for (let m = 0; m < j.length; m++) {
if (j[m].indexOf('.m3u8') >= 0 && j[m].startsWith('http')) {
if (j[m].startsWith('http')) {
m3u8Arr.push(j[m])
break
}
@@ -611,10 +610,10 @@ export default {
}
}
VIDEO_DETAIL_CACHE[cacheKey] = {
VIDEO_DETAIL_CACHE[cacheKey] = Object.assign(VIDEO_DETAIL_CACHE[cacheKey] || {}, {
list: m3u8Arr,
name: res.name
}
})
resolve(m3u8Arr)
})
})
@@ -655,6 +654,37 @@ export default {
this.checkStar()
this.checkTop()
},
async setProgressDotEvent (position, timespan, text) {
const key = this.video.key + '@' + this.video.info.id
const db = await history.find({ site: this.video.key, ids: this.video.info.id })
if (db && this.xg && VIDEO_DETAIL_CACHE[key].list.length > 1) {
this[position] = { min: '' + parseInt(timespan / 60), sec: '' + parseInt(timespan % 60) }
const positionTime = position === 'endPosition' ? this.xg.duration - timespan : timespan
if (db[position]) this.xg.removeProgressDot(position === 'endPosition' ? this.xg.duration - db[position] : db[position])
this.xg.addProgressDot(positionTime, text)
const doc = { ...db }
doc[position] = timespan
delete doc.id
history.update(db.id, doc)
VIDEO_DETAIL_CACHE[key][position] = timespan
}
},
async setProgressDotByInput () {
this.xg.removeAllProgressDot()
const startTime = parseInt(this.startPosition.min) * 60 + parseInt(this.startPosition.sec)
const endTime = parseInt(this.endPosition.min) * 60 + parseInt(this.endPosition.sec)
if (startTime > this.xg.duration || endTime > this.xg.duration) {
this.$message.error('设置的跳跃时间长度已超过视频播放时长,请调整设置!')
return
}
await this.setProgressDotEvent('startPosition', startTime)
await this.setProgressDotEvent('endPosition', endTime)
},
async clearPosition () {
await this.setProgressDotEvent('startPosition', 0)
await this.setProgressDotEvent('endPosition', 0)
this.xg.removeAllProgressDot()
},
timerEvent () {
this.timer = setInterval(async () => {
const endTime = this.xg.duration
@@ -673,7 +703,7 @@ export default {
},
prevEvent () {
if (this.video.iptv) {
var index = this.channelList.findIndex(obj => obj.prefer === this.video.iptv.id)
var index = this.channelList.findIndex(obj => obj.id === this.video.iptv.channelID)
if (index >= 1) {
var channel = this.channelList[index - 1]
this.playChannel(channel)
@@ -691,7 +721,7 @@ export default {
},
nextEvent () {
if (this.video.iptv) {
var index = this.channelList.findIndex(obj => obj.prefer === this.video.iptv.id)
var index = this.channelList.findIndex(obj => obj.id === this.video.iptv.channelID)
if (index < (this.channelList.length - 1)) {
var channel = this.channelList[index + 1]
this.playChannel(channel)
@@ -781,6 +811,7 @@ export default {
if (!miniWindowBounds) miniWindowBounds = { x: win.getPosition()[0], y: win.getPosition()[1], width: 550, height: 340 }
win.setBounds(miniWindowBounds)
this.xg.getCssFullscreen()
document.querySelector('xg-btn-quitMiniMode').style.display = 'block'
this.miniMode = true
},
async exitMiniEvent () {
@@ -798,6 +829,7 @@ export default {
})
win.setBounds(this.mainWindowBounds)
this.xg.exitCssFullscreen()
document.querySelector('xg-btn-quitMiniMode').style.display = 'none'
this.miniMode = false
},
shareEvent () {
@@ -1021,7 +1053,7 @@ export default {
}
})
},
shortcutEvent (e) {
async shortcutEvent (e) {
if (e === 'playAndPause') {
if (this.xg) {
if (this.xg.paused) {
@@ -1113,6 +1145,18 @@ export default {
}
return false
}
if (e === 'startPosition') {
this.setProgressDotEvent('startPosition', this.xg.currentTime, '片头')
return false
}
if (e === 'endPosition') {
this.setProgressDotEvent('endPosition', this.xg.duration - this.xg.currentTime, '片尾')
return false
}
if (e === 'clearPosition') {
this.clearPosition()
return false
}
if (e === 'opacityUp') {
const num = win.getOpacity()
if (num > 0.1) {
@@ -1146,7 +1190,18 @@ export default {
return false
}
if (e === 'mini') {
this.miniEvent()
if (!this.miniMode) {
this.miniEvent()
} else {
this.exitMiniEvent()
}
return false
}
if (e === 'resetMini') {
if (this.miniMode) {
const miniWindowBounds = { x: this.mainWindowBounds.x, y: this.mainWindowBounds.y, width: 550, height: 340 }
win.setBounds(miniWindowBounds)
}
return false
}
},
@@ -1278,6 +1333,19 @@ export default {
setting.find().then(res => { res.volume = this.config.volume; setting.update(res) })
})
this.xg.on('timeupdate', () => {
const key = this.video.key + '@' + this.video.info.id
if (VIDEO_DETAIL_CACHE[key] && VIDEO_DETAIL_CACHE[key].endPosition) {
const time = this.xg.duration - VIDEO_DETAIL_CACHE[key].endPosition - this.xg.currentTime
if (time > 0 && time < 0.3) {
if (!VIDEO_DETAIL_CACHE[key].skipend) {
VIDEO_DETAIL_CACHE[key].skipend = true
this.xg.emit('ended')
}
}
}
})
this.xg.on('playNextOne', () => {
this.nextEvent()
})
@@ -1299,6 +1367,10 @@ export default {
this.videoStop()
})
this.xg.on('quitMiniMode', () => {
if (this.miniMode) this.exitMiniEvent()
})
const ev = ['click', 'touchend', 'mousemove']
let timerID
ev.forEach(item => {
@@ -1329,7 +1401,7 @@ export default {
clearInterval(this.timer)
this.video.key = ''
this.xg.src = ''
this.config.src = ''
this.config.url = ''
this.xg.destroy(false)
this.xg = null
this.name = ''
@@ -1365,6 +1437,10 @@ export default {
Player.install('videoStop', function () {
addPlayerBtn.bind(this, 'videoStop', '<svg t="1603093629102" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3621" style="width: 25px;height: 25px;margin-top: 8px;margin-left: 0px;"><path d="M768 768H256V256h512v512z" p-id="3622" fill="#ffffff"></path></svg>', { title: '停止播放' })()
})
Player.install('quitMiniMode', function () {
addPlayerBtn.bind(this, 'quitMiniMode', '<svg t="1606051549980" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2510" style="width: 22px;height: 22px;margin-top: 9px;margin-left: 6px;"><path d="M224 704c-8 0-16-3.2-22.4-9.6l-160-160c-12.8-12.8-12.8-32 0-44.8l160-160c12.8-12.8 32-12.8 44.8 0 12.8 12.8 12.8 32 0 44.8L108.8 512l137.6 137.6c12.8 12.8 12.8 32 0 44.8-6.4 6.4-14.4 9.6-22.4 9.6z m416-160H80c-17.6 0-32-14.4-32-32s14.4-32 32-32h560c17.6 0 32 14.4 32 32s-14.4 32-32 32z m192 384H480c-52.8 0-96-43.2-96-96V704c0-17.6 14.4-32 32-32s32 14.4 32 32v128c0 17.6 14.4 32 32 32h352c17.6 0 32-14.4 32-32V192c0-17.6-14.4-32-32-32H480c-17.6 0-32 14.4-32 32v128c0 17.6-14.4 32-32 32s-32-14.4-32-32V192c0-52.8 43.2-96 96-96h352c52.8 0 96 43.2 96 96v640c0 52.8-43.2 96-96 96z" p-id="2511" fill="#ffffff"></path></svg>',
{ title: '退出精简模式' })()
})
Player.install('showList', function () {
addPlayerBtn.bind(this, 'showList', '<svg t="1595866128681" class="icon" viewBox="0 0 1316 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4187" style="width: 22px;height: 22px;margin-top: 9px;margin-left: 6px;" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M0 0h1316.571429v146.285714H0zM0 438.857143h1316.571429v146.285714H0zM0 877.714286h1316.571429v146.285714H0z" p-id="4188" fill="#ffffff"></path></svg>', { title: '播放列表' })()
})
@@ -1421,7 +1497,8 @@ export default {
.xgplayer-skin-default .xg-btn-playNextOne,
.xgplayer-skin-default .xg-btn-showList,
.xgplayer-skin-default .xg-btn-showHistory,
.xgplayer-skin-default .xg-btn-videoStop {
.xgplayer-skin-default .xg-btn-videoStop,
.xgplayer-skin-default .xg-btn-quitMiniMode {
width: 32px;
position: relative;
-webkit-order: 0;
@@ -1435,7 +1512,8 @@ export default {
.xgplayer-skin-default .xg-btn-playNextOne:hover,
.xgplayer-skin-default .xg-btn-showList:hover,
.xgplayer-skin-default .xg-btn-showHistory:hover,
.xgplayer-skin-default .xg-btn-videoStop:hover {
.xgplayer-skin-default .xg-btn-videoStop:hover,
.xgplayer-skin-default .xg-btn-quitMiniMode:hover {
opacity: 0.8;
}
.xgplayer-skin-default .xg-btn-playNextOne {
@@ -1444,15 +1522,22 @@ export default {
.xgplayer-skin-default .xgplayer-play, .xgplayer-skin-default .xgplayer-play-img {
order: 1 !important;
}
.xgplayer-skin-default .xg-btn-videoStop {
order: 2;
}
.xgplayer-skin-default .xg-btn-quitMiniMode {
order: 4;
}
.xgplayer-skin-default .xg-btn-showList {
order: 4;
}
.xgplayer-skin-default .xg-btn-showHistory {
order: 4;
}
.xgplayer-skin-default .xg-btn-showList ul, .xgplayer-skin-default .xg-btn-showHistory ul {
display: none;
list-style: none;
@@ -1575,6 +1660,16 @@ export default {
margin-right: 10px;
cursor: pointer;
}
.timespan{
margin-left: auto;
justify-content: space-between;
align-items: center;
input{
&::-webkit-inner-spin-button, &::-webkit-outer-spin-button {
opacity: 1;
}
}
}
}
}
.list{

View File

@@ -276,36 +276,21 @@ export default {
}
},
downloadEvent (e) {
zy.download(e.key, e.ids).then(res => {
if (res && res.dl && res.dl.dd) {
const text = res.dl.dd._t
if (text) {
const list = text.split('#')
let downloadUrl = ''
for (const i of list) {
const url = encodeURI(i.split('$')[1])
downloadUrl += (url + '\n')
}
clipboard.writeText(downloadUrl)
this.$message.success('『MP4』格式的链接已复制, 快去下载吧!')
} else {
this.$message.warning('没有查询到下载链接.')
const key = e.key
const id = e.ids
zy.download(key, id).then(res => {
if (res && res.m3u8List) {
const list = res.m3u8List.split('#')
let downloadUrl = ''
for (const i of list) {
const url = encodeURI(i.split('$')[1])
downloadUrl += (url + '\n')
}
clipboard.writeText(downloadUrl)
this.$message.success('『MP4』格式的链接已复制, 快去下载吧!')
} else {
var m3u8List = {}
zy.detail(e.key, e.ids).then(res => {
const dd = res.dl.dd
const type = Object.prototype.toString.call(dd)
if (type === '[object Array]') {
for (const i of dd) {
if (i._flag.indexOf('m3u8') >= 0) {
m3u8List = i._t.split('#')
}
}
} else {
m3u8List = dd._t.split('#')
}
const list = [...m3u8List]
zy.detail(key, id).then(res => {
const list = [...res.m3u8List]
let downloadUrl = ''
for (const i of list) {
const url = encodeURI(i.split('$')[1])

View File

@@ -78,6 +78,12 @@
<div class="zy-select">
<div class="vs-placeholder vs-noAfter" @click="view = 'IPTV'">编辑直播源</div>
</div>
<div class="zy-input">
<input type="checkbox" v-model = "d.allowPassWhenIptvCheck" @change="updateSettingEvent"> 检测时自动跳过停用源
</div>
<div class="zy-input">
<input type="checkbox" v-model = "d.autocleanWhenIptvCheck" @change="updateSettingEvent"> 检测时自动清理无效源
</div>
</div>
</div>
<div class="site">

View File

@@ -74,20 +74,9 @@ export default {
zy.detail(this.share.key, id).then(res => {
if (res) {
this.pic = res.pic
var m3u8List = {}
const dd = res.dl.dd
const type = Object.prototype.toString.call(dd)
if (type === '[object Array]') {
for (const i of dd) {
if (i._flag.indexOf('m3u8') >= 0) {
m3u8List = i._t.split('#')
}
}
} else {
m3u8List = dd._t.split('#')
}
var m3u8List = res.m3u8List
const url = m3u8List[1]
this.link = 'http://zyplayer.fun/player/player.html?url=' + url + '&title=' + this.share.info.name
this.link = 'http://hunlongyu.gitee.io/zy-player-web?url=' + url + '&name=' + this.share.info.name
}
this.loading = false
})

View File

@@ -299,36 +299,21 @@ export default {
})
},
downloadEvent (e) {
zy.download(e.key, e.ids).then(res => {
if (res && res.dl && res.dl.dd) {
const text = res.dl.dd._t
if (text) {
const list = text.split('#')
let downloadUrl = ''
for (const i of list) {
const url = encodeURI(i.split('$')[1])
downloadUrl += (url + '\n')
}
clipboard.writeText(downloadUrl)
this.$message.success('『MP4』格式的链接已复制, 快去下载吧!')
} else {
this.$message.warning('没有查询到下载链接.')
const key = e.key
const id = e.id
zy.download(key, id).then(res => {
if (res && res.m3u8List) {
const list = res.m3u8List.split('#')
let downloadUrl = ''
for (const i of list) {
const url = encodeURI(i.split('$')[1])
downloadUrl += (url + '\n')
}
clipboard.writeText(downloadUrl)
this.$message.success('『MP4』格式的链接已复制, 快去下载吧!')
} else {
var m3u8List = {}
zy.detail(e.key, e.ids).then(res => {
const dd = res.dl.dd
const type = Object.prototype.toString.call(dd)
if (type === '[object Array]') {
for (const i of dd) {
if (i._flag.indexOf('m3u8') >= 0) {
m3u8List = i._t.split('#')
}
}
} else {
m3u8List = dd._t.split('#')
}
const list = [...m3u8List]
zy.detail(key, id).then(res => {
const list = [...res.m3u8List]
let downloadUrl = ''
for (const i of list) {
const url = encodeURI(i.split('$')[1])

View File

@@ -5,14 +5,12 @@ const db = new Dexie('zy')
db.version(4).stores({
search: '++id, keywords',
iptvSearch: '++id, keywords',
setting: 'id, theme, site, shortcut, view, volume, externalPlayer, searchGroup, excludeRootClasses, excludeR18Films, forwardTimeInSec, starViewMode, recommandationViewMode, searchViewMode, password, proxy',
setting: 'id, theme, site, shortcut, view, volume, externalPlayer, searchGroup, excludeRootClasses, excludeR18Films, forwardTimeInSec, starViewMode, recommandationViewMode, searchViewMode, password, proxy, allowPassWhenIptvCheck, autocleanWhenIptvCheck',
shortcut: 'name, key, desc',
star: '++id, [key+ids], site, name, detail, index, rate, hasUpdate',
recommendation: '++id, [key+ids], site, name, detail, index, rate, hasUpdate',
sites: '++id, key, name, api, download, isActive, group',
history: '++id, [site+ids], name, type, year, index, time, duration, detail',
// mini: 'id, mode, site, ids, name, index, time, url',
mini: 'id, bounds',
iptv: '++id, name, url, isActive',
channelList: '++id, name, prefer, channels, group, isActive'

View File

@@ -5,7 +5,6 @@ import shortcut from './shortcut'
import star from './star'
import sites from './sites'
import search from './search'
import iptvSearch from './iptvSearch'
import iptv from './iptv'
import channelList from './channelList'
import recommendation from './recommendation'
@@ -20,6 +19,5 @@ export {
iptv,
channelList,
search,
iptvSearch,
recommendation
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,259 @@
[
{
"key": "1886zy",
"ids": 16944,
"site": {
"id": 2,
"key": "1886zy",
"name": "1886 资源",
"api": "http://cj.1886zy.co/inc/api.php",
"download": "",
"group": "默认",
"isActive": true,
"status": "可用"
},
"name": "柯明斯基理论",
"detail": {
"last": "2018-11-23 18:13:07",
"id": 16944,
"tid": 15,
"name": "柯明斯基理论",
"type": "欧美剧",
"pic": "http://pic.yc370.com/upload/vod/2019-01-19/15479133688.jpg",
"lang": "",
"area": "美国",
"year": 2018,
"state": 8,
"note": "08",
"actor": "迈克尔·道格拉斯,艾伦·阿金,莎拉·贝克,南希·特拉维斯",
"director": "安迪·坦纳特,查克·罗瑞,唐纳德·佩特瑞,贝丝·麦卡锡-米勒",
"dl": {
"dd": [
{
"_t": "08$https://zuikzy.51moca.com/share/XoIqsGnIP7IED2LS#07$https://zkcdn.yiya520.com/share/kJOL42dTmm6VJkqK#06$https://zkcdn.yiya520.com/share/f8gxIqAchIPyxlAg#05$https://zkcdn.yiya520.com/share/mTG5GkXpB7yro1sQ#04$https://zkcdn.yiya520.com/share/HjQAbC0lzzHAusIw#03$https://zkcdn.yiya520.com/share/qlN7TvZUDDueiefE#02$https://zkcdn.yiya520.com/share/2P9HAA5H1KvkMgm2#01$https://zkcdn.yiya520.com/share/KUD3QMMS4UGnNA3Y",
"_flag": "zkyun"
},
{
"_t": "08$https://zuikzy.51moca.com/2018/11/23/XoIqsGnIP7IED2LS/playlist.m3u8#07$https://zkcdn.yiya520.com/2018/11/21/kJOL42dTmm6VJkqK/playlist.m3u8#06$https://zkcdn.yiya520.com/2018/11/21/f8gxIqAchIPyxlAg/playlist.m3u8#05$https://zkcdn.yiya520.com/2018/11/21/mTG5GkXpB7yro1sQ/playlist.m3u8#04$https://zkcdn.yiya520.com/2018/11/19/HjQAbC0lzzHAusIw/playlist.m3u8#03$https://zkcdn.yiya520.com/2018/11/19/qlN7TvZUDDueiefE/playlist.m3u8#02$https://zkcdn.yiya520.com/2018/11/18/2P9HAA5H1KvkMgm2/playlist.m3u8#01$https://zkcdn.yiya520.com/2018/11/18/KUD3QMMS4UGnNA3Y/playlist.m3u8",
"_flag": "zkm3u8"
}
]
},
"des": "迈克尔·道格拉斯、艾伦·阿金有望加盟Netflix喜剧剧集《柯明斯基理论》(The Kominsky Method暂译)该剧由《生活大爆炸》联合编剧查克·罗瑞担任制片。道格拉斯剧中饰演曾经红极一时的明星现下却只能靠教授表演课程为生阿金饰演他的老友。道格拉斯上次出演电视剧集还是上世纪70年代的《旧金山风物记》而阿金上一部荧屏作品则是2001年的犯罪剧集《百厦街》。",
"m3u8List": [
"08$https://zuikzy.51moca.com/2018/11/23/XoIqsGnIP7IED2LS/playlist.m3u8",
"07$https://zkcdn.yiya520.com/2018/11/21/kJOL42dTmm6VJkqK/playlist.m3u8",
"06$https://zkcdn.yiya520.com/2018/11/21/f8gxIqAchIPyxlAg/playlist.m3u8",
"05$https://zkcdn.yiya520.com/2018/11/21/mTG5GkXpB7yro1sQ/playlist.m3u8",
"04$https://zkcdn.yiya520.com/2018/11/19/HjQAbC0lzzHAusIw/playlist.m3u8",
"03$https://zkcdn.yiya520.com/2018/11/19/qlN7TvZUDDueiefE/playlist.m3u8",
"02$https://zkcdn.yiya520.com/2018/11/18/2P9HAA5H1KvkMgm2/playlist.m3u8",
"01$https://zkcdn.yiya520.com/2018/11/18/KUD3QMMS4UGnNA3Y/playlist.m3u8"
],
"rate": "9.2"
},
"rate": "9.2",
"id": 255
},
{
"key": "mahuazy",
"ids": 21869,
"site": {
"id": 1,
"key": "mahuazy",
"name": "麻花资源",
"api": "http://www.mhapi123.com/inc/ldg_api.php",
"download": "",
"group": "默认",
"isActive": true,
"status": "可用"
},
"name": "海上钢琴师",
"detail": {
"last": "2019-12-26 17:45:44",
"id": 21869,
"tid": 10,
"name": "海上钢琴师",
"type": "剧情片",
"pic": "https://mahuapic.com/upload/vod/2019-12-26/201912261577353503.png",
"lang": "英语",
"area": "其它",
"year": 2019,
"state": 0,
"note": "HD",
"actor": "蒂姆·罗斯",
"director": "朱塞佩·托纳多雷",
"dl": {
"dd": {
"_t": "HD$https://mhkuaibo.com/20191226/4s3AkbXZ/index.m3u8$mahua",
"_flag": "mahua"
}
},
"des": "<span style=\"color: rgb(51, 51, 51); font-family: Tahoma, Helvetica, Arial, 微软雅黑, sans-serif; font-size: 14px; line-height: 22px; background-color: rgb(248, 248, 248);\">1900年Virginian号豪华邮轮上一个孤儿被遗弃在头等舱由船上的水手抚养长大取名1900。1900慢慢长大显示出了无师自通的非凡钢琴天赋在船上的乐队表演钢琴每个听过他演奏的人都被深深打动。爵士乐鼻祖杰尼听说了1900的高超技艺专门上船和他比赛最后自叹弗如黯然离去。可惜这一切的事情都发生在海上1900从来不愿踏上陆地直到有一天他爱上了一个女孩情愫在琴键上流淌。他会不会为了爱情踏上陆地开始新的生活用他的琴声惊艳世界他将怎样谱写自己非凡的人生。</span><br />",
"m3u8List": [
"HD$https://mhkuaibo.com/20191226/4s3AkbXZ/index.m3u8$mahua"
],
"rate": "9.3"
},
"rate": "9.3",
"id": 254
},
{
"key": "mahuazy",
"ids": 22567,
"site": {
"id": 1,
"key": "mahuazy",
"name": "麻花资源",
"api": "http://www.mhapi123.com/inc/ldg_api.php",
"download": "",
"group": "默认",
"isActive": true,
"status": "可用"
},
"name": "王冠第一季",
"detail": {
"last": "2019-12-19 11:41:40",
"id": 22567,
"tid": 15,
"name": "王冠第一季",
"type": "欧美剧",
"pic": "https://mahuapic.com/upload/vod/2019-12-19/15767269760.jpg",
"lang": "英语",
"area": "美国",
"year": 2016,
"state": 0,
"note": "完结",
"actor": "克莱尔·芙伊,马特·史密斯,约翰·利思戈,凡妮莎·柯比",
"director": "本·卡隆,史蒂芬·戴德利,菲利普·马丁,朱里安·杰拉德",
"dl": {
"dd": {
"_t": "第01集$https://mhyunbo.com/20191218/5vUSpghQ/index.m3u8$mahua#第02集$https://mhyunbo.com/20191218/jC9O5JXb/index.m3u8$mahua#第03集$https://mhyunbo.com/20191218/yHN6zIDc/index.m3u8$mahua#第04集$https://mhyunbo.com/20191218/q47c0tVo/index.m3u8$mahua#第05集$https://mhyunbo.com/20191218/PBckT1Qt/index.m3u8$mahua#第06集$https://mhyunbo.com/20191218/BSy4h1fR/index.m3u8$mahua#第07集$https://mhyunbo.com/20191218/gn2peH5k/index.m3u8$mahua#第08集$https://mhyunbo.com/20191218/2UNcvDq5/index.m3u8$mahua#第09集$https://mhyunbo.com/20191218/ROV7hhdI/index.m3u8$mahua#第10集$https://mhyunbo.com/20191218/VnSKiBc4/index.m3u8$mahua",
"_flag": "mahua"
}
},
"des": "马特·史密斯和约翰·利斯高加盟Netflix剧集《王冠》(The Crown暂译),二人分别饰演菲利普亲王和丘吉尔。剧集剧本由《女王》编剧彼得·摩根创作,首播集由《时时刻刻》导演史蒂芬·戴德利执导,讲述伊丽莎白二世与丘吉尔在二战后,重塑英伦的故事。之前确定由克莱尔·福伊出演伊丽莎白二世。",
"m3u8List": [
"第01集$https://mhyunbo.com/20191218/5vUSpghQ/index.m3u8$mahua",
"第02集$https://mhyunbo.com/20191218/jC9O5JXb/index.m3u8$mahua",
"第03集$https://mhyunbo.com/20191218/yHN6zIDc/index.m3u8$mahua",
"第04集$https://mhyunbo.com/20191218/q47c0tVo/index.m3u8$mahua",
"第05集$https://mhyunbo.com/20191218/PBckT1Qt/index.m3u8$mahua",
"第06集$https://mhyunbo.com/20191218/BSy4h1fR/index.m3u8$mahua",
"第07集$https://mhyunbo.com/20191218/gn2peH5k/index.m3u8$mahua",
"第08集$https://mhyunbo.com/20191218/2UNcvDq5/index.m3u8$mahua",
"第09集$https://mhyunbo.com/20191218/ROV7hhdI/index.m3u8$mahua",
"第10集$https://mhyunbo.com/20191218/VnSKiBc4/index.m3u8$mahua"
],
"rate": "9.2"
},
"rate": "9.2",
"id": 253
},
{
"id": 252,
"key": "mahuazy",
"ids": 29806,
"site": {
"id": 1,
"key": "mahuazy",
"name": "麻花资源",
"api": "https://www.mhapi123.com/inc/api.php",
"download": "",
"group": "默认",
"isActive": true,
"status": "可用"
},
"name": "最后的棒棒",
"rate": "9.6",
"detail": {
"last": "2020-04-12 15:43:02",
"id": 29806,
"tid": 20,
"name": "最后的棒棒",
"type": "记录片",
"pic": "https://mahuapic.com/upload/vod/2020-04-12/15866774000.jpg",
"lang": "国语",
"area": "大陆",
"year": 2016,
"state": 0,
"note": "完结",
"actor": "何苦",
"director": "何苦",
"dl": {
"dd": {
"_t": "第01集$https://mahua-kb.com/20200412/vpFPIG1f/index.m3u8#第02集$https://mahua-kb.com/20200412/K0b5AvUp/index.m3u8#第03集$https://mahua-kb.com/20200412/tgpvWhFj/index.m3u8#第04集$https://mahua-kb.com/20200412/9mc4bPsO/index.m3u8#第05集$https://mahua-kb.com/20200412/gs0qmble/index.m3u8#第06集$https://mahua-kb.com/20200412/l2eDtPPY/index.m3u8#第07集$https://mahua-kb.com/20200412/7LrOTyqT/index.m3u8#第08集$https://mahua-kb.com/20200412/rnLFz9kO/index.m3u8#第09集$https://mahua-kb.com/20200412/nOTSjrba/index.m3u8#第10集$https://mahua-kb.com/20200412/qrfl8OzL/index.m3u8#第11集$https://mahua-kb.com/20200412/Y4sTsCWm/index.m3u8#第12集$https://mahua-kb.com/20200412/w5L2lXpy/index.m3u8#第13集$https://mahua-kb.com/20200412/Up2AGSWE/index.m3u8",
"_flag": "mahua"
}
},
"des": "改革开放之初,山城重庆特殊的地理环境孕育了一个特殊的行业——山城棒棒军。爬坡上坎,负重前行的三十多年,数十万棒棒大军不仅挑走了汗水浸泡的年华,也挑走了属于自己的年代。癸巳岁末,几个佝偻背影即将道别正在消逝的行业,一名退役中校扛起一根棒棒开始了自己的追寻——辉煌与尴尬,艰韧和无奈,他们的人生无须评说,他们的故事值得铭记。",
"m3u8List": [
"第01集$https://mahua-kb.com/20200412/vpFPIG1f/index.m3u8",
"第02集$https://mahua-kb.com/20200412/K0b5AvUp/index.m3u8",
"第03集$https://mahua-kb.com/20200412/tgpvWhFj/index.m3u8",
"第04集$https://mahua-kb.com/20200412/9mc4bPsO/index.m3u8",
"第05集$https://mahua-kb.com/20200412/gs0qmble/index.m3u8",
"第06集$https://mahua-kb.com/20200412/l2eDtPPY/index.m3u8",
"第07集$https://mahua-kb.com/20200412/7LrOTyqT/index.m3u8",
"第08集$https://mahua-kb.com/20200412/rnLFz9kO/index.m3u8",
"第09集$https://mahua-kb.com/20200412/nOTSjrba/index.m3u8",
"第10集$https://mahua-kb.com/20200412/qrfl8OzL/index.m3u8",
"第11集$https://mahua-kb.com/20200412/Y4sTsCWm/index.m3u8",
"第12集$https://mahua-kb.com/20200412/w5L2lXpy/index.m3u8",
"第13集$https://mahua-kb.com/20200412/Up2AGSWE/index.m3u8"
],
"rate": "9.6"
}
},
{
"id": 251,
"key": "mahuazy",
"ids": 50694,
"site": {
"id": 1,
"key": "mahuazy",
"name": "麻花资源",
"api": "https://www.mhapi123.com/inc/api.php",
"download": "",
"group": "默认",
"isActive": true,
"status": "可用"
},
"name": "以你的心诠释我的爱",
"index": 2,
"rate": "9.5",
"detail": {
"last": "2020-11-13 09:34:47",
"id": 50694,
"tid": 17,
"name": "以你的心诠释我的爱",
"type": "泰剧",
"pic": "https://mahuapic.com/upload/vod/2020-10-23/16034119330.jpg",
"lang": "泰语",
"area": "泰国",
"year": 2020,
"state": 0,
"note": "更新至04集",
"actor": "克里特·安努艾德奇康,普提蓬·阿萨拉塔纳功",
"director": "纳卢拜·库诺",
"dl": {
"dd": {
"_t": "第01集$https://b.mhqiyi.com/20201022/K4gdEqpu/index.m3u8#第02集$https://b.mhqiyi.com/20201029/h3maf38g/index.m3u8#第03集$https://e.mahua-kb.com/20201105/HVK7wMlM/index.m3u8#第04集$https://b.mhqiyi.com/20201112/pOl6JaA7/index.m3u8",
"_flag": "mahua"
}
},
"des": "这部电视剧是BKPP project的一部分",
"m3u8List": [
"第01集$https://b.mhqiyi.com/20201022/K4gdEqpu/index.m3u8",
"第02集$https://b.mhqiyi.com/20201029/h3maf38g/index.m3u8",
"第03集$https://e.mahua-kb.com/20201105/HVK7wMlM/index.m3u8",
"第04集$https://b.mhqiyi.com/20201112/pOl6JaA7/index.m3u8"
],
"rate": "9.5"
}
},
{
"id": 250,
"key": "niuniucj",
"ids": 20044,
"site": {
@@ -12,6 +266,7 @@
"isActive": 1
},
"name": "此画怎讲",
"rate": "8.1",
"detail": {
"last": "2020-09-23 23:23:36",
"id": 20044,
@@ -72,11 +327,10 @@
"第30集$https://s6.niuniu-baidu.com/2020/09/23/37H4vtEiTXcjSzoa/index.m3u8"
],
"rate": "8.1"
},
"rate": "8.1",
"id": 250
}
},
{
"id": 249,
"key": "niuniucj",
"ids": 4255,
"site": {
@@ -89,6 +343,7 @@
"isActive": 1
},
"name": "紧急呼救第一季",
"rate": "8.6",
"detail": {
"last": "2019-10-10 19:19:15",
"id": 4255,
@@ -129,11 +384,10 @@
"第10集$https://s1.niuniu-baidu.com/20191010/XZjWRMxLgh8nyFlT/index.m3u8"
],
"rate": "8.6"
},
"rate": "8.6",
"id": 249
}
},
{
"id": 248,
"key": "niuniucj",
"ids": 20632,
"site": {
@@ -146,6 +400,7 @@
"isActive": 1
},
"name": "小小世界",
"rate": "9.4",
"detail": {
"last": "2020-10-03 12:00:49",
"id": 20632,
@@ -182,9 +437,7 @@
"第06集$https://s6.niuniu-baidu.com/2020/10/03/U0JFALI1lHOjWCfw/index.m3u8"
],
"rate": "9.4"
},
"rate": "9.4",
"id": 248
}
},
{
"id": 247,
@@ -9238,6 +9491,7 @@
}
},
{
"id": 22,
"key": "mahuazy",
"ids": 20868,
"site": {
@@ -9250,6 +9504,7 @@
"group": "默认"
},
"name": "铁血战士(1987)",
"rate": "7.7",
"detail": {
"last": "2019-11-23 10:59:36",
"id": 20868,
@@ -9275,9 +9530,7 @@
"HD$https://mhbobo.com/20191121/vyWmCGRH/index.m3u8"
],
"rate": "7.7"
},
"rate": "7.7",
"id": 22
}
},
{
"id": 21,

View File

@@ -3,7 +3,7 @@
"id": 1,
"key": "mahuazy",
"name": "麻花资源",
"api": "https://www.mhapi123.com/inc/api.php",
"api": "http://www.mhapi123.com/inc/ldg_api.php",
"download": "",
"group": "默认",
"isActive": true,
@@ -11,9 +11,9 @@
},
{
"id": 2,
"key": "niuniucj",
"name": "牛牛资源",
"api": "http://v.niuniucj.com/inc/api.php",
"key": "1886zy",
"name": "1886 资源",
"api": "http://cj.1886zy.co/inc/api.php",
"download": "",
"group": "默认",
"isActive": true,
@@ -21,46 +21,6 @@
},
{
"id": 3,
"key": "88zyw",
"name": "88 影视资源站",
"api": "http://www.88zyw.net/inc/api.php",
"download": "",
"group": "默认",
"isActive": true,
"status": "可用"
},
{
"id": 4,
"key": "apibdzy",
"name": "百度云资源",
"api": "https://api.apibdzy.com/api.php/provide/vod/at/xml",
"download": "",
"group": "默认",
"isActive": true,
"status": "可用"
},
{
"id": 5,
"key": "mbo",
"name": "秒播资源",
"api": "http://caiji.mb77.vip/inc/api.php",
"download": "",
"group": "默认",
"isActive": true,
"status": "可用"
},
{
"id": 6,
"key": "zuidazy",
"name": "最大资源网",
"api": "http://www.zdziyuan.com/inc/api.php",
"download": "http://www.zdziyuan.com/inc/apidown.php",
"group": "默认",
"isActive": true,
"status": "可用"
},
{
"id": 7,
"key": "123ku",
"name": "123 资源",
"api": "http://cj.123ku2.com:12315/inc/api.php",
@@ -69,8 +29,58 @@
"isActive": true,
"status": "可用"
},
{
"id": 4,
"key": "subo988",
"name": "速播资源站",
"api": "https://www.subo988.com/inc/api.php",
"download": "",
"group": "默认",
"isActive": true,
"status": "可用"
},
{
"id": 5,
"key": "88zyw",
"name": "88 影视资源站",
"api": "http://www.88zyw.net/inc/api.php",
"download": "",
"group": "默认",
"isActive": true,
"status": "可用"
},
{
"key": "zuidazy",
"id": 6,
"name": "最大资源网",
"api": "http://www.zdziyuan.com/inc/ldg_sea.php",
"download": "http://www.zdziyuan.com/inc/apidown.php",
"group": "默认",
"isActive": true,
"status": "可用"
},
{
"key": "mbo",
"id": 7,
"name": "秒播资源",
"api": "http://caiji.mb77.vip/inc/seacmsapi.php",
"download": "",
"group": "默认",
"isActive": true,
"status": "可用"
},
{
"id": 8,
"key": "apibdzy",
"name": "百度云资源",
"api": "https://api.apibdzy.com/api.php/provide/vod/at/xml",
"download": "",
"group": "默认",
"isActive": true,
"status": "可用"
},
{
"id": 9,
"key": "okzy",
"name": "OK 资源网",
"api": "http://cj.okzy.tv/inc/api.php",
@@ -80,7 +90,7 @@
"status": "可用"
},
{
"id": 9,
"id": 10,
"key": "kuyunzy",
"name": "酷云资源",
"api": "http://caiji.kuyun98.com/inc/ldg_api.php",
@@ -90,7 +100,7 @@
"status": "可用"
},
{
"id": 10,
"id": 11,
"key": "kubozy",
"name": "酷播资源",
"api": "http://api.kbzyapi.com/inc/api.php",
@@ -100,7 +110,7 @@
"status": "可用"
},
{
"id": 11,
"id": 12,
"key": "yongjiuzy",
"name": "永久资源",
"api": "http://cj.yongjiuzyw.com/inc/api.php",
@@ -110,7 +120,7 @@
"status": "可用"
},
{
"id": 12,
"id": 13,
"key": "rrzy",
"name": "人人资源",
"api": "https://www.rrzyw.cc/api.php/provide/vod/from/rrm3u8/at/xml/",
@@ -120,7 +130,7 @@
"status": "可用"
},
{
"id": 13,
"id": 14,
"key": "bbkdj",
"name": "步步高顶尖资源网",
"api": "http://api.bbkdj.com/api",
@@ -129,16 +139,6 @@
"isActive": true,
"status": "可用"
},
{
"id": 14,
"key": "solezy",
"name": "搜乐资源网",
"api": "https://www.caijizy.vip/api.php/provide/vod/at/xml/",
"download": "",
"group": "默认",
"isActive": true,
"status": "可用"
},
{
"id": 15,
"key": "zuixinzy",
@@ -151,66 +151,6 @@
},
{
"id": 16,
"key": "605zy",
"name": "605资源",
"api": "http://www.605zy.net/inc/seacmsapi.php",
"download": "",
"group": "默认",
"isActive": true,
"status": "可用"
},
{
"id": 17,
"key": "subo988",
"name": "速播资源站",
"api": "https://www.subo988.com/inc/api.php",
"download": "",
"group": "默认",
"isActive": true,
"status": "可用"
},
{
"id": 18,
"key": "1886zy",
"name": "1886 资源",
"api": "http://cj.1886zy.co/inc/api.php",
"download": "",
"group": "默认",
"isActive": true,
"status": "可用"
},
{
"id": 19,
"key": "doubanzy",
"name": "豆瓣电影资源",
"api": "http://v.1988cj.com/inc/api.php",
"download": "http://v.1988cj.com/inc/apidown.php",
"group": "默认",
"isActive": true,
"status": "可用"
},
{
"id": 20,
"key": "135zy",
"name": "135 资源网",
"api": "http://cj.zycjw1.com/inc/api.php",
"download": "http://cj.zycjw1.com/inc/apidown.php",
"group": "默认",
"isActive": true,
"status": "可用"
},
{
"id": 21,
"key": "mgtvzy",
"name": "芒果 TV 资源网",
"api": "https://api.shijiapi.com/api.php/provide/vod/at/xml/",
"download": "",
"group": "默认",
"isActive": true,
"status": "可用"
},
{
"id": 22,
"key": "209zy",
"name": "209 资源",
"api": "http://cj.1156zy.com/inc/api.php",
@@ -218,55 +158,5 @@
"group": "默认",
"isActive": true,
"status": "可用"
},
{
"id": 23,
"key": "kkzy",
"name": "快快资源",
"api": "https://api.kkzy.tv/inc/api.php",
"download": "",
"group": "默认",
"isActive": true,
"status": "可用"
},
{
"id": 24,
"key": "wolongzy",
"name": "卧龙资源",
"api": "http://cj.wlzy.tv/inc/api_mac.php",
"download": "",
"group": "默认",
"isActive": true,
"status": "可用"
},
{
"id": 25,
"key": "mokazy",
"name": "魔卡资源网",
"api": "https://cj.heiyap.com/api.php/provide/vod/at/xml/",
"download": "",
"group": "默认",
"isActive": true,
"status": "可用"
},
{
"id": 26,
"key": "158zy",
"name": "壹伍捌资源网",
"api": "http://cj.158zyz.net:158/inc/api.php",
"download": "",
"group": "默认",
"isActive": true,
"status": "可用"
},
{
"id": 27,
"key": "kyzy",
"name": "快影资源站",
"api": "https://www.kyzy.tv/api.php/kyyun/vod/at/xml/",
"download": "",
"group": "默认",
"isActive": true,
"status": "可用"
}
]

View File

@@ -19,7 +19,9 @@ const setting = [
scheme: '',
url: '',
port: ''
}
},
allowPassWhenIptvCheck: true,
autocleanWhenIptvCheck: false
}
]
@@ -66,7 +68,7 @@ const localKey = [
},
{
name: 'escape',
desc: '退出全屏',
desc: '退出全屏/精简模式',
key: 'esc'
},
{
@@ -89,6 +91,21 @@ const localKey = [
desc: '跳到视频结束位置',
key: 'end'
},
{
name: 'startPosition',
desc: '标记片头',
key: 'ctrl+home'
},
{
name: 'endPosition',
desc: '标记片尾',
key: 'ctrl+end'
},
{
name: 'clearPosition',
desc: '清除标记',
key: 'ctrl+del'
},
{
name: 'opacityUp',
desc: '透明度调高',
@@ -113,6 +130,11 @@ const localKey = [
name: 'mini',
desc: '进入或退出mini模式',
key: 'alt+m'
},
{
name: 'resetMini',
desc: '重置mini窗口',
key: 'ctrl+0'
}
]

View File

@@ -1,22 +0,0 @@
import db from './dexie'
const { iptvSearch } = db
export default {
async add (doc) {
return await iptvSearch.add(doc)
},
async find (doc) {
return await iptvSearch.get(doc)
},
async update (id, docs) {
return await iptvSearch.update(id, docs)
},
async all () {
return await iptvSearch.toArray()
},
async remove (id) {
return await iptvSearch.delete(id)
},
async clear () {
return await iptvSearch.clear()
}
}

View File

@@ -1,5 +1,5 @@
import Vue from 'vue'
import { Message, Button, Table, TableColumn, Tag, Input, Dialog, Form, FormItem, Switch, Select, Option, Checkbox, Autocomplete, Col, Tree } from 'element-ui'
import { Message, Button, Table, TableColumn, Tag, Input, InputNumber, Dialog, Form, FormItem, Switch, Select, Option, Checkbox, Autocomplete, Col, Tree, Divider } from 'element-ui'
import Plugin from 'v-fit-columns'
Vue.use(Button)
Vue.use(Col)
@@ -7,6 +7,7 @@ Vue.use(Table)
Vue.use(TableColumn)
Vue.use(Tag)
Vue.use(Input)
Vue.use(InputNumber)
Vue.use(Dialog)
Vue.use(Form)
Vue.use(FormItem)
@@ -17,4 +18,5 @@ Vue.use(Option)
Vue.use(Checkbox)
Vue.use(Autocomplete)
Vue.use(Tree)
Vue.use(Divider)
Vue.prototype.$message = Message

View File

@@ -92,9 +92,10 @@ const zy = {
axios.post(url).then(res => {
const data = res.data
const json = parser.parse(data, this.xmlConfig)
const jsondata = json.rss === undefined ? json : json.rss
const arr = []
if (json.rss.class) {
for (const i of json.rss.class.ty) {
if (jsondata.class) {
for (const i of jsondata.class.ty) {
const j = {
tid: i._id,
name: i._t
@@ -104,10 +105,10 @@ const zy = {
}
const doc = {
class: arr,
page: json.rss.list._page,
pagecount: json.rss.list._pagecount,
pagesize: json.rss.list._pagesize,
recordcount: json.rss.list._recordcount
page: jsondata.list._page,
pagecount: jsondata.list._pagecount,
pagesize: jsondata.list._pagesize,
recordcount: jsondata.list._recordcount
}
resolve(doc)
}).catch(err => {
@@ -136,7 +137,8 @@ const zy = {
axios.post(url).then(async res => {
const data = res.data
const json = parser.parse(data, this.xmlConfig)
const videoList = json.rss.list.video
const jsondata = json.rss === undefined ? json : json.rss
const videoList = jsondata.list.video
resolve(videoList)
}).catch(err => {
reject(err)
@@ -163,11 +165,12 @@ const zy = {
axios.post(url).then(async res => {
const data = res.data
const json = parser.parse(data, this.xmlConfig)
const jsondata = json.rss === undefined ? json : json.rss
const pg = {
page: json.rss.list._page,
pagecount: json.rss.list._pagecount,
pagesize: json.rss.list._pagesize,
recordcount: json.rss.list._recordcount
page: jsondata.list._page,
pagecount: jsondata.list._pagecount,
pagesize: jsondata.list._pagesize,
recordcount: jsondata.list._recordcount
}
resolve(pg)
}).catch(err => {
@@ -191,8 +194,9 @@ const zy = {
axios.post(url, { timeout: 3000 }).then(res => {
const data = res.data
const json = parser.parse(data, this.xmlConfig)
if (json && json.rss && json.rss.list) {
const videoList = json.rss.list.video
const jsondata = json.rss === undefined ? json : json.rss
if (json && jsondata && jsondata.list) {
const videoList = jsondata.list.video
resolve(videoList)
}
}).catch(err => {
@@ -216,14 +220,16 @@ const zy = {
axios.post(url).then(res => {
const data = res.data
const json = parser.parse(data, this.xmlConfig)
const videoList = json.rss.list.video
const jsondata = json.rss === undefined ? json : json.rss
const videoList = jsondata.list.video
// Parse m3u8List
var m3u8List = []
const dd = videoList.dl.dd
const type = Object.prototype.toString.call(dd)
if (type === '[object Array]') {
for (const i of dd) {
if (i._flag.indexOf('m3u8') >= 0) {
// 如果含有多个视频列表的话, 仅获取m3u8列表
if (i._flag.includes('m3u8')) {
m3u8List = i._t.split('#')
}
}
@@ -255,7 +261,20 @@ const zy = {
axios.post(url).then(res => {
const data = res.data
const json = parser.parse(data, this.xmlConfig)
const videoList = json.rss.list.video
const jsondata = json.rss === undefined ? json : json.rss
const videoList = jsondata.list.video
// Parse m3u8List
var m3u8List = []
const dd = videoList.dl.dd
const type = Object.prototype.toString.call(dd)
if (type === '[object Array]') {
for (const i of dd) {
m3u8List = i._t.split('#')
}
} else {
m3u8List = dd._t.split('#')
}
videoList.m3u8List = m3u8List
resolve(videoList)
}).catch(err => {
reject(err)
@@ -374,17 +393,15 @@ const zy = {
async proxy () {
return new Promise((resolve, reject) => {
setting.find().then(db => {
if (db.proxy) {
if (db.proxy.type === 'none') {
session.setProxy({ proxyRules: 'direct://' })
if (db && db.proxy && db.proxy.type === 'manual') {
if (db.proxy.scheme && db.proxy.url && db.proxy.port) {
const proxyURL = db.proxy.scheme + '://' + db.proxy.url.trim() + ':' + db.proxy.port.trim()
session.setProxy({ proxyRules: proxyURL })
http.globalAgent = https.globalAgent = new ElectronProxyAgent(session)
} else if (db.proxy.type === 'manual') {
if (db.proxy.scheme && db.proxy.url && db.proxy.port) {
const proxyURL = db.proxy.scheme + '://' + db.proxy.url.trim() + ':' + db.proxy.port.trim()
session.setProxy({ proxyRules: proxyURL })
http.globalAgent = https.globalAgent = new ElectronProxyAgent(session)
}
}
} else {
session.setProxy({ proxyRules: 'direct://' })
http.globalAgent = https.globalAgent = new ElectronProxyAgent(session)
}
// 不要删了,留着测试用
// axios.get('https://api.my-ip.io/ip').then(res => console.log(res))

View File

@@ -1,6 +1,6 @@
module.exports = {
pages: {
index: 'src/main.js',
index: 'src/main.js'
},
pluginOptions: {
electronBuilder: {

1560
yarn.lock

File diff suppressed because it is too large Load Diff