Compare commits

...

138 Commits

Author SHA1 Message Date
Hunlongyu
68fd0d0c6a Merge pull request #789 from Hunlongyu/dependabot/npm_and_yarn/ejs-3.1.8
Bump ejs from 3.1.3 to 3.1.8
2022-09-27 08:47:03 +08:00
dependabot[bot]
a95403849d Bump ejs from 3.1.3 to 3.1.8
Bumps [ejs](https://github.com/mde/ejs) from 3.1.3 to 3.1.8.
- [Release notes](https://github.com/mde/ejs/releases)
- [Changelog](https://github.com/mde/ejs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mde/ejs/compare/v3.1.3...v3.1.8)

---
updated-dependencies:
- dependency-name: ejs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-26 07:05:21 +00:00
Hunlongyu
554f8d87bc Merge pull request #763 from Hunlongyu/dependabot/npm_and_yarn/postcss-7.0.39
Bump postcss from 7.0.32 to 7.0.39
2022-09-26 15:04:03 +08:00
dependabot[bot]
895619d194 Bump postcss from 7.0.32 to 7.0.39
Bumps [postcss](https://github.com/postcss/postcss) from 7.0.32 to 7.0.39.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/7.0.39/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/7.0.32...7.0.39)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-20 09:08:10 +00:00
Hunlongyu
fd77157f72 Merge pull request #788 from Hunlongyu/dependabot/npm_and_yarn/ejs-and-vue/cli-plugin-babel-and-vue/cli-plugin-vuex-and-vue/cli-service-3.1.8
Bump ejs, @vue/cli-plugin-babel, @vue/cli-plugin-vuex and @vue/cli-service
2022-09-20 17:06:41 +08:00
dependabot[bot]
0d8786db21 Bump ejs, @vue/cli-plugin-babel, @vue/cli-plugin-vuex and @vue/cli-service
Bumps [ejs](https://github.com/mde/ejs), [@vue/cli-plugin-babel](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-babel), [@vue/cli-plugin-vuex](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-vuex) and [@vue/cli-service](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-service). These dependencies needed to be updated together.

Updates `ejs` from 3.1.3 to 3.1.8
- [Release notes](https://github.com/mde/ejs/releases)
- [Changelog](https://github.com/mde/ejs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mde/ejs/compare/v3.1.3...v3.1.8)

Updates `@vue/cli-plugin-babel` from 4.5.11 to 5.0.8
- [Release notes](https://github.com/vuejs/vue-cli/releases)
- [Changelog](https://github.com/vuejs/vue-cli/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-cli/commits/v5.0.8/packages/@vue/cli-plugin-babel)

Updates `@vue/cli-plugin-vuex` from 4.5.11 to 5.0.8
- [Release notes](https://github.com/vuejs/vue-cli/releases)
- [Changelog](https://github.com/vuejs/vue-cli/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-cli/commits/v5.0.8/packages/@vue/cli-plugin-vuex)

Updates `@vue/cli-service` from 4.5.11 to 5.0.8
- [Release notes](https://github.com/vuejs/vue-cli/releases)
- [Changelog](https://github.com/vuejs/vue-cli/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-cli/commits/v5.0.8/packages/@vue/cli-service)

---
updated-dependencies:
- dependency-name: ejs
  dependency-type: indirect
- dependency-name: "@vue/cli-plugin-babel"
  dependency-type: direct:development
- dependency-name: "@vue/cli-plugin-vuex"
  dependency-type: direct:development
- dependency-name: "@vue/cli-service"
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-19 03:29:18 +00:00
Hunlongyu
e9e86c12bd Merge pull request #787 from Hunlongyu/dependabot/npm_and_yarn/jszip-3.10.1
Bump jszip from 3.5.0 to 3.10.1
2022-09-19 11:26:10 +08:00
hunlongyu
c61a3e2f1d fix: 蓝奏云外链被劫持跳转黄色网站 2022-09-13 08:51:58 +08:00
dependabot[bot]
9f36969e81 Bump jszip from 3.5.0 to 3.10.1
Bumps [jszip](https://github.com/Stuk/jszip) from 3.5.0 to 3.10.1.
- [Release notes](https://github.com/Stuk/jszip/releases)
- [Changelog](https://github.com/Stuk/jszip/blob/main/CHANGES.md)
- [Commits](https://github.com/Stuk/jszip/compare/v3.5.0...v3.10.1)

---
updated-dependencies:
- dependency-name: jszip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-08 15:03:20 +00:00
Hunlongyu
b8c970cefe Merge pull request #762 from Hunlongyu/dependabot/npm_and_yarn/node-fetch-2.6.7
Bump node-fetch from 2.6.1 to 2.6.7
2022-08-30 15:04:39 +08:00
Hunlongyu
da1ee461db Merge pull request #761 from Hunlongyu/dependabot/npm_and_yarn/lodash-4.17.21
Bump lodash from 4.17.20 to 4.17.21
2022-08-27 13:04:28 +08:00
Hunlongyu
c691a96d26 Merge pull request #774 from Hunlongyu/dependabot/npm_and_yarn/shell-quote-1.7.3
Bump shell-quote from 1.7.2 to 1.7.3
2022-08-25 16:22:54 +08:00
dependabot[bot]
90d2bb3e47 Bump lodash from 4.17.20 to 4.17.21
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.20 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.20...4.17.21)

---
updated-dependencies:
- dependency-name: lodash
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-17 09:02:18 +00:00
dependabot[bot]
2bfaad5500 Bump node-fetch from 2.6.1 to 2.6.7
Bumps [node-fetch](https://github.com/node-fetch/node-fetch) from 2.6.1 to 2.6.7.
- [Release notes](https://github.com/node-fetch/node-fetch/releases)
- [Commits](https://github.com/node-fetch/node-fetch/compare/v2.6.1...v2.6.7)

---
updated-dependencies:
- dependency-name: node-fetch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-17 09:02:16 +00:00
dependabot[bot]
c186ba5e4e Bump shell-quote from 1.7.2 to 1.7.3
Bumps [shell-quote](https://github.com/substack/node-shell-quote) from 1.7.2 to 1.7.3.
- [Release notes](https://github.com/substack/node-shell-quote/releases)
- [Changelog](https://github.com/substack/node-shell-quote/blob/master/CHANGELOG.md)
- [Commits](https://github.com/substack/node-shell-quote/compare/v1.7.2...1.7.3)

---
updated-dependencies:
- dependency-name: shell-quote
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-17 09:02:12 +00:00
Hunlongyu
38378794ea Merge pull request #784 from Hunlongyu/dependabot/npm_and_yarn/terser-4.8.1
Bump terser from 4.8.0 to 4.8.1
2022-08-17 17:00:40 +08:00
dependabot[bot]
841f3424f9 Bump terser from 4.8.0 to 4.8.1
Bumps [terser](https://github.com/terser/terser) from 4.8.0 to 4.8.1.
- [Release notes](https://github.com/terser/terser/releases)
- [Changelog](https://github.com/terser/terser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/terser/terser/commits)

---
updated-dependencies:
- dependency-name: terser
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-21 04:22:32 +00:00
hunlongyu
81b34ff54a release: v2.2.8 2022-07-13 18:34:33 +08:00
hunlongyu
9b9db55f49 feat: 移除推荐,修改默认远程视频源 2022-07-13 18:33:50 +08:00
hunlongyu
e7c7367ea8 release: v2.8.7 2022-07-13 16:44:48 +08:00
hunlongyu
5e37ef32fd release: v2.8.6 2022-07-13 10:58:16 +08:00
hunlongyu
85525745a1 feat: remove qrcode and modify sites url 2022-07-13 10:56:50 +08:00
hunlongyu
c7f581a088 fix: 让项目能正常跑起来 2022-07-13 09:49:12 +08:00
Hunlongyu
a88dfb1bc3 Merge pull request #769 from Hunlongyu/dependabot/npm_and_yarn/eventsource-1.1.1
Bump eventsource from 1.0.7 to 1.1.1
2022-07-03 21:29:37 +08:00
Hunlongyu
410cd8fc1a Merge pull request #767 from cuiocean/dependabot/npm_and_yarn/dexie-3.2.2
Bump dexie from 3.0.3 to 3.2.2
2022-06-16 09:43:55 +08:00
dependabot[bot]
bb30be3c4d Bump eventsource from 1.0.7 to 1.1.1
Bumps [eventsource](https://github.com/EventSource/eventsource) from 1.0.7 to 1.1.1.
- [Release notes](https://github.com/EventSource/eventsource/releases)
- [Changelog](https://github.com/EventSource/eventsource/blob/master/HISTORY.md)
- [Commits](https://github.com/EventSource/eventsource/compare/v1.0.7...v1.1.1)

---
updated-dependencies:
- dependency-name: eventsource
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-01 18:54:40 +00:00
dependabot[bot]
6230c9e87a Bump dexie from 3.0.3 to 3.2.2
Bumps [dexie](https://github.com/dfahlander/Dexie.js) from 3.0.3 to 3.2.2.
- [Release notes](https://github.com/dfahlander/Dexie.js/releases)
- [Commits](https://github.com/dfahlander/Dexie.js/compare/v3.0.3...v3.2.2)

---
updated-dependencies:
- dependency-name: dexie
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-23 20:15:41 +00:00
Hunlongyu
93efb64211 Merge pull request #759 from cuiocean/dependabot/npm_and_yarn/electron-13.6.6
Bump electron from 11.5.0 to 13.6.6
2022-03-27 17:21:26 +08:00
dependabot[bot]
3c4dd91d36 Bump electron from 11.5.0 to 13.6.6
Bumps [electron](https://github.com/electron/electron) from 11.5.0 to 13.6.6.
- [Release notes](https://github.com/electron/electron/releases)
- [Changelog](https://github.com/electron/electron/blob/main/docs/breaking-changes.md)
- [Commits](https://github.com/electron/electron/compare/v11.5.0...v13.6.6)

---
updated-dependencies:
- dependency-name: electron
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-25 19:09:35 +00:00
Hunlongyu
45041fdab1 Merge pull request #746 from cuiocean/dependabot/npm_and_yarn/axios-0.21.2
Bump axios from 0.21.1 to 0.21.2
2021-10-13 08:57:18 +08:00
dependabot[bot]
bcf0613ff0 Bump axios from 0.21.1 to 0.21.2
Bumps [axios](https://github.com/axios/axios) from 0.21.1 to 0.21.2.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/master/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v0.21.1...v0.21.2)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-13 00:56:23 +00:00
Hunlongyu
3107b851c5 Merge pull request #745 from cuiocean/dependabot/npm_and_yarn/electron-11.5.0
Bump electron from 11.3.0 to 11.5.0
2021-10-13 08:55:37 +08:00
dependabot[bot]
b27883ad0f Bump electron from 11.3.0 to 11.5.0
Bumps [electron](https://github.com/electron/electron) from 11.3.0 to 11.5.0.
- [Release notes](https://github.com/electron/electron/releases)
- [Changelog](https://github.com/electron/electron/blob/main/docs/breaking-changes.md)
- [Commits](https://github.com/electron/electron/compare/v11.3.0...v11.5.0)

---
updated-dependencies:
- dependency-name: electron
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-12 22:51:49 +00:00
haiyangcui
e0c3502c3f Update x86.yml 2021-08-10 16:10:30 +02:00
haiyangcui
4c2db002eb 推荐页面添加"豆瓣华语电影" 2021-08-10 15:56:16 +02:00
haiyangcui
898f769d24 电影页面删除重复的数据 2021-08-10 15:24:02 +02:00
cuiocean
d6549c6a6b Update x86.yml 2021-08-10 15:23:13 +02:00
haiyangcui
eea4081d58 v2.8.5 2021-07-22 23:07:53 +02:00
haiyangcui
1e9f48e48c "按上映年份"排序改为降序排序,从新到旧排序 2021-06-05 22:01:35 +02:00
haiyangcui
0816933679 删除"作者推荐" 2021-05-28 23:10:52 +02:00
haiyangcui
8af6ff2bd7 修复分类刷新的一个bug 2021-05-24 22:29:55 +02:00
haiyangcui
c5d979fd28 引入xgplayer-mp4模块 2021-05-24 22:28:35 +02:00
haiyangcui
beb0c29326 源站增加"倒序排列"开关 2021-05-24 22:06:46 +02:00
haiyangcui
5509ace412 添加'豆瓣冷门佳片' 2021-05-09 23:45:07 +02:00
haiyangcui
6f296a1170 v2.8.4 2021-04-23 17:04:32 +02:00
haiyangcui
f8228a71f3 添加"热门美剧""热门英剧""热门国产剧"推荐列表 2021-04-22 11:47:09 +02:00
haiyangcui
9886f04b48 推荐页面添加"按评分"排序 2021-04-22 11:31:47 +02:00
haiyangcui
37c4aad4b0 Update lock files 2021-04-22 11:31:29 +02:00
haiyangcui
77d7b28e26 Update lock files 2021-04-21 21:10:51 +02:00
haiyangcui
3505b22344 简化调用解析网址的逻辑 2021-04-21 21:00:04 +02:00
haiyangcui
80cec08982 v2.8.3 2021-04-21 18:59:53 +02:00
haiyangcui
f92094daec 支持"豆瓣热门动画电影" 2021-04-21 18:57:54 +02:00
haiyangcui
2c06ef1da6 支持"豆瓣热门综艺" 2021-04-21 18:52:42 +02:00
haiyangcui
06403ece3f 因不明原因,全屏时上一集按钮被遮盖而无法点取.简单粗暴的解决方法:把所有按钮向右移动一下. 2021-04-21 18:42:26 +02:00
haiyangcui
39a6491403 添加"豆瓣热门纪录片" 2021-04-21 16:37:17 +02:00
haiyangcui
edb82eb3be 支持更新豆瓣推荐 2021-04-20 22:57:23 +02:00
haiyangcui
c7ca3df50d 修复设置默认解析网址 2021-04-20 22:13:16 +02:00
haiyangcui
0b198381b1 升级依赖 2021-04-20 22:11:53 +02:00
hunlongyu
2dcda83741 升级依赖 2021-04-16 09:09:33 +08:00
haiyangcui
5b3c3f0ff2 推荐页面,移除"删除" 2021-04-13 23:00:02 +02:00
haiyangcui
23454f7c7f v2.8.2 2021-04-13 17:49:02 +02:00
haiyangcui
0fdfe29343 增加"豆瓣高分电影" 2021-04-13 17:44:43 +02:00
haiyangcui
fa7a799e2b 支持缓存电影数据 2021-04-13 17:34:46 +02:00
haiyangcui
9c1a707279 初始的数据都移到iniData文件夹下 2021-04-13 17:07:18 +02:00
haiyangcui
7b69bb05d4 支持设置是否最小化时暂停播放 2021-04-13 17:06:33 +02:00
haiyangcui
3b6b6ea11b 记录窗口大小及位置 2021-04-12 17:57:56 +02:00
haiyangcui
9ec65ab027 Introduce searchFirstDetail 2021-04-12 16:48:58 +02:00
haiyangcui
da5531a947 主分类过滤, 检测关键词是否包含分类名. 福利过滤,检测分类名是否包含关键词 2021-04-12 14:55:06 +02:00
haiyangcui
4744f91f6b 过滤开启改为开关 2021-04-12 14:41:37 +02:00
haiyangcui
36b80c1d7e Import axios in Recommendation.vue 2021-04-12 12:56:26 +02:00
haiyangcui
15f4ab7248 修复"动漫"子分类消失的问题 2021-04-12 12:30:56 +02:00
haiyangcui
0e25c25480 推荐页面,加入"豆瓣热门电影"和"豆瓣热门剧集" 2021-04-12 12:26:29 +02:00
haiyangcui
7ff48a407d 删除log 2021-04-11 21:42:10 +02:00
haiyangcui
bbc371b1c5 添加初始化的设置文件 2021-04-11 20:31:00 +02:00
haiyangcui
d141d60e77 v2.8.1 2021-04-11 17:53:44 +02:00
haiyangcui
80af701e5c 删除经常跳出来的一个无用信息 2021-04-11 17:52:53 +02:00
haiyangcui
f0e70e03cb 在refreshClass内部调用classClick 2021-04-11 17:48:46 +02:00
haiyangcui
aba3472f2e 避免rootClassFilter r18ClassFilter数据为空时出错 2021-04-11 17:48:10 +02:00
haiyangcui
8772076d76 检测site变化,以及时刷新数据 2021-04-11 17:36:26 +02:00
haiyangcui
4abe03347a 修正数据库版本号 2021-04-11 17:31:31 +02:00
haiyangcui
b3e6e817dd 过滤开关关联局部变量,否则点击取消的话, 设置也会记录在setting里 2021-04-11 16:27:10 +02:00
haiyangcui
e48445c224 过滤设置更新后,刷新分类列表 2021-04-11 16:19:52 +02:00
haiyangcui
159f19d5ec 支持分开设置分类过滤和福利分类过滤 2021-04-11 16:11:20 +02:00
haiyangcui
c2953a530c 替换函数containsR18Keywords 2021-04-10 14:35:13 +02:00
haiyangcui
9166f129d8 移除过滤关键词列表中的空格 2021-04-10 13:52:59 +02:00
haiyangcui
72ac3eafdd 调高过滤词输入窗口 2021-04-10 13:52:40 +02:00
haiyangcui
8610b41fad 支持定义分类过滤关键词 2021-04-10 13:44:51 +02:00
haiyangcui
06e4c0e83e 只有当视频的核心信息变化时,才刷新播放页面 2021-04-09 14:10:03 +02:00
haiyangcui
5db3fd9f9b 历史页面初始化filteredList,否则视图切换有问题 2021-04-09 12:14:55 +02:00
haiyangcui
978afb2b38 删除无用代码 2021-04-08 15:38:07 +02:00
haiyangcui
b00b69a582 更新调用API的逻辑,如果某些重要数据没有API返回结果中,很可能是该源站已经失效,直接返回空数据 2021-04-06 16:49:00 +02:00
haiyangcui
9a33b0cfb3 搜索分三类,站内,组内,全站 2021-04-06 16:25:18 +02:00
haiyangcui
f4bf42bf07 将"有更新"切换按钮从工具栏移到顶层按钮区 2021-04-04 22:40:41 +02:00
haiyangcui
671a6e32d0 v2.8.0 2021-03-31 21:24:54 +02:00
haiyangcui
d05534fb17 恢复推荐视频的收藏,分享和详情功能 2021-03-31 20:47:02 +02:00
haiyangcui
b655c8c8bc 调整样式 2021-03-31 20:47:02 +02:00
haiyangcui
8fbea8ab57 添加"喜欢这部电影的人也喜欢" 2021-03-31 20:47:01 +02:00
haiyangcui
2ddfc66104 解决某些网址返回分类里含有{}字符串的问题 2021-03-30 09:54:00 +02:00
haiyangcui
26d62cdef4 历史页面增加按完成度排序 2021-03-29 22:41:08 +02:00
haiyangcui
7f6be795b5 v2.7.9 2021-03-29 17:49:11 +02:00
haiyangcui
d7fc97b3d7 有更新项目,进入详情页面,也清除有更新标记 2021-03-29 15:49:03 +02:00
haiyangcui
4a2aa9ee4b 历史页面添加只显示有更新过滤开关 2021-03-29 15:33:10 +02:00
haiyangcui
f4aeec0937 收藏页面添加有更新过滤开关 2021-03-29 15:31:08 +02:00
haiyangcui
ea06a52921 历史页面添加检查更新按钮 2021-03-29 15:12:11 +02:00
haiyangcui
26dc24d216 v2.7.8 2021-03-28 17:31:13 +02:00
haiyangcui
1c57c37997 降级xgplayer回2.17.3, 否则精简模式不工作 2021-03-28 17:28:49 +02:00
haiyangcui
15a6370785 增加推荐页面工具栏 2021-03-28 17:17:45 +02:00
haiyangcui
c8580ff6e6 增加历史页面工具栏 2021-03-28 16:48:33 +02:00
haiyangcui
a104e7cfa8 收藏页面工具栏 2021-03-28 16:31:48 +02:00
haiyangcui
c649d97021 升级依赖 2021-03-28 13:39:24 +02:00
haiyangcui
17601935f1 v2.7.7 2021-03-27 22:27:08 +01:00
haiyangcui
0f85e65e26 更新默认推荐视频列表 2021-03-21 23:06:10 +01:00
haiyangcui
8eb4ca5090 Gitee上的推荐文件显示"根据相关法律政策,该内容无法显示",重新指向为github上的文件 2021-03-21 22:45:19 +01:00
Hunlongyu
d6fcd151e3 直播源支持网址导入. 2021-03-17 10:06:54 +08:00
Hunlongyu
711637ac8b var => let or const 2021-03-17 09:07:25 +08:00
Hunlongyu
1769fb9780 修改成 正确的内容格式 2021-03-16 19:06:21 +08:00
Hunlongyu
40de0337be 默认显示所有支持的格式文件, 不做过滤 2021-03-16 18:35:29 +08:00
Hunlongyu
b0fbdeef15 支持 txt 文件格式的 直播源 和 视频源本地导入. 2021-03-16 18:30:52 +08:00
cuiocean
f75d961aaa Merge pull request #661 from cuiocean/dependabot/npm_and_yarn/elliptic-6.5.4
Bump elliptic from 6.5.3 to 6.5.4
2021-03-15 15:24:39 +01:00
buvta
12e2500fd7 点播视频地址失效时可换源并调整收藏 2021-03-13 18:21:43 +08:00
dependabot[bot]
e405225e02 Bump elliptic from 6.5.3 to 6.5.4
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.3 to 6.5.4.
- [Release notes](https://github.com/indutny/elliptic/releases)
- [Commits](https://github.com/indutny/elliptic/compare/v6.5.3...v6.5.4)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-11 01:23:54 +00:00
haiyangcui
dcba96a773 v2.7.6 2021-03-07 13:09:05 +01:00
haiyangcui
9910daa7c0 添加福利片过滤关键词 2021-03-07 12:54:52 +01:00
buvta
5ac57092db 停止时亦隐藏(频道列表为空) 2021-02-28 17:10:30 +08:00
buvta
8864a624f5 Revert "详情页默认选中历史播放的那集"该功能已实现,移动鼠标变换选中以切换分享播放指定集数
This reverts commit 52562a1a12.
2021-02-28 16:14:46 +08:00
haiyangcui
72ae7494d2 当IPTV的列表为空时,不显示频道列表 2021-02-27 22:23:25 +01:00
haiyangcui
877b564322 改变海报卡片背景,增强与背景的对比 2021-02-27 21:37:37 +01:00
haiyangcui
52562a1a12 详情页默认选中历史播放的那集 2021-02-27 21:18:03 +01:00
haiyangcui
43ff812b21 实现鼠标划过card时的放大效果 2021-02-27 16:08:37 +01:00
haiyangcui
a3a26e0deb 转移getDefaultSites函数到tools.js 2021-02-23 22:51:40 +01:00
haiyangcui
289f3c3c2d xgplayer2.18版本精简模式不工作,降级回2.17版本 2021-02-23 15:53:53 +01:00
haiyangcui
b580ae4329 记录最近打开detail页面的视图,当回到该视图时,恢复detail页面 2021-02-21 22:55:31 +01:00
haiyangcui
8ae32f0f55 v2.7.5 2021-02-21 21:49:39 +01:00
haiyangcui
713ffa6b3e 从gitee上获取推荐影视列表 2021-02-21 21:39:56 +01:00
haiyangcui
a3bc8f1f31 当重置或源站列表为空时,从云端获取源站 2021-02-21 21:32:58 +01:00
haiyangcui
22318f601b 修复播放速率显示信息位置错误的问题 2021-02-21 21:15:56 +01:00
buvta
aa8b4b527d 修复历史兼容导入m3u8List 2021-02-21 23:03:05 +08:00
haiyangcui
7bee4df2f9 默认使用gitee上的源站文件 2021-02-21 12:49:57 +01:00
37 changed files with 46472 additions and 7606 deletions

View File

@@ -1,4 +1,4 @@
name: release-build
name: x86-release-build
on:
push:
@@ -25,11 +25,3 @@ jobs:
shell: pwsh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload artifact
uses: actions/upload-artifact@v2
with:
name: dist_electron
path: dist_electron/*.exe
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -70,7 +70,7 @@
<h1>ZY Player 资源播放器</h1>
<h2>跨平台视频资源播放器, 简洁免费无广告.</h2>
<a href="https://github.com/Hunlongyu/ZY-Player/releases" target="_blank" class="download-btn"><i class="icofont-home"></i></i> Github 下载</a>
<a href="https://www.lanzous.com/b04s6a3re" target="_blank" class="download-btn"><i class="icofont-cloud"></i> 蓝奏下载 (密码:95px)</a>
<a href="https://hly.lanzoul.com/b04s6a3re" target="_blank" class="download-btn"><i class="icofont-cloud"></i> 蓝奏下载 (密码:95px)</a>
</div>
</div>
<div class="col-lg-6 d-lg-flex flex-lg-column align-items-stretch order-1 order-lg-2 hero-img" data-aos="fade-up">

34209
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "zy",
"version": "2.7.4",
"version": "2.8.8",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
@@ -17,56 +17,50 @@
},
"main": "background.js",
"dependencies": {
"axios": "^0.21.1",
"cheerio": "^1.0.0-rc.5",
"core-js": "^3.9.0",
"dexie": "^3.0.3",
"@electron/remote": "^2.0.8",
"axios": "^0.21.2",
"bootstrap-vue": "^2.22.0",
"cheerio": "1.0.0-rc.6",
"core-js": "^3.10.2",
"dexie": "^3.2.2",
"electron-localshortcut": "^3.2.1",
"electron-proxy-agent": "^1.2.0",
"electron-updater": "^4.3.5",
"element-ui": "^2.15.0",
"fast-xml-parser": "^3.18.0",
"electron-updater": "^4.3.8",
"element-ui": "^2.15.9",
"fast-xml-parser": "^3.19.0",
"html2canvas": "^1.0.0-rc.7",
"iptv-playlist-parser": "^0.6.0",
"m3u": "0.0.2",
"m3u8-parser": "^4.5.2",
"m3u8-parser": "^4.6.0",
"memcached": "^2.2.2",
"modern-normalize": "^1.0.0",
"mousetrap": "^1.6.5",
"pinyin-match": "^1.2.0",
"pinyin-match": "^1.2.1",
"qrcode.vue": "^1.7.0",
"randomstring": "^1.1.5",
"session": "^0.1.0",
"sortablejs": "^1.13.0",
"v-fit-columns": "^0.2.0",
"vue": "^2.6.12",
"vue": "^2.6.14",
"vue-infinite-loading": "^2.4.5",
"vue-waterfall-plugin": "^1.1.0",
"vuedraggable": "^2.24.3",
"vuex": "^3.6.2",
"xgplayer": "^2.18.0",
"xgplayer-flv.js": "^2.2.0",
"xgplayer-hls.js": "^2.4.1"
"xgplayer": "2.19.1",
"xgplayer-flv.js": "^2.3.0",
"xgplayer-hls.js": "^2.4.2",
"xgplayer-mp4": "^1.2.2"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.11",
"@vue/cli-plugin-eslint": "~4.5.11",
"@vue/cli-plugin-vuex": "~4.5.11",
"@vue/cli-service": "~4.5.11",
"@vue/eslint-config-standard": "^6.0.0",
"babel-eslint": "^10.1.0",
"@vue/cli-plugin-babel": "~5.0.8",
"@vue/cli-plugin-vuex": "~5.0.8",
"@vue/cli-service": "~5.0.8",
"babel-plugin-component": "^1.1.1",
"electron": "^11.3.0",
"electron": "^13.0.0",
"electron-devtools-installer": "^3.1.1",
"eslint": "^7.20.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.3.1",
"eslint-plugin-standard": "^4.1.0",
"eslint-plugin-vue": "^7.6.0",
"sass": "^1.30.0",
"sass-loader": "^10.1.0",
"vue-cli-plugin-electron-builder": "2.0.0-rc.6",
"vue-template-compiler": "^2.6.12"
"vue-template-compiler": "^2.6.14"
}
}

View File

@@ -10,7 +10,6 @@
<Setting v-show="view === 'Setting'" />
<IPTV v-show="view === 'IPTV'" />
<EditSites v-if="view === 'EditSites'"/>
<Recommendation v-show="view === 'Recommendation'" />
</div>
<transition name="slide">
<Detail v-if="detail.show"/>
@@ -22,11 +21,62 @@
</template>
<script>
import { setting } from './lib/dexie'
const remote = require('@electron/remote')
export default {
name: 'App',
data () {
return {
appTheme: 'theme-light'
appTheme: 'theme-light',
winSizePosition: {
x: 0,
y: 0,
width: 0,
height: 0
}
}
},
created () {
// 窗口创建口,检查是否有窗口大小位置的记录,如果有的话,更新窗口位置及大小
setting.find().then(res => {
if (res.restoreWindowPositionAndSize) {
var win = remote.getCurrentWindow()
win.setBounds({
x: res.windowPositionAndSize.x,
y: res.windowPositionAndSize.y,
width: res.windowPositionAndSize.width,
height: res.windowPositionAndSize.height
})
this.winSizePosition = {
x: win.getPosition()[0],
y: win.getPosition()[1],
width: win.getSize()[0],
height: win.getSize()[1]
}
}
})
},
updated () {
// 本来想hook up到beforedestroy 但不工作
// 每当窗口更新时检查窗口大小及位置记录到setting数据库中
if (this.setting.restoreWindowPositionAndSize) {
const win = remote.getCurrentWindow()
var newWinSizePosition = {
x: win.getPosition()[0],
y: win.getPosition()[1],
width: win.getSize()[0],
height: win.getSize()[1]
}
if (newWinSizePosition.x !== this.winSizePosition.x ||
newWinSizePosition.y !== this.winSizePosition.y ||
newWinSizePosition.width !== this.winSizePosition.width ||
newWinSizePosition.height !== this.winSizePosition.height) {
this.winSizePosition = newWinSizePosition
setting.find().then(res => {
res.windowPositionAndSize = newWinSizePosition
setting.update(res)
})
}
}
},
computed: {

View File

@@ -178,7 +178,6 @@
.el-select-dropdown__item.selected.hover{ //是上游的bug吗临时性修补
background-color: transparent;
}
.el-select-dropdown__wrap{
max-height: 574px
}
@@ -284,7 +283,8 @@
cursor: pointer;
transition: 0.2s;
&:hover {
top: -3px;
width: 102%;
height: 102%
}
.img{
position: relative;
@@ -441,3 +441,134 @@
}
}
}
// detail
.detail{
.detail-content{
.detail-body{
.m3u8{
.show-picture{
height: 100%;
width: 100%;
padding: 10px;
.card{
border-radius: 6px;
overflow: hidden;
position: relative;
cursor: pointer;
transition: 0.2s;
&:hover {
width: 102%;
height: 102%
}
.img{
position: relative;
min-height: 40px;
img{
width: 100%;
height: auto;
cursor: pointer;
}
.rate{
position: absolute;
top: 3%;
right: -40%;
width: 100%;
background-color: #111111aa;
color:#2f90b9;
height: 30px;
line-height: 30px;
font-size: 14px;
font-weight: bolder;
text-align: center;
transform: rotate(45deg);
}
.site{
position: absolute;
top: 0%;
left: 0%;
width: 100%;
background-color: #111111aa;
color:#2f90b9;
height: 30px;
line-height: 30px;
font-size: 14px;
font-weight: bolder;
text-align: center;
}
.progress{
position: absolute;
bottom: 10%;
left: 0%;
width: 40%;
background-color: #111111aa;
color: #f8df70;
height: 30px;
line-height: 30px;
font-size: 14px;
font-weight: bolder;
text-align: left;
}
.update{
position: absolute;
top: 5%;
left: -40%;
width: 100%;
background-color: #68b88e;
color: #cdcdcd;
height: 30px;
line-height: 30px;
font-size: 14px;
text-align: center;
transform: rotate(-45deg);
}
.operate{
display: none;
position: absolute;
left: 0;
bottom: 0;
background-color: #111111aa;
width: 100%;
font-size: 13px;
.operate-wrap{
display: flex;
justify-content: space-between;
.o-play, .o-star, .o-share{
cursor: pointer;
display: inline-block;
width: 80px;
height: 36px;
text-align: center;
line-height: 36px;
color: #cdcdcd;
&:hover{
background-color: #111;
}
}
}
}
}
.name{
font-size: 16px;
padding: 10px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.info{
display: flex;
justify-content: space-between;
font-size: 12px;
padding: 10px;
}
&:hover{
.operate{
display: block;
}
}
}
}
}
}
}
}

View File

@@ -14,6 +14,7 @@
--l-fc-3: #823aa0;
--l-bgc-1: #ffffff;
--l-bgc-2: #f2f6f9;
--l-bgc-3: #F9FBFC;
--l-bsc: 0 1px 3px #8e8da233, 0 1px 2px #8e8da244;
--l-bsc-hover: 0 14px 28px #8e8da255, 0 10px 10px #8e8da244;
--l-bsc-2: 0 -4px 23px 0 #8e8da233;
@@ -32,6 +33,7 @@
--d-fc-3: #38dd77;
--d-bgc-1: #222222;
--d-bgc-2: #2f2f2f;
--d-bgc-3: #292929;
--d-bsc: 0 1px 3px #38dd7733, 0 1px 2px #38dd7744;
--d-bsc-hover: 0 14px 28px #38dd7755, 0 10px 10px #38dd7744;
--d-bsc-2: 0 -4px 23px 0 #38dd7733;
@@ -50,6 +52,7 @@
--g-fc-3: #C1D95C;
--g-bgc-1: #4baea0;
--g-bgc-2: #74b4ac;
--g-bgc-3: #60B1A6;
--g-bsc: 0 1px 3px #e1ebe033, 0 1px 2px #e1ebe044;
--g-bsc-hover: 0 14px 28px #e1ebe055, 0 10px 10px #e1ebe044;
--g-bsc-2: 0 -4px 23px 0 #e1ebe033;
@@ -68,6 +71,7 @@
--p-fc-3: #177ea7;
--p-bgc-1: #ff8499;
--p-bgc-2: #fea1b2;
--p-bgc-3: #FF93A6;
--p-bsc: 0 1px 3px #ef528533, 0 1px 2px #ef528544;
--p-bsc-hover: 0 14px 28px #ef528555, 0 10px 10px #ef528544;
--p-bsc-2: 0 -4px 23px 0 #ef528533;

View File

@@ -138,6 +138,17 @@
}
}
}
.show-picture{
color: var(--d-fc-1);
.card{
background-color: var(--d-bgc-3);
box-shadow: var(--d-bsc);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
&:hover{
box-shadow: var(--d-bsc-hover);
}
}
}
}
}
}
@@ -461,7 +472,7 @@
.show-picture{
color: var(--d-fc-1);
.card{
background-color: var(--d-bgc-1);
background-color: var(--d-bgc-3);
box-shadow: var(--d-bsc);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
&:hover{

View File

@@ -138,6 +138,17 @@
}
}
}
.show-picture{
color: var(--g-fc-1);
.card{
background-color: var(--g-bgc-3);
box-shadow: var(--g-bsc);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
&:hover{
box-shadow: var(--g-bsc-hover);
}
}
}
}
}
}
@@ -449,7 +460,7 @@
.show-picture{
color: var(--g-fc-1);
.card{
background-color: var(--g-bgc-1);
background-color: var(--g-bgc-3);
box-shadow: var(--g-bsc);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
&:hover{

View File

@@ -1,5 +1,6 @@
.theme-light{
background-color: var(--l-bgc-1);
// background-color: var(--l-bgc-1);
background: rgba(0, 0, 0, 0);
.zy-select{
color: var(--l-fc-1);
background-color: var(--l-bgc-1);
@@ -138,6 +139,17 @@
}
}
}
.show-picture{
color: var(--l-fc-1);
.card{
background-color: var(--l-bgc-3);
box-shadow: var(--l-bsc);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
&:hover{
box-shadow: var(--l-bsc-hover);
}
}
}
}
}
}
@@ -449,7 +461,7 @@
.show-picture{
color: var(--l-fc-1);
.card{
background-color: var(--l-bgc-1);
background-color: var(--l-bgc-3);
box-shadow: var(--l-bsc);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
&:hover{

View File

@@ -138,6 +138,17 @@
}
}
}
.show-picture{
color: var(--p-fc-1);
.card{
background-color: var(--p-bgc-3);
box-shadow: var(--p-bsc);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
&:hover{
box-shadow: var(--p-bsc-hover);
}
}
}
}
}
}
@@ -449,7 +460,7 @@
.show-picture{
color: var(--p-fc-1);
.card{
background-color: var(--p-bgc-1);
background-color: var(--p-bgc-3);
box-shadow: var(--p-bsc);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
&:hover{

View File

@@ -4,7 +4,10 @@ import { app, protocol, BrowserWindow, globalShortcut } from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
import { initUpdater } from './lib/update/update'
require('@electron/remote/main').initialize()
const isDevelopment = process.env.NODE_ENV !== 'production'
// const log = require('electron-log') // 用于调试主程序
app.commandLine.appendSwitch('disable-features', 'OutOfBlinkCors') // 允许跨域
@@ -23,7 +26,8 @@ function createWindow () {
webPreferences: {
webSecurity: false,
enableRemoteModule: true,
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
nodeIntegration: true,
contextIsolation: false,
allowRunningInsecureContent: false
}
})
@@ -35,12 +39,13 @@ function createWindow () {
createProtocol('app')
win.loadURL('app://./index.html')
}
// 修改request headers
// Sec-Fetch下禁止修改浏览器自动加上请求头 https://www.cnblogs.com/fulu/p/13879080.html 暂时先用index.html的meta referer policy替代
const filter = {
urls: ['http://*/*', 'http://*/*']
}
require("@electron/remote/main").enable(win.webContents)
win.webContents.session.webRequest.onBeforeSendHeaders(filter, (details, callback) => {
const url = new URL(details.url)
details.requestHeaders.Origin = url.origin
@@ -63,7 +68,7 @@ function createWindow () {
if (process.platform === 'darwin') {
app.dock.show()
}
if (process.platform === 'Linux') {
if (process.platform === 'linux') {
app.disableHardwareAcceleration()
app.commandLine.appendSwitch('--no-sandbox') // linux 关闭沙盒模式
}

View File

@@ -14,13 +14,13 @@
</g>
</svg>
</span>
<span :class="[view === 'Recommendation' ? 'active ': ''] + 'zy-svg'" @click="changeView('Recommendation')">
<!-- <span :class="[view === 'Recommendation' ? 'active ': ''] + 'zy-svg'" @click="changeView('Recommendation')">
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="48px" height="48px" viewBox="0 0 24 24" aria-labelledby="thumbUpIconTitle" stroke="#2329D6" stroke-width="1" stroke-linecap="square" stroke-linejoin="miter" fill="none" color="#2329D6">
<title id="thumbUpIconTitle">影视推荐</title>
<path d="M8,8.73984815 C8,8.26242561 8.17078432,7.80075162 8.4814868,7.43826541 L13.2723931,1.84887469 C13.7000127,1.34998522 14.4122932,1.20614658 15,1.5 C15.5737957,1.78689785 15.849314,2.45205792 15.6464466,3.06066017 L14,8 L18.6035746,8 C18.7235578,8 18.8432976,8.01079693 18.9613454,8.03226018 C20.0480981,8.22985158 20.7689058,9.27101818 20.5713144,10.3577709 L19.2985871,17.3577709 C19.1256814,18.3087523 18.2974196,19 17.3308473,19 L10,19 C8.8954305,19 8,18.1045695 8,17 L8,8.73984815 Z"/>
<path d="M4,18 L4,9"/>
</svg>
</span>
</span> -->
<span :class="[view === 'Play' ? 'active ': ''] + 'zy-svg'" @click="changeView('Play')">
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-labelledby="playIconTitle">
<title id="playIconTitle">播放</title>
@@ -53,6 +53,12 @@
import { mapMutations } from 'vuex'
export default {
name: 'Aside',
data () {
return {
lastViewOpenDetail: '',
savedDetail: {}
}
},
computed: {
view: {
get () {
@@ -74,9 +80,19 @@ export default {
methods: {
...mapMutations(['SET_VIEW', 'SET_DETAIL']),
changeView (e) {
// 记录打开detail的view
if (this.detail.show === true) {
this.lastViewOpenDetail = this.view
this.savedDetail = this.detail
}
this.view = e
this.detail = {
show: false
// 如果回到上一次打开detail的试图页面,恢复detail页面
if (e === this.lastViewOpenDetail) {
this.detail = this.savedDetail
} else {
this.detail = {
show: false
}
}
}
}

View File

@@ -17,7 +17,7 @@
</svg>
</span>
</div>
<div class="detail-body zy-scroll" v-show="!loading">
<div class="detail-body zy-scroll listpage" v-show="!loading">
<div class="info">
<div class="info-left">
<img :src="info.pic" alt="">
@@ -37,9 +37,9 @@
</div>
<div class="operate">
<span @click="playEvent(selectedEpisode)">播放</span>
<span @click="starEvent">收藏</span>
<span @click="starEvent(info)">收藏</span>
<span @click="downloadEvent">下载</span>
<span @click="shareEvent">分享</span>
<span @click="shareEvent(info,selectedEpisode)">分享</span>
<span @click="doubanLinkEvent">豆瓣</span>
<span @click="togglePlayOnlineEvent">
<input type="checkbox" v-model="playOnline"> 播放在线高清视频
@@ -64,6 +64,47 @@
<span v-bind:class="{ selected: j === selectedEpisode }" v-for="(i, j) in videoList" :key="j" @click="playEvent(j)" @mouseenter="() => { selectedEpisode = j }">{{ i | ftName(j) }}</span>
</div>
</div>
<div class="m3u8">
<div class="show-picture" v-show="info.recommendations && info.recommendations.length > 0">
<span>喜欢这部电影的人也喜欢 · · · · · ·</span>
<Waterfall :list="info.recommendations" :gutter="20" :width="240"
:breakpoints="{
1200: { //当屏幕宽度小于等于1200
rowPerView: 4,
},
800: { //当屏幕宽度小于等于800
rowPerView: 3,
},
500: { //当屏幕宽度小于等于500
rowPerView: 2,
}
}"
animationEffect="fadeIn"
backgroundColor="rgba(0, 0, 0, 0)">
<template slot="item" slot-scope="props">
<div class="card">
<div class="img">
<img style="width: 100%" :src="props.data.pic" alt="" @click="detailEvent(props.data)">
<div class="operate">
<div class="operate-wrap">
<span class="o-play" @click="playRecommendationEvent(props.data)">播放</span>
<span class="o-star" @click="starEvent(props.data)">收藏</span>
<span class="o-share" @click="shareEvent(props.data, 0)">分享</span>
</div>
</div>
</div>
<div class="name">{{props.data.name}}</div>
<div class="info">
<span>{{props.data.area}}</span>
<span>{{props.data.year}}</span>
<span>{{props.data.note}}</span>
<span>{{props.data.type}}</span>
</div>
</div>
</template>
</Waterfall>
</div>
</div>
</div>
<div class="detail-mask zy-loading" v-show="loading">
<div class="loader"></div>
@@ -73,6 +114,7 @@
</template>
<script>
import { mapMutations } from 'vuex'
import Waterfall from 'vue-waterfall-plugin'
import zy from '../lib/site/tools'
import onlineVideo from '../lib/site/onlineVideo'
import { star, history } from '../lib/dexie'
@@ -85,6 +127,8 @@ export default {
videoFlag: '',
videoList: [],
videoFullList: [],
key: '',
site: {},
info: {},
playOnline: false,
selectedEpisode: 0, // 选定集数
@@ -144,8 +188,22 @@ export default {
}
}
},
components: {
Waterfall
},
methods: {
...mapMutations(['SET_VIEW', 'SET_VIDEO', 'SET_DETAIL', 'SET_SHARE', 'SET_DetailCache']),
async playRecommendationEvent (e) {
const db = await history.find({ site: this.detail.key, ids: e.id })
if (db) {
this.video = { key: db.site, info: { id: db.ids, name: db.name, index: db.index, site: this.detail.site } }
} else {
this.video = { key: this.detail.key, info: { id: e.id, name: e.name, index: 0, site: this.detail.site } }
}
this.video.detail = e
this.view = 'Play'
this.detail.show = false
},
addClass (flag) {
if (flag === this.videoFlag) {
return 'selectedBox'
@@ -200,15 +258,15 @@ export default {
onlineVideo.playVideoOnline(this.selectedOnlineSite, this.detail.info.name, n)
}
},
async starEvent () {
const db = await star.find({ key: this.detail.key, ids: this.info.id })
async starEvent (info) {
const db = await star.find({ key: this.detail.key, ids: info.id })
const doc = {
key: this.detail.key,
ids: this.info.id,
ids: info.id,
site: this.detail.site,
name: this.info.name,
detail: this.info,
rate: this.info.rate
name: info.name,
detail: info,
rate: info.rate
}
if (db) {
star.update(db.id, doc)
@@ -219,6 +277,10 @@ export default {
})
}
},
detailEvent (info) {
this.detail.info = info
this.getDetailInfo()
},
togglePlayOnlineEvent () {
this.playOnline = !this.playOnline
},
@@ -257,12 +319,12 @@ export default {
this.$message.error(err.info)
})
},
shareEvent () {
shareEvent (info, selectedEpisode) {
this.share = {
show: true,
key: this.detail.key,
info: this.info,
index: this.selectedEpisode
info: info,
index: selectedEpisode
}
},
doubanLinkEvent () {
@@ -277,6 +339,17 @@ export default {
const name = this.info.name.trim()
const year = this.info.year
this.info.rate = await zy.doubanRate(name, year)
const recommendations = await zy.doubanRecommendations(name, year)
if (recommendations) {
this.info.recommendations = []
recommendations.forEach(element => {
zy.searchFirstDetail(this.detail.key, element).then(detailRes => {
if (detailRes) {
this.info.recommendations.push(detailRes)
}
})
})
}
},
async getDetailInfo () {
const id = this.detail.info.ids || this.detail.info.id
@@ -293,13 +366,14 @@ export default {
if (res) {
this.info = res
this.$set(this.info, 'rate', this.DetailCache[cacheKey].rate || '')
this.$set(this.info, 'recommendations', this.DetailCache[cacheKey].recommendations || [])
this.videoFlag = this.videoFlag || res.fullList[0].flag
this.videoList = res.fullList[0].list
this.videoFullList = res.fullList
this.loading = false
if (!this.info.rate) {
await this.getDoubanRate()
this.DetailCache[cacheKey].rate = this.info.rate
this.DetailCache[cacheKey] = this.info
}
}
}

View File

@@ -2,7 +2,7 @@
<div class="listpage" id="sites">
<div class="listpage-header" v-show="!enableBatchEdit">
<el-switch v-model="enableBatchEdit" active-text="批处理分组">></el-switch>
<el-checkbox v-model="setting.excludeR18Films" @change="excludeR18FilmsChangeEvent">屏蔽福利片</el-checkbox>
<el-button @click="openFilterKeywordsDiag" icon="el-icon-key">关键词过滤</el-button>
<el-button @click="addSite" icon="el-icon-document-add">新增</el-button>
<el-button @click="exportSites" icon="el-icon-upload2" title="导出全部,自动添加扩展名">导出</el-button>
<el-button @click="importSites" icon="el-icon-download" title="支持同时导入多个文件">导入</el-button>
@@ -41,7 +41,18 @@
<template slot-scope="scope">
<el-switch
v-model="scope.row.isActive"
@click.native.stop='isActiveChangeEvent(scope.row)'>
@click.native.stop='propChangeEvent(scope.row)'>
</el-switch>
</template>
</el-table-column>
<el-table-column
prop="reverseOrder"
width="120"
label="倒序排列">
<template slot-scope="scope">
<el-switch
v-model="scope.row.reverseOrder"
@click.native.stop='propChangeEvent(scope.row)'>>
</el-switch>
</template>
</el-table-column>
@@ -83,7 +94,7 @@
</div>
<!-- 编辑页面 -->
<div>
<el-dialog :visible.sync="dialogVisible" v-if='dialogVisible' :title="dialogType==='edit'?'编辑源':'新增源'" :append-to-body="true" @close="closeDialog">
<el-dialog :visible.sync="editSiteDialogVisible" v-if='editSiteDialogVisible' :title="dialogType==='edit'?'编辑源':'新增源'" :append-to-body="true" @close="closeDialog">
<el-form :model="siteInfo" ref='siteInfo' label-width="75px" label-position="left" :rules="rules">
<el-form-item label="源站名" prop='name'>
<el-input v-model="siteInfo.name" placeholder="请输入源站名" />
@@ -112,15 +123,36 @@
</span>
</el-dialog>
</div>
<!-- 设置过滤关键词页面 -->
<div>
<el-dialog :visible.sync="filterKeywordsDialogVisible" v-if='filterKeywordsDialogVisible' :title="'分类过滤'" :append-to-body="true" @close="closeDialog">
<el-form>
<el-switch v-model="excludeRootClasses" active-text="开启主分类过滤">></el-switch>
<el-form-item>
<el-input v-model="rootClassFilterKeywords" :autosize="{ minRows: 3, maxRows: 6}" type="textarea" placeholder="请输入过滤关键词" />
</el-form-item>
</el-form>
<el-form>
<el-switch v-model="excludeR18Films" active-text="开启福利分类过滤">></el-switch>
<el-form-item>
<el-input v-model="r18ClassFilterKeywords" :autosize="{ minRows: 3, maxRows: 6}" type="textarea" placeholder="请输入过滤关键词" />
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="closeDialog">取消</el-button>
<el-button type="primary" @click="saveFilterKeywords">保存</el-button>
</span>
</el-dialog>
</div>
</div>
</template>
<script>
import { mapMutations } from 'vuex'
import { sites, setting } from '../lib/dexie'
import zy from '../lib/site/tools'
import { remote } from 'electron'
import fs from 'fs'
import Sortable from 'sortablejs'
const remote = require('@electron/remote')
export default {
name: 'editSites',
@@ -129,7 +161,8 @@ export default {
show: false,
sites: [],
dialogType: 'new',
dialogVisible: false,
editSiteDialogVisible: false,
filterKeywordsDialogVisible: false,
siteInfo: {
key: '',
name: '',
@@ -139,6 +172,10 @@ export default {
group: '',
isActive: true
},
excludeRootClasses: true,
excludeR18Films: true,
rootClassFilterKeywords: [],
r18ClassFilterKeywords: [],
siteGroup: [],
rules: {
name: [
@@ -204,12 +241,6 @@ export default {
},
methods: {
...mapMutations(['SET_SETTING']),
excludeR18FilmsChangeEvent () {
setting.find().then(res => {
res.excludeR18Films = this.setting.excludeR18Films
setting.update(res)
})
},
selectionCellClick (selection, row) {
if (this.shiftDown && this.selectionBegin !== '' && selection.includes(row)) {
this.selectionEnd = row.id
@@ -249,6 +280,11 @@ export default {
},
getSites () {
sites.all().then(res => {
res.forEach(element => {
if (element.reverseOrder === null || element.reverseOrder === undefined) {
element.reverseOrder = false
}
})
this.sites = res
})
},
@@ -261,6 +297,29 @@ export default {
}
this.siteGroup = arr
},
openFilterKeywordsDiag () {
this.excludeRootClasses = this.setting.excludeRootClasses
this.excludeR18Films = this.setting.excludeR18Films
this.rootClassFilterKeywords = this.setting.rootClassFilter?.join()
this.r18ClassFilterKeywords = this.setting.r18ClassFilter?.join()
this.filterKeywordsDialogVisible = true
},
saveFilterKeywords () {
// 移除空格,然后按逗号分开
this.setting.rootClassFilter = this.rootClassFilterKeywords?.replace(/\s/g, '').split(',')
this.setting.r18ClassFilter = this.r18ClassFilterKeywords?.replace(/\s/g, '').split(',')
this.setting.classFilter = []
this.setting.excludeRootClasses = this.excludeRootClasses
if (this.excludeRootClasses) {
this.setting.classFilter = this.setting.classFilter.concat(this.setting.rootClassFilter)
}
this.setting.excludeR18Films = this.excludeR18Films
if (this.excludeR18Films) {
this.setting.classFilter = this.setting.classFilter.concat(this.setting.r18ClassFilter)
}
setting.update(this.setting)
this.filterKeywordsDialogVisible = false
},
addSite () {
if (this.checkAllSitesLoading) {
this.$message.info('正在检测, 请勿操作.')
@@ -268,7 +327,7 @@ export default {
}
this.getSitesGroup()
this.dialogType = 'new'
this.dialogVisible = true
this.editSiteDialogVisible = true
this.siteInfo = {
key: '',
name: '',
@@ -286,12 +345,13 @@ export default {
}
this.getSitesGroup()
this.dialogType = 'edit'
this.dialogVisible = true
this.editSiteDialogVisible = true
this.siteInfo = siteInfo
this.editOldkey = siteInfo.key
},
closeDialog () {
this.dialogVisible = false
this.editSiteDialogVisible = false
this.filterKeywordsDialogVisible = false
this.getSites()
},
removeEvent (e) {
@@ -348,7 +408,7 @@ export default {
group: ''
}
this.dialogType === 'edit' ? this.$message.success('修改成功!') : this.$message.success('新增源成功!')
this.dialogVisible = false
this.editSiteDialogVisible = false
this.getSites()
})
this.editOldkey = ''
@@ -379,31 +439,57 @@ export default {
}
const options = {
filters: [
{ name: 'JSON file', extensions: ['json'] }
{ name: '支持的文件格式', extensions: ['json', 'txt'] }
],
properties: ['openFile', 'multiSelections']
}
remote.dialog.showOpenDialog(options).then(result => {
if (!result.canceled) {
result.filePaths.forEach(file => {
const str = fs.readFileSync(file)
const json = JSON.parse(str)
json.forEach(ele => {
if (ele.api && this.sites.filter(x => x.key === ele.key).length === 0 && this.sites.filter(x => x.name === ele.name && x.api === ele.api).length === 0) {
// 不含该key 同时也不含名字和url一样的
if (ele.isActive === undefined) {
ele.isActive = true
if (file.endsWith('json')) {
const str = fs.readFileSync(file)
const json = JSON.parse(str)
json.forEach(ele => {
if (ele.api && this.sites.filter(x => x.key === ele.key).length === 0 && this.sites.filter(x => x.name === ele.name && x.api === ele.api).length === 0) {
// 不含该key 同时也不含名字和url一样的
if (ele.isActive === undefined) {
ele.isActive = true
}
if (ele.group === undefined) {
ele.group = '导入'
}
this.sites.push(ele)
}
if (ele.group === undefined) {
ele.group = '导入'
}
this.sites.push(ele)
})
this.resetId(this.sites)
sites.clear().then(sites.bulkAdd(this.sites))
this.$message.success('导入成功')
this.getSites()
}
if (file.endsWith('txt')) {
try {
const txt = fs.readFileSync(file, 'utf8')
const json = JSON.parse(txt)
json.forEach(ele => {
if (ele.api && this.sites.filter(x => x.key === ele.key).length === 0 && this.sites.filter(x => x.name === ele.name && x.api === ele.api).length === 0) {
// 不含该key 同时也不含名字和url一样的
if (ele.isActive === undefined) {
ele.isActive = true
}
if (ele.group === undefined) {
ele.group = '导入'
}
this.sites.push(ele)
}
})
this.resetId(this.sites)
sites.clear().then(sites.bulkAdd(this.sites))
this.$message.success('导入成功')
this.getSites()
} catch (error) {
this.$message.warning('导入失败')
}
})
this.resetId(this.sites)
sites.clear().then(sites.bulkAdd(this.sites))
this.$message.success('导入成功')
this.getSites()
}
})
}
})
@@ -411,17 +497,13 @@ export default {
resetSitesEvent () {
let url = this.setting.sitesDataURL
if (!url) {
// 如果没有设置源站文件链接,使用默认的github源
url = 'https://raw.githubusercontent.com/cuiocean/ZY-Player-Resources/main/Sites/Sites.json'
url = 'https://raw.iqiq.io/Hunlongyu/ZY-Player-Resources/main/Sites/20220713.json'
}
const axios = require('axios')
axios.get(url).then(res => {
if (res.status === 200) {
if (res.data.length > 0) {
sites.clear().then(sites.bulkAdd(res.data))
this.$message.success('重置源成功')
this.getSites()
}
zy.getDefaultSites(url).then(res => {
if (res.length > 0) {
sites.clear().then(sites.bulkAdd(res))
this.$message.success('重置源成功')
this.getSites()
}
}).catch(error => {
this.$message.error('导入云端源站失败. ' + error)
@@ -440,9 +522,10 @@ export default {
this.sites = this.$refs.editSitesTable.tableData
}
},
isActiveChangeEvent (row) {
propChangeEvent (row) {
sites.remove(row.id)
sites.add(row)
this.getSites()
},
resetId (inArray) {
let id = 1

View File

@@ -281,7 +281,7 @@
animationEffect="fadeIn"
backgroundColor="rgba(0, 0, 0, 0)">
<template slot="item" slot-scope="props">
<div class="card" v-show="!setting.excludeR18Films || !containsR18Keywords(props.data.type)">
<div class="card" v-show="!setting.excludeR18Films || !containsClassFilterKeyword(props.data.type)">
<div class="img">
<div class="site">
<span>{{props.data.site.name}}</span>
@@ -322,7 +322,6 @@ export default {
data () {
return {
showFind: false,
showToolbar: false,
showTableLastColumn: false,
sites: [],
site: {},
@@ -345,18 +344,19 @@ export default {
filteredSearchContents: [],
currentColumn: '',
searchGroup: '',
searchGroups: [],
// 福利片关键词
r18KeyWords: ['伦理', '论理', '倫理', '福利', '激情', '理论', '写真', '情色', '美女', '街拍', '赤足', '性感', '里番'],
searchGroups: ['站内', '组内', '全站'],
classFilterKeywords: [],
filteredList: [],
areas: [],
searchRunning: false,
siteSearchCount: 0,
infiniteHandlerCount: 0,
// Toolbar
showToolbar: false,
selectedAreas: [],
sortKeyword: '',
sortKeywords: ['按片名', '按上映年份', '按更新时间'],
selectedYears: { start: 0, end: new Date().getFullYear() },
searchRunning: false,
siteSearchCount: 0,
infiniteHandlerCount: 0
selectedYears: { start: 0, end: new Date().getFullYear() }
}
},
components: {
@@ -413,12 +413,13 @@ export default {
}
},
filterSettings () {
return this.$store.getters.getSetting.excludeR18Films // 需要监听的数据
return this.$store.getters.getSetting.classFilter // 需要监听的数据
},
searchSites () {
if (this.searchGroup === '站内') return [this.site]
if (this.searchGroup === '组内') return this.sites.filter(site => site.group === this.site.group)
if (this.searchGroup === '全站') return this.sites
return this.sites.filter(site => site.group === this.searchGroup)
return this.sites.filter(site => site.isActive)
}
},
filters: {
@@ -443,7 +444,7 @@ export default {
}
},
filterSettings () {
this.siteClick(this.site.name)
this.refreshClass()
},
list: {
handler (list) {
@@ -455,9 +456,12 @@ export default {
siteSearchCount () {
if (this.siteSearchCount === this.searchSites.length) this.searchRunning = false
},
site () {
this.siteClick(this.site.name)
},
searchContents: {
handler (list) {
list = list.filter(res => !this.setting.excludeR18Films || !this.containsR18Keywords(res.type))
list = list.filter(res => !this.setting.excludeR18Films || !this.containsClassFilterKeyword(res.type))
this.areas = [...new Set(list.map(ele => ele.area))].filter(x => x)
this.searchClassList = [...new Set(list.map(ele => ele.type))].filter(x => x)
this.refreshFilteredList()
@@ -499,14 +503,14 @@ export default {
let filteredData = this.showFind ? this.searchContents : this.list
if (this.showFind) filteredData = filteredData.filter(x => (this.selectedSearchClassNames.length === 0) || this.selectedSearchClassNames.includes(x.type))
filteredData = filteredData.filter(x => (this.selectedAreas.length === 0) || this.selectedAreas.includes(x.area))
filteredData = filteredData.filter(res => !this.setting.excludeR18Films || !this.containsR18Keywords(res.type))
filteredData = filteredData.filter(res => !this.setting.excludeR18Films || !this.containsClassFilterKeyword(res.type))
filteredData = filteredData.filter(res => res.year >= this.selectedYears.start)
filteredData = filteredData.filter(res => res.year <= this.selectedYears.end)
if (!this.showFind) this.selectedClassName = this.type.name + ' ' + filteredData.length + '/' + this.recordcount
switch (this.sortKeyword) {
case '按上映年份':
filteredData.sort(function (a, b) {
return a.year - b.year
return b.year - a.year
})
break
case '按片名':
@@ -520,8 +524,14 @@ export default {
})
break
default:
filteredData.sort(function (a, b) {
return new Date(b.last) - new Date(a.last)
})
break
}
// Get unique film data
filteredData = Array.from(new Set(filteredData))
if (this.showFind) {
this.filteredSearchContents = filteredData
} else {
@@ -591,6 +601,16 @@ export default {
})
}
},
refreshClass () {
this.getClass().then(res => {
this.classList = res
// cache classList data
FILM_DATA_CACHE[this.site.key] = {
classList: this.classList
}
this.classClick(this.type.name)
})
},
classClick (className) {
this.list = []
this.type = this.classList.find(x => x.name === className)
@@ -618,20 +638,11 @@ export default {
getClass () {
return new Promise((resolve, reject) => {
const key = this.site.key
// 屏蔽主分类
const classToHide = ['电影', '电影片', '电视剧', '连续剧', '综艺', '动漫']
zy.class(key).then(res => {
const allClass = [{ name: '最新', tid: 0 }]
res.class.forEach(element => {
if (!this.setting.excludeRootClasses || !classToHide.includes(element.name)) {
if (this.setting.excludeR18Films) {
const containKeyWord = this.containsR18Keywords(element.name)
if (!containKeyWord) {
allClass.push(element)
}
} else {
allClass.push(element)
}
if (!this.containsClassFilterKeyword(element.name)) {
allClass.push(element)
}
})
resolve(allClass)
@@ -640,19 +651,20 @@ export default {
})
})
},
containsR18Keywords (name) {
const containKeyWord = false
if (!name) {
return containKeyWord
containsClassFilterKeyword (name) {
let ret = false
// 主分类过滤, 检测关键词是否包含分类名
if (this.setting.excludeRootClasses) {
ret = this.setting.rootClassFilter?.some(v => v.includes(name))
}
return this.r18KeyWords.some(v => name.includes(v))
// 福利过滤,检测分类名是否包含关键词
if (this.setting.excludeR18Films && !ret) {
ret = this.setting.r18ClassFilter?.some(v => name?.includes(v))
}
return ret
},
toFlipPagecount () {
// 似乎需要解析的网站的视频排序和其他m3u8采集站的顺序正好相反
if (this.site.jiexiUrl) {
return true
}
return false
return this.site.reverseOrder
},
infiniteHandler ($state) {
const key = this.site.key
@@ -860,12 +872,34 @@ export default {
this.showFind = false
}
},
async getDefaultSites () {
const s = await setting.find()
zy.getDefaultSites(s.sitesDataURL).then(res => {
if (res && typeof res === 'string') {
const json = JSON.parse(res)
sites.clear().then(sites.bulkAdd(json))
}
if (res && typeof res === 'object') {
sites.clear().then(sites.bulkAdd(res))
}
sites.all().then(res => {
if (res) {
this.sites = res.filter(item => item.isActive)
if (this.site === undefined || !this.sites.some(x => x.key === this.site.key)) {
this.site = this.sites[0]
this.selectedSiteName = this.sites[0].name
}
}
})
}).catch(error => {
this.$message.error('获取云端源站失败. ' + error)
})
},
getAllSites () {
sites.all().then(res => {
if (res.length <= 0) {
this.site = {}
this.type = {}
this.list = []
this.$message.warning('检测到视频源未能正常加载, 即将重置源.')
this.getDefaultSites()
} else {
this.sites = res.filter(item => item.isActive)
if (this.site === undefined || !this.sites.some(x => x.key === this.site.key)) {
@@ -873,10 +907,6 @@ export default {
this.selectedSiteName = this.sites[0].name
}
}
this.searchGroups = [...new Set(this.sites.map(site => site.group))]
if (this.searchGroups.length === 1) this.searchGroups = []
this.searchGroups.unshift('站内')
this.searchGroups.push('全站')
this.searchGroup = this.setting.searchGroup
if (this.searchGroup === undefined) setting.find().then(res => { this.searchGroup = res.searchGroup })
})

View File

@@ -15,7 +15,7 @@
</div>
</template>
<script>
const { remote } = require('electron')
const remote = require('@electron/remote')
export default {
name: 'frame',
computed: {

View File

@@ -1,15 +1,55 @@
<template>
<div class="listpage" id="history">
<div class="listpage-header" id="history-header">
<el-switch v-model="setting.historyViewMode" active-text="海报" active-value="picture" inactive-text="列表" inactive-value="table" @change="updateViewMode"></el-switch>
<el-button @click.stop="exportHistory" icon="el-icon-upload2" title="导出全部,自动添加扩展名">导出</el-button>
<el-button @click.stop="importHistory" icon="el-icon-download" title="支持同时导入多个文件">导入</el-button>
<el-button @click.stop="removeSelectedItems" icon="el-icon-delete-solid">{{ multipleSelection.length === 0 ? "清空" : "删除所选" }}</el-button>
<b-button-group>
<el-switch v-model="onlyShowItemsHasUpdate" active-text="有更新" inactive-text="全部" @change="refreshFilteredList"></el-switch>
<el-button @click.stop="updateAllEvent" icon="el-icon-refresh">检查更新</el-button>
</b-button-group>
</div>
<div class="toolbar" v-show="showToolbar">
<el-select v-model="selectedAreas" size="small" multiple placeholder="地区" popper-class="popper" :popper-append-to-body="false" @remove-tag="refreshFilteredList" @change="refreshFilteredList">
<el-option
v-for="item in areas"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select>
<el-select v-model="selectedTypes" size="small" multiple placeholder="类型" popper-class="popper" :popper-append-to-body="false" @remove-tag="refreshFilteredList" @change="refreshFilteredList">
<el-option
v-for="item in types"
: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 class="listpage-header-divider" content-position="right">
<el-button type="text" size="mini" @click="toggleViewMode">视图切换</el-button>
<el-button type="text" size="mini" @click='() => { showToolbar = !showToolbar; if (!showToolbar) this.refreshFilteredList() }' title="收起工具栏会重置筛选排序">{{ showToolbar ? '隐藏工具栏' : '显示工具栏' }}</el-button>
<el-button type="text" size="mini" @click="backTop">回到顶部</el-button>
</el-divider>
<div class="listpage-body" id="history-body">
<div class="show-table" id="history-table" v-if="setting.historyViewMode === 'table'">
<el-table size="mini" fit height="100%"
:data="history"
:data="filteredList"
row-key="id"
ref="historyTable"
@select="selectionCellClick"
@@ -40,11 +80,11 @@
</span>
</template>
</el-table-column>
<el-table-column v-if="history.some(e => e.time)"
width="150"
<el-table-column v-if="list.some(e => e.time)"
width="200"
label="时间进度">
<template slot-scope="scope">
<span v-if="scope.row.time && scope.row.duration">{{fmtMSS(scope.row.time.toFixed(0))}}/{{fmtMSS(scope.row.duration.toFixed(0))}}</span>
<span v-if="scope.row.time && scope.row.duration">{{fmtMSS(scope.row.time.toFixed(0))}}/{{fmtMSS(scope.row.duration.toFixed(0))}} ({{progress(scope.row)}}%)</span>
<span v-if="scope.row.onlinePlay">在线解析</span>
</template>
</el-table-column>
@@ -63,7 +103,7 @@
</el-table>
</div>
<div class="show-picture" id="star-picture" v-if="setting.historyViewMode === 'picture'">
<Waterfall ref="historyWaterfall" :list="history" :gutter="20" :width="240"
<Waterfall ref="historyWaterfall" :list="filteredList" :gutter="20" :width="240"
:breakpoints="{
1200: { //当屏幕宽度小于等于1200
rowPerView: 4,
@@ -80,6 +120,9 @@
<template slot="item" slot-scope="props">
<div class="card">
<div class="img">
<div class="update" v-if="props.data.hasUpdate">
<span>有更新</span>
</div>
<img v-if="props.data.detail && props.data.detail.pic" style="width: 100%" :src="props.data.detail.pic" alt="" @load="$refs.historyWaterfall.refresh()" @click="detailEvent(props.data)">
<div class="operate">
<div class="operate-wrap">
@@ -93,7 +136,7 @@
<div class="name" @click="detailEvent(props.data)">{{props.data.name}}</div>
<div class="info">
<span v-if="props.data.time && props.data.duration">
{{fmtMSS(props.data.time.toFixed(0))}}/{{fmtMSS(props.data.duration.toFixed(0))}}
{{fmtMSS(props.data.time.toFixed(0))}}/{{fmtMSS(props.data.duration.toFixed(0))}} ({{progress(props.data)}}%)
</span>
<span v-if="props.data.onlinePlay">在线解析</span>
<span v-if="props.data.detail && props.data.detail.fullList[0].list !== undefined && props.data.detail.fullList[0].list.length > 1">
@@ -111,21 +154,34 @@
import { mapMutations } from 'vuex'
import { history, sites, setting } from '../lib/dexie'
import zy from '../lib/site/tools'
import { remote } from 'electron'
import fs from 'fs'
import Waterfall from 'vue-waterfall-plugin'
const remote = require('@electron/remote')
const { clipboard } = require('electron')
export default {
name: 'history',
data () {
return {
history: [],
list: [],
sites: [],
shiftDown: false,
selectionBegin: '',
selectionEnd: '',
multipleSelection: []
multipleSelection: [],
areas: [],
types: [],
filteredList: [],
// Update
numNoUpdate: 0,
// Toolbar
showToolbar: false,
selectedAreas: [],
selectedTypes: [],
sortKeyword: '',
sortKeywords: ['按片名', '按上映年份', '按更新时间', '按完成度'],
selectedYears: { start: 0, end: new Date().getFullYear() },
onlyShowItemsHasUpdate: false
}
},
components: {
@@ -171,6 +227,14 @@ export default {
set (val) {
this.SET_SETTING(val)
}
},
DetailCache: {
get () {
return this.$store.getters.getDetailCache
},
set (val) {
this.SET_DetailCache(val)
}
}
},
watch: {
@@ -180,19 +244,134 @@ export default {
this.getAllsites()
if (this.setting.historyViewMode === 'table') this.showShiftPrompt()
}
},
list: {
handler (list) {
this.areas = [...new Set(list.map(ele => ele.detail.area))].filter(x => x)
this.types = [...new Set(list.map(ele => ele.detail.type))].filter(x => x)
this.refreshFilteredList()
},
deep: true
},
numNoUpdate () {
// 如果所有历史都没有更新的话
if (this.numNoUpdate === this.list.length) {
this.numNoUpdate = 0
this.$message.warning('未查询到任何更新')
}
}
},
methods: {
...mapMutations(['SET_VIEW', 'SET_DETAIL', 'SET_VIDEO', 'SET_SHARE', 'SET_SETTING']),
updateAllEvent () {
this.numNoUpdate = 0
this.list.forEach(e => {
this.updateEvent(e)
})
},
async updateEvent (e) {
try {
if (!this.DetailCache[e.site + '@' + e.ids]) {
this.DetailCache[e.site + '@' + e.ids] = await zy.detail(e.site, e.ids)
}
const newDetail = this.DetailCache[e.site + '@' + e.ids]
history.get(e.id).then(res => {
if (!e.hasUpdate && e.detail.last !== newDetail.last) {
res.hasUpdate = true
res.detail = newDetail
const msg = `检查到"${e.name}"有更新。`
this.$message.success(msg)
} else {
this.numNoUpdate += 1
}
history.update(e.id, res)
this.getAllhistory()
})
} catch (err) {
const msg = `更新"${e.name}"失败, 请重试。`
this.$message.warning(msg, err)
}
},
toggleViewMode () {
this.setting.historyViewMode = this.setting.historyViewMode === 'picture' ? 'table' : 'picture'
if (this.setting.historyViewMode === 'table') {
this.showShiftPrompt()
} else {
setTimeout(() => { if (this.$refs.historyWaterfall) this.$refs.historyWaterfall.refresh() }, 700)
}
setting.find().then(res => {
res.historyViewMode = this.setting.historyViewMode
setting.update(res)
})
},
backTop () {
if (this.setting.starViewMode === 'picture') {
document.getElementById('history-body').scrollTop = 0
} else {
this.$refs.historyTable.bodyWrapper.scrollTop = 0
}
},
refreshFilteredList () {
if (!this.showToolbar) {
this.sortKeyword = ''
this.selectedAreas = []
this.selectedSearchClassNames = []
this.selectedYears.start = 0
this.selectedYears.end = new Date().getFullYear()
this.filteredList = this.list
} else {
let filteredData = this.list
filteredData = filteredData.filter(x => (this.selectedAreas.length === 0) || this.selectedAreas.includes(x.detail.area))
filteredData = filteredData.filter(x => (this.selectedTypes.length === 0) || this.selectedTypes.includes(x.detail.type))
filteredData = filteredData.filter(res => res.detail.year >= this.selectedYears.start)
filteredData = filteredData.filter(res => res.detail.year <= this.selectedYears.end)
switch (this.sortKeyword) {
case '按上映年份':
filteredData.sort(function (a, b) {
return a.detail.year - b.detail.year
})
break
case '按片名':
filteredData.sort(function (a, b) {
return a.detail.name.localeCompare(b.detail.name, 'zh')
})
break
case '按更新时间':
filteredData.sort(function (a, b) {
return new Date(b.detail.last) - new Date(a.detail.last)
})
break
case '按完成度':
filteredData.sort(this.sortByProgress)
break
default:
break
}
this.filteredList = filteredData
}
if (this.onlyShowItemsHasUpdate) {
this.filteredList = this.filteredList.filter(x => x.hasUpdate)
}
},
progress (e) {
return e.duration > 0 ? ((e.time / e.duration) * 100).toFixed(0) : 0
},
sortByProgress (a, b) {
if (this.progress(a) < this.progress(b)) {
return -1
} else {
return 1
}
},
fmtMSS (s) {
return (s - (s %= 60)) / 60 + (s > 9 ? ':' : ':0') + s
},
selectionCellClick (selection, row) { // 历史id与顺序刚好相反大的反而在前面
if (this.shiftDown && this.selectionBegin !== '' && selection.includes(row)) {
this.selectionEnd = row.id
const start = this.history.findIndex(e => e.id === Math.max(this.selectionBegin, this.selectionEnd))
const end = this.history.findIndex(e => e.id === Math.min(this.selectionBegin, this.selectionEnd))
const selections = this.history.slice(start, end + 1)
const start = this.list.findIndex(e => e.id === Math.max(this.selectionBegin, this.selectionEnd))
const end = this.list.findIndex(e => e.id === Math.min(this.selectionBegin, this.selectionEnd))
const selections = this.list.slice(start, end + 1)
this.$nextTick(() => {
selections.forEach(e => this.$refs.historyTable.toggleRowSelection(e, true))
})
@@ -209,7 +388,7 @@ export default {
this.multipleSelection = rows
},
removeSelectedItems () {
if (!this.multipleSelection.length) this.multipleSelection = this.history
if (!this.multipleSelection.length) this.multipleSelection = this.list
this.multipleSelection.forEach(e => history.remove(e.id))
this.multipleSelection = []
this.getAllhistory()
@@ -224,6 +403,9 @@ export default {
name: e.name
}
}
if (e.hasUpdate) {
this.clearHasUpdateFlag(e)
}
},
async playEvent (e) {
const db = await history.find({ site: e.site, ids: e.ids })
@@ -232,8 +414,19 @@ export default {
} else {
this.video = { key: e.site, info: { id: e.ids, name: e.name, index: 0 } }
}
if (e.hasUpdate) {
this.clearHasUpdateFlag(e)
}
this.view = 'Play'
},
async clearHasUpdateFlag (e) {
const db = await history.find({ id: e.id })
if (db) {
db.hasUpdate = false
history.update(e.id, db)
this.getAllhistory()
}
},
shareEvent (e) {
this.share = {
show: true,
@@ -251,7 +444,7 @@ export default {
},
exportHistory () {
this.getAllhistory()
const arr = [...this.history]
const arr = [...this.list]
const str = JSON.stringify(arr, null, 2)
const options = {
filters: [
@@ -280,7 +473,12 @@ export default {
result.filePaths.forEach(file => {
const str = fs.readFileSync(file)
const json = JSON.parse(str)
json.forEach(record => { if (record.detail.m3u8List) record.detail.fullList = [].concat(record.detail.m3u8List) })
json.forEach(record => {
if (record.detail && record.detail.m3u8List) {
record.detail.fullList = [].concat({ flag: 'm3u8', list: record.detail.m3u8List })
delete record.detail.m3u8List
}
})
history.bulkAdd(json).then(res => {
this.$message.success('导入成功')
this.getAllhistory()
@@ -291,7 +489,7 @@ export default {
},
getAllhistory () {
history.all().then(res => {
this.history = res.reverse()
this.list = res.reverse()
})
},
getAllsites () {
@@ -315,24 +513,13 @@ export default {
updateDatabase () {
history.clear().then(res => {
let id = length
this.history.forEach(ele => {
this.list.forEach(ele => {
ele.id = id
id -= 1
history.add(ele)
})
})
},
updateViewMode () {
if (this.setting.historyViewMode === 'table') {
this.showShiftPrompt()
} else {
setTimeout(() => { if (this.$refs.historyWaterfall) this.$refs.historyWaterfall.refresh() }, 700)
}
setting.find().then(res => {
res.historyViewMode = this.setting.historyViewMode
setting.update(res)
})
},
showShiftPrompt () {
if (this.setting.shiftTooltipLimitTimes === undefined) this.setting.shiftTooltipLimitTimes = 5
if (this.setting.shiftTooltipLimitTimes) {

View File

@@ -110,9 +110,10 @@ import { mapMutations } from 'vuex'
import { iptv, channelList, setting } from '../lib/dexie'
import { iptv as defaultChannels } from '../lib/dexie/initData'
import zy from '../lib/site/tools'
import { remote } from 'electron'
import fs from 'fs'
import Sortable from 'sortablejs'
import axios from 'axios'
const remote = require('@electron/remote')
export default {
name: 'iptv',
data () {
@@ -349,10 +350,55 @@ export default {
this.$message.info('正在检测, 请勿操作.')
return false
}
this.$msgbox.prompt('请输入网址', '提示', {
distinguishCancelAndClose: true,
inputValue: 'http://y.qibaobaike.com/nzy.txt',
confirmButtonText: '确定',
cancelButtonText: '本地文件'
}).then(({ value }) => {
this.importOnlineChannels(value)
}).catch(action => {
if (action === 'cancel') {
this.importLocalChannels()
}
})
},
async importOnlineChannels (url) {
try {
const docs = []
let id = this.channelList.length ? this.channelList.slice(-1)[0].id + 1 : 1
const res = await axios.get(url)
const result = res.data.split('\n')
const supportFormats = /\.(m3u8|flv)$/
for (const i of result) {
if (i.includes('http') && supportFormats.test(i)) {
const j = i.split(',')
const doc = {
id: id,
name: j[0],
url: j[1],
isActive: true
}
id += 1
docs.push(doc)
}
}
// 获取url不重复的列表
const uniqueList = [...new Map(docs.map(item => [item.url, item])).values()]
iptv.clear().then(res => {
iptv.bulkAdd(uniqueList).then(e => { // 支持导入同名频道,群里反馈
this.updateChannelList()
})
})
this.$message.success('导入成功')
} catch (error) {
this.$message.warning('导入失败')
}
},
importLocalChannels () {
const options = {
filters: [
{ name: 'm3u file', extensions: ['m3u', 'm3u8'] },
{ name: 'JSON file', extensions: ['json'] }
{ name: '支持的文件格式', extensions: ['m3u', 'm3u8', 'json', 'txt'] }
],
properties: ['openFile', 'multiSelections']
}
@@ -389,8 +435,9 @@ export default {
this.updateChannelList()
})
})
} else {
// Import Json file
this.$message.success('导入成功')
}
if (file.endsWith('json')) {
const importedList = JSON.parse(fs.readFileSync(file))
importedList.forEach(ele => {
const commonEle = this.channelList.find(e => e.name === ele.name)
@@ -404,9 +451,41 @@ export default {
}
})
this.updateDatabase()
this.$message.success('导入成功')
}
if (file.endsWith('txt')) {
try {
const docs = []
let id = this.channelList.length ? this.channelList.slice(-1)[0].id + 1 : 1
const playlist = fs.readFileSync(file, 'utf8')
const result = playlist.split('\n')
const supportFormats = /\.(m3u8|flv)$/
for (const i of result) {
if (i.includes('http') && supportFormats.test(i)) {
const j = i.split(',')
const doc = {
id: id,
name: j[0],
url: j[1],
isActive: true
}
id += 1
docs.push(doc)
}
}
// 获取url不重复的列表
const uniqueList = [...new Map(docs.map(item => [item.url, item])).values()]
iptv.clear().then(res => {
iptv.bulkAdd(uniqueList).then(e => { // 支持导入同名频道,群里反馈
this.updateChannelList()
})
})
this.$message.success('导入成功')
} catch (error) {
this.$message.warning('导入失败')
}
}
})
this.$message.success('导入成功')
}
})
},

View File

@@ -50,7 +50,7 @@
<polyline points="12 5 12 12 16 16"></polyline>
</svg>
</span>
<span class="zy-svg" @click="starEvent" :class="isStar ? 'active' : ''" v-show="right.list.length > 0">
<span class="zy-svg" @click="starEvent" :class="isStar ? 'active' : ''" v-show="right.list.length > 0 || isStar">
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-labelledby="favouriteIconTitle">
<title id="favouriteIconTitle">收藏</title>
<path d="M12,21 L10.55,19.7051771 C5.4,15.1242507 2,12.1029973 2,8.39509537 C2,5.37384196 4.42,3 7.5,3 C9.24,3 10.91,3.79455041 12,5.05013624 C13.09,3.79455041 14.76,3 16.5,3 C19.58,3 22,5.37384196 22,8.39509537 C22,12.1029973 18.6,15.1242507 13.45,19.7149864 L12,21 Z"></path>
@@ -217,7 +217,7 @@
</div>
</transition>
<transition name="slideX">
<div v-if="state.showChannelList" class="list" v-clickoutside="closeListEvent">
<div v-if="state.showChannelList && channelList && channelList.length > 0" class="list" v-clickoutside="closeListEvent">
<div class="list-top">
<span class="list-top-title">频道列表</span>
<span class="list-top-close zy-svg" @click="state.showChannelList = false">
@@ -252,6 +252,7 @@ import { mapMutations } from 'vuex'
import { star, history, setting, shortcut, mini, channelList, sites } from '../lib/dexie'
import zy from '../lib/site/tools'
import Player from 'xgplayer'
import 'xgplayer-mp4'
import HlsJsPlayer from 'xgplayer-hls.js'
import FlvJsPlayer from 'xgplayer-flv.js'
import mt from 'mousetrap'
@@ -259,7 +260,8 @@ import Clickoutside from 'element-ui/src/utils/clickoutside'
import { exec, execFile } from 'child_process'
import PinyinMatch from 'pinyin-match'
const { remote, clipboard } = require('electron')
const { clipboard } = require('electron')
const remote = require('@electron/remote')
const win = remote.getCurrentWindow()
const URL = require('url')
const VIDEO_DETAIL_CACHE = {}
@@ -342,7 +344,7 @@ export default {
videoTitle: true,
airplay: true,
closeVideoTouch: true,
ignores: ['cssFullscreen', 'replay', 'error'], // 为了切换播放器类型时避免显示错误刷新,暂时忽略错误
ignores: ['replay', 'error'], // 为了切换播放器类型时避免显示错误刷新,暂时忽略错误
preloadTime: 300
},
state: {
@@ -445,6 +447,9 @@ export default {
set (val) {
this.SET_DetailCache(val)
}
},
VideoEssentialInfo () {
return this.video.key + '@' + this.video.info.id + '@' + this.video.info.index
}
},
watch: {
@@ -458,12 +463,11 @@ export default {
}
}
},
video: {
VideoEssentialInfo: {
handler () {
if (this.changingIPTV) return
this.getUrls()
},
deep: true
}
},
setting: {
handler () {
@@ -639,6 +643,7 @@ export default {
},
playVideo (index = 0, time = 0) {
this.isLive = false
this.isStar = false
this.exportablePlaylist = false
this.fetchPlaylist().then(async (fullList) => {
let playlist = fullList[0].list // ZY支持的已移到首位
@@ -654,9 +659,9 @@ export default {
const currentSite = await sites.find({ key: this.video.key })
this.$message.info('即将调用解析接口播放,请等待...')
if (currentSite.jiexiUrl) {
this.onlineUrl = /^\s*(default|默认)\s*$/i.test(currentSite.jiexiUrl) ? this.setting.defaultParseURL + url : currentSite.jiexiUrl + url
this.onlineUrl = currentSite.jiexiUrl + url
} else {
this.onlineUrl = url
this.onlineUrl = this.setting.defaultParseURL + url
}
this.videoPlaying('online')
return
@@ -710,7 +715,7 @@ export default {
name: res.name
})
resolve(res.fullList)
})
}).catch(err => { this.$message.error('播放地址可能已失效,请换源并调整收藏', err); this.name = this.video.info.name; this.updateStar(); this.otherEvent() })
} else {
res = this.DetailCache[cacheKey]
this.name = res.name
@@ -1567,7 +1572,7 @@ export default {
},
minMaxEvent () {
win.on('minimize', () => {
if (this.xg && this.xg.hasStart) {
if (this.xg && this.xg.hasStart && this.setting.pauseWhenMinimize) {
this.xg.pause()
}
})
@@ -1663,6 +1668,9 @@ export default {
cursor: pointer;
margin-left: 3px;
}
.xgplayer-skin-default .xg-btn-playPrev {
margin-left: 50px;
}
.xgplayer-skin-default .xg-btn-quitMiniMode {
display: none;
}
@@ -1740,12 +1748,6 @@ export default {
.xgplayer-skin-default .xgplayer-playbackrate {
width: 40px !important;
}
.xgplayer-skin-default .xgplayer-playbackrate .name {
top: 10px !important;
}
.xgplayer-skin-default .xgplayer-playbackrate ul {
bottom: 20px;
}
.xgplayer-skin-default .xgplayer-playbackrate ul li {
font-size: 13px !important;
}

View File

@@ -1,39 +1,63 @@
<template>
<div class="listpage" id="recommendations">
<div class="listpage-header" id="recommendations-header">
<el-switch v-model="setting.recommendationViewMode" active-text="海报" active-value="picture" inactive-text="列表" inactive-value="table" @change="updateViewMode"></el-switch>
<el-select v-model="selectedRecommendationType" size="small" slot="prepend"
:popper-append-to-body="false"
popper-class="popper"
default-first-option placeholder="请选择"
@change="changeRecommendationTypeEvent">
<el-option
v-for="item in recommendationTypes"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select>
<el-button type="text">视频数{{ recommendations.length }}</el-button>
<el-select v-model="selectedAreas" size="small" multiple placeholder="地区" popper-class="popper" :popper-append-to-body="false">
<el-option
v-for="item in areas"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select>
<el-select v-model="selectedTypes" size="small" multiple placeholder="类型" popper-class="popper" :popper-append-to-body="false">
<el-option
v-for="item in types"
: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">
<el-option
v-for="item in sortKeywords"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select>
<el-button :loading="loading" @click.stop="updateEvent" icon="el-icon-refresh">更新推荐</el-button>
</div>
<div class="toolbar" v-show="showToolbar">
<el-select v-model="selectedAreas" size="small" multiple placeholder="地区" popper-class="popper" :popper-append-to-body="false" @remove-tag="refreshFilteredList" @change="refreshFilteredList">
<el-option
v-for="item in areas"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select>
<el-select v-model="selectedTypes" size="small" multiple placeholder="类型" popper-class="popper" :popper-append-to-body="false" @remove-tag="refreshFilteredList" @change="refreshFilteredList">
<el-option
v-for="item in types"
: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 class="listpage-header-divider" content-position="right">
<el-button type="text" size="mini" @click="toggleViewMode">视图切换</el-button>
<el-button type="text" size="mini" @click='() => { showToolbar = !showToolbar; if (!showToolbar) this.refreshFilteredList() }' title="收起工具栏会重置筛选排序">{{ showToolbar ? '隐藏工具栏' : '显示工具栏' }}</el-button>
<el-button type="text" size="mini" @click="backTop">回到顶部</el-button>
</el-divider>
<div class="listpage-body" id="recommendations-body" >
<div class="show-table" id="star-table" v-if="setting.recommendationViewMode === 'table'">
<el-table size="mini" fit height="100%" row-key="id"
ref="recommendationsTable"
:data="filteredRecommendations"
:data="filteredList"
@row-click="detailEvent">
<el-table-column
prop="name"
@@ -55,13 +79,13 @@
width="100"
align="center">
</el-table-column>
<el-table-column v-if="filteredRecommendations.some(e => e.rate)"
<el-table-column v-if="filteredList.some(e => e.rate)"
prop="rate"
align="center"
width="100"
label="豆瓣评分">
</el-table-column>
<el-table-column v-if="filteredRecommendations.some(e => e.detail.note)"
<el-table-column v-if="filteredList.some(e => e.detail.note)"
prop="detail.note"
label="备注">
</el-table-column>
@@ -74,13 +98,12 @@
<el-button @click.stop="playEvent(scope.row)" type="text">播放</el-button>
<el-button @click.stop="shareEvent(scope.row)" type="text">分享</el-button>
<el-button @click.stop="downloadEvent(scope.row)" type="text">下载</el-button>
<el-button @click.stop="deleteEvent(scope.row)" type="text">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="show-picture" id="star-picture" v-if="setting.recommendationViewMode === 'picture'">
<Waterfall ref="recommendationsWaterfall" :list="filteredRecommendations" :gutter="20" :width="240"
<Waterfall ref="recommendationsWaterfall" :list="filteredList" :gutter="20" :width="240"
:breakpoints="{
1200: { //当屏幕宽度小于等于1200
rowPerView: 4,
@@ -106,7 +129,6 @@
<span class="o-play" @click="playEvent(props.data)">播放</span>
<span class="o-share" @click="shareEvent(props.data)">分享</span>
<span class="o-star" @click="downloadEvent(props.data)">下载</span>
<span class="o-star" @click="deleteEvent(props.data)">删除</span>
</div>
</div>
</div>
@@ -126,10 +148,12 @@
</template>
<script>
import { mapMutations } from 'vuex'
import { history, recommendation, setting } from '../lib/dexie'
import { history, recommendation, setting, sites, cachedMovies } from '../lib/dexie'
import zy from '../lib/site/tools'
import Waterfall from 'vue-waterfall-plugin'
import axios from 'axios'
const { clipboard } = require('electron')
export default {
name: 'recommendations',
data () {
@@ -138,11 +162,49 @@ export default {
sites: [],
loading: false,
types: [],
selectedTypes: [],
areas: [],
filteredList: [],
// 不同推荐
recommendationsDefault: [],
recommendationTypes: ['豆瓣热门电影', '豆瓣高分电影', '豆瓣华语电影', '豆瓣冷门佳片', '豆瓣热门剧集', '豆瓣热门美剧', '豆瓣热门英剧', '豆瓣热门国产剧', '豆瓣热门综艺', '豆瓣热门动漫', '豆瓣热门纪录片', '豆瓣热门动画电影'],
selectedRecommendationType: '豆瓣热门电影',
// Toolbar
showToolbar: false,
selectedAreas: [],
selectedTypes: [],
sortKeyword: '',
sortKeywords: ['上映', '评分', '默认']
sortKeywords: ['按片名', '按上映年份', '按更新时间', '按评分'],
selectedYears: { start: 0, end: new Date().getFullYear() },
// 缓存数据
localCachedMovies: [],
// 豆瓣
douban: {
page_limit: 50,
hotMoviePageStart: 0,
hotmovie: [],
hotTVPageStart: 0,
hotTV: [],
highRateMoviePageStart: 0,
highRateMovie: [],
hotAnimePageStart: 0,
hotAnime: [],
hotDocumentaryPageStart: 0,
hotDocumentary: [],
hotTVShowPageStart: 0,
hotTVShow: [],
hotCartonMoviePageStart: 0,
hotCartonMovie: [],
hotAmericanTVSeriesPageStart: 0,
hotAmericanTVSeries: [],
hotBritishTVSeriesPageStart: 0,
hotBritishTVSeries: [],
hotChineseTVSeriesPageStart: 0,
hotChineseTVSeries: [],
goodButNotHotMoviesPageStart: 0,
goodButNotHotMovies: [],
chineseMoviesPageStart: 0,
chineseMovies: []
}
}
},
components: {
@@ -188,11 +250,6 @@ export default {
set (val) {
this.SET_SETTING(val)
}
},
filteredRecommendations () {
let filteredData = this.recommendations.filter(x => (this.selectedAreas.length === 0) || this.selectedAreas.includes(x.detail.area))
filteredData = filteredData.filter(x => (this.selectedTypes.length === 0) || this.selectedTypes.includes(x.detail.type))
return filteredData
}
},
watch: {
@@ -201,44 +258,142 @@ export default {
if (this.$refs.recommendationsWaterfall) this.$refs.recommendationsWaterfall.resize()
}
},
sortKeyword () {
switch (this.sortKeyword) {
case '上映':
this.recommendations = this.recommendations.sort(function (a, b) {
return b.detail.year - a.detail.year
})
break
case '评分':
this.recommendations.sort(function (a, b) {
return b.rate - a.rate
})
break
case '默认':
this.recommendations.sort(function (a, b) {
return b.id - a.id
})
break
default:
break
}
recommendations: {
handler (recommendations) {
this.areas = [...new Set(recommendations.map(ele => ele.detail.area))].filter(x => x)
this.types = [...new Set(recommendations.map(ele => ele.detail.type))].filter(x => x)
this.refreshFilteredList()
},
deep: true
}
},
methods: {
...mapMutations(['SET_VIEW', 'SET_DETAIL', 'SET_VIDEO', 'SET_SHARE', 'SET_SETTING']),
detailEvent (e) {
this.detail = {
show: true,
key: e.key,
info: {
id: e.ids,
name: e.name
changeRecommendationTypeEvent () {
if (this.selectedRecommendationType === '作者推荐') {
this.recommendations = this.recommendationsDefault
} else {
if (this.selectedRecommendationType === '豆瓣热门电影') {
this.recommendations = [...this.douban.hotmovie]
}
if (this.selectedRecommendationType === '豆瓣高分电影') {
this.recommendations = [...this.douban.highRateMovie]
}
if (this.selectedRecommendationType === '豆瓣热门剧集') {
this.recommendations = [...this.douban.hotTV]
}
if (this.selectedRecommendationType === '豆瓣热门美剧') {
this.recommendations = [...this.douban.hotAmericanTVSeries]
}
if (this.selectedRecommendationType === '豆瓣热门英剧') {
this.recommendations = [...this.douban.hotBritishTVSeries]
}
if (this.selectedRecommendationType === '豆瓣热门国产剧') {
this.recommendations = [...this.douban.hotChineseTVSeries]
}
if (this.selectedRecommendationType === '豆瓣热门动漫') {
this.recommendations = [...this.douban.hotAnime]
}
if (this.selectedRecommendationType === '豆瓣热门纪录片') {
this.recommendations = [...this.douban.hotDocumentary]
}
if (this.selectedRecommendationType === '豆瓣热门综艺') {
this.recommendations = [...this.douban.hotTVShow]
}
if (this.selectedRecommendationType === '豆瓣热门动画电影') {
this.recommendations = [...this.douban.hotCartonMovie]
}
if (this.selectedRecommendationType === '豆瓣冷门佳片') {
this.recommendations = [...this.douban.goodButNotHotMovies]
}
if (this.selectedRecommendationType === '豆瓣华语电影') {
this.recommendations = [...this.douban.chineseMovies]
}
if (this.recommendations.length === 0) {
this.updateDoubanRecommendationsEvent()
}
}
},
getRecommendationsDoubanMovieOrTV (doubanUrl) {
axios.get(doubanUrl).then(res => {
if (res.data) {
res.data.subjects.forEach(element => {
const localCachedMovie = this.localCachedMovies.find(e => e.key === this.sites[0].key && e.name === element.title)
if (localCachedMovie) {
this.updateDoubanRecommendataions(localCachedMovie)
} else {
this.searchAndCacheMovie(element)
}
})
}
})
},
updateDoubanRecommendataions (movie) {
this.recommendations.push(movie)
if (this.selectedRecommendationType === '豆瓣热门电影') {
this.douban.hotmovie.push(movie)
}
if (this.selectedRecommendationType === '豆瓣高分电影') {
this.douban.highRateMovie.push(movie)
}
if (this.selectedRecommendationType === '豆瓣热门剧集') {
this.douban.hotTV.push(movie)
}
if (this.selectedRecommendationType === '豆瓣热门美剧') {
this.douban.hotAmericanTVSeries.push(movie)
}
if (this.selectedRecommendationType === '豆瓣热门英剧') {
this.douban.hotBritishTVSeries.push(movie)
}
if (this.selectedRecommendationType === '豆瓣热门国产剧') {
this.douban.hotChineseTVSeries.push(movie)
}
if (this.selectedRecommendationType === '豆瓣热门动漫') {
this.douban.hotAnime.push(movie)
}
if (this.selectedRecommendationType === '豆瓣热门纪录片') {
this.douban.hotDocumentary.push(movie)
}
if (this.selectedRecommendationType === '豆瓣热门综艺') {
this.douban.hotTVShow.push(movie)
}
if (this.selectedRecommendationType === '豆瓣热门动画电影') {
this.douban.hotCartonMovie.push(movie)
}
if (this.selectedRecommendationType === '豆瓣冷门佳片') {
this.douban.goodButNotHotMovies.push(movie)
}
if (this.selectedRecommendationType === '豆瓣华语电影') {
this.douban.chineseMovies.push(movie)
}
},
searchAndCacheMovie (element) {
zy.searchFirstDetail(this.sites[0].key, element.title).then(detailRes => {
if (detailRes) {
const doc = {
key: this.sites[0].key,
ids: detailRes.id,
site: this.sites[0],
name: detailRes.name,
detail: detailRes,
rate: element.rate
}
this.updateDoubanRecommendataions(doc)
this.localCachedMovies.push(doc)
cachedMovies.add(doc)
}
})
},
updateEvent () {
if (this.selectedRecommendationType === '作者推荐') {
this.updateAuthorRecommendataions()
} else {
this.updateDoubanRecommendationsEvent()
}
},
updateAuthorRecommendataions () {
const url = 'https://raw.githubusercontent.com/cuiocean/ZY-Player-Resources/main/Recommendations/Recommendations.json'
this.loading = true
const axios = require('axios')
axios.get(url).then(res => {
if (res.status === 200) {
if (res.data.length > 0) {
@@ -255,6 +410,128 @@ export default {
this.$message.warning('最新的推荐数据保存在Github上,请考虑使用代理或者等待下一版本内置数据更新.')
})
},
updateDoubanRecommendationsEvent () {
let doubanUrl = ''
if (this.selectedRecommendationType === '豆瓣热门电影') {
doubanUrl = `https://movie.douban.com/j/search_subjects?type=movie&tag=热门&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.hotMoviePageStart}`
this.douban.hotMoviePageStart = this.douban.hotMoviePageStart + this.douban.page_limit
}
if (this.selectedRecommendationType === '豆瓣热门剧集') {
doubanUrl = `https://movie.douban.com/j/search_subjects?type=tv&tag=热门&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.hotTVPageStart}`
this.douban.hotTVPageStart = this.douban.hotTVPageStart + this.douban.page_limit
}
if (this.selectedRecommendationType === '豆瓣热门美剧') {
doubanUrl = `https://movie.douban.com/j/search_subjects?type=tv&tag=美剧&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.hotCartonMoviePageStart}`
this.douban.hotCartonMoviePageStart = this.douban.hotCartonMoviePageStart + this.douban.page_limit
}
if (this.selectedRecommendationType === '豆瓣热门英剧') {
doubanUrl = `https://movie.douban.com/j/search_subjects?type=tv&tag=英剧&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.hotBritishTVSeriesPageStart}`
this.douban.hotBritishTVSeriesPageStart = this.douban.hotBritishTVSeriesPageStart + this.douban.page_limit
}
if (this.selectedRecommendationType === '豆瓣热门国产剧') {
doubanUrl = `https://movie.douban.com/j/search_subjects?type=tv&tag=国产剧&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.hotChineseTVSeriesPageStart}`
this.douban.hotChineseTVSeriesPageStart = this.douban.hotChineseTVSeriesPageStart + this.douban.page_limit
}
if (this.selectedRecommendationType === '豆瓣高分电影') {
doubanUrl = `https://movie.douban.com/j/search_subjects?type=movie&tag=豆瓣高分&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.highRateMoviePageStart}`
this.douban.highRateMoviePageStart = this.douban.highRateMoviePageStart + this.douban.page_limit
}
if (this.selectedRecommendationType === '豆瓣热门动漫') {
doubanUrl = `https://movie.douban.com/j/search_subjects?type=tv&tag=日本动画&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.hotAnimePageStart}`
this.douban.hotAnimePageStart = this.douban.hotAnimePageStart + this.douban.page_limit
}
if (this.selectedRecommendationType === '豆瓣热门纪录片') {
doubanUrl = `https://movie.douban.com/j/search_subjects?type=tv&tag=纪录片&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.hotDocumentaryPageStart}`
this.douban.hotDocumentaryPageStart = this.douban.hotDocumentaryPageStart + this.douban.page_limit
}
if (this.selectedRecommendationType === '豆瓣热门综艺') {
doubanUrl = `https://movie.douban.com/j/search_subjects?type=tv&tag=综艺&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.hotTVShowPageStart}`
this.douban.hotTVShowPageStart = this.douban.hotTVShowPageStart + this.douban.page_limit
}
if (this.selectedRecommendationType === '豆瓣热门动画电影') {
doubanUrl = `https://movie.douban.com/j/search_subjects?type=movie&tag=动画&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.hotCartonMoviePageStart}`
this.douban.hotCartonMoviePageStart = this.douban.hotCartonMoviePageStart + this.douban.page_limit
}
if (this.selectedRecommendationType === '豆瓣冷门佳片') {
doubanUrl = `https://movie.douban.com/j/search_subjects?type=movie&tag=冷门佳片&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.goodButNotHotMoviesPageStart}`
this.douban.goodButNotHotMoviesPageStart = this.douban.goodButNotHotMoviesPageStart + this.douban.page_limit
}
if (this.selectedRecommendationType === '豆瓣华语电影') {
doubanUrl = `https://movie.douban.com/j/search_subjects?type=movie&tag=华语&sort=recommend&page_limit=${this.douban.page_limit}&page_start=${this.douban.chineseMoviesPageStart}`
this.douban.chineseMoviesPageStart = this.douban.chineseMoviesPageStart + this.douban.page_limit
}
this.getRecommendationsDoubanMovieOrTV(doubanUrl)
},
toggleViewMode () {
this.setting.recommendationViewMode = this.setting.recommendationViewMode === 'picture' ? 'table' : 'picture'
if (this.setting.recommendationViewMode === 'table') {
setTimeout(() => { this.rowDrop() }, 100)
} else {
setTimeout(() => { if (this.$refs.recommendationsWaterfall) this.$refs.recommendationsWaterfall.refresh() }, 700)
}
setting.find().then(res => {
res.recommendationViewMode = this.setting.recommendationViewMode
setting.update(res)
})
},
backTop () {
if (this.setting.recommendationViewMode === 'picture') {
document.getElementById('recommendations-body').scrollTop = 0
} else {
this.$refs.recommendationsTable.bodyWrapper.scrollTop = 0
}
},
refreshFilteredList () {
if (!this.showToolbar) {
this.sortKeyword = ''
this.selectedAreas = []
this.selectedSearchClassNames = []
this.selectedYears.start = 0
this.selectedYears.end = new Date().getFullYear()
this.filteredList = this.recommendations
} else {
let filteredData = this.recommendations
filteredData = filteredData.filter(x => (this.selectedAreas.length === 0) || this.selectedAreas.includes(x.detail.area))
filteredData = filteredData.filter(x => (this.selectedTypes.length === 0) || this.selectedTypes.includes(x.detail.type))
filteredData = filteredData.filter(res => res.detail.year >= this.selectedYears.start)
filteredData = filteredData.filter(res => res.detail.year <= this.selectedYears.end)
switch (this.sortKeyword) {
case '按上映年份':
filteredData.sort(function (a, b) {
return b.detail.year - a.detail.year
})
break
case '按片名':
filteredData.sort(function (a, b) {
return a.detail.name.localeCompare(b.detail.name, 'zh')
})
break
case '按更新时间':
filteredData.sort(function (a, b) {
return new Date(b.detail.last) - new Date(a.detail.last)
})
break
case '按评分':
filteredData.sort(function (a, b) {
return b.rate - a.rate
})
break
default:
break
}
this.filteredList = filteredData
}
},
detailEvent (e) {
this.detail = {
show: true,
key: e.key,
info: {
id: e.ids,
name: e.name
}
}
},
async playEvent (e) {
const db = await history.find({ site: e.key, ids: e.ids })
if (db) {
@@ -264,14 +541,6 @@ export default {
}
this.view = 'Play'
},
deleteEvent (e) {
recommendation.remove(e.id).then(res => {
if (res) {
this.$message.warning('删除失败')
}
this.getRecommendations()
})
},
shareEvent (e) {
this.share = {
show: true,
@@ -291,12 +560,9 @@ export default {
})
},
getRecommendations () {
recommendation.all().then(res => {
this.recommendations = res.sort(function (a, b) {
return b.id - a.id
})
this.getFilterData()
})
this.recommendationsDefault = []
this.changeRecommendationTypeEvent()
this.getFilterData()
},
getFilterData () {
this.types = [...new Set(this.recommendations.map(ele => ele.detail.type))].filter(x => x)
@@ -308,10 +574,24 @@ export default {
res.recommendationViewMode = this.setting.recommendationViewMode
setting.update(res)
})
},
getAllSites () {
sites.all().then(res => {
if (res.length > 0) {
this.sites = res.filter(item => item.isActive)
}
})
},
getCachedMovies () {
cachedMovies.all().then(res => {
this.localCachedMovies = res
})
}
},
created () {
this.getAllSites()
this.getRecommendations()
this.getCachedMovies()
},
mounted () {
addEventListener('resize', () => {

View File

@@ -5,9 +5,7 @@
<div class="info">
<a @click="linkOpen('http://zyplayer.fun/')">官网</a>
<a @click="linkOpen('https://github.com/Hunlongyu/ZY-Player')">Github</a>
<a @click="linkOpen('https://github.com/Hunlongyu/ZY-Player/releases/tag/v' + pkg.version)">v{{pkg.version}}更新日志</a>
<a @click="linkOpen('https://github.com/Hunlongyu/ZY-Player/issues/80')">常见问题</a>
<a @click="linkOpen('https://github.com/Hunlongyu/ZY-Player/issues')">反馈建议</a>
<a @click="linkOpen('https://github.com/Hunlongyu/ZY-Player/discussions/776')">软件完全免费如遇收费请立即给差评并退费</a>
<a style="color:#38dd77" @click="openUpdate()" v-show="update.find" >最新版本v{{update.version}}</a>
</div>
<div class="shortcut">
@@ -93,9 +91,6 @@
<div class="zy-select">
<div class="vs-placeholder vs-noAfter" @click="show.configSitesDataUrlDialog = true">设置源站接口文件</div>
</div>
<div class="zy-input" @click="toggleExcludeRootClasses">
<input type="checkbox" v-model = "d.excludeRootClasses" @change="updateSettingEvent"> 屏蔽主分类
</div>
</div>
</div>
<div class="site">
@@ -113,6 +108,15 @@
</div>
</div>
</div>
<div class="site">
<div class="title">窗口及播放</div>
<div class="site-box">
<div class="zy-input">
<input type="checkbox" v-model = "d.restoreWindowPositionAndSize" @change="updateSettingEvent"> 记录并恢复窗口位置和大小
<input type="checkbox" v-model = "d.pauseWhenMinimize" @change="updateSettingEvent"> 最小化时暂停播放
</div>
</div>
</div>
<div class="theme">
<div class="title">主题</div>
<div class="theme-box">
@@ -142,13 +146,6 @@
</div>
</div>
</div>
<div class="qrcode">
<div class="title">请作者吃辣条</div>
<div class="qrcode-box">
<img class="qrcode-item" src="../assets/image/wepay-hunlongyu.png">
<img class="qrcode-item" src="../assets/image/wepay_cuiocean.jpg">
</div>
</div>
<div class="clearDB">
<span @click="clearDBEvent" class="clearBtn">软件重置</span>
<span @click="changePasswordEvent" class="clearBtn">设置密码</span>
@@ -167,7 +164,7 @@
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="closeDialog">取消</el-button>
<el-button type="danger" @click="get7kParseURL">重置</el-button>
<el-button type="danger" @click="resetDefaultParseURL">重置</el-button>
<el-button type="primary" @click="configDefaultParseURL">确定</el-button>
</span>
</el-dialog>
@@ -181,7 +178,7 @@
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="closeDialog">取消</el-button>
<el-button type="danger" @click="getDefaultdeSitesDataURL">重置</el-button>
<el-button type="danger" @click="resetDefaultSitesDataURL">重置</el-button>
<el-button type="primary" @click="configSitesDataURL">确定</el-button>
</span>
</el-dialog>
@@ -258,8 +255,9 @@
import { mapMutations } from 'vuex'
import pkg from '../../package.json'
import { setting, sites, shortcut } from '../lib/dexie'
import { sites as defaultSites, localKey as defaultShortcuts } from '../lib/dexie/initData'
import { shell, clipboard, remote, ipcRenderer } from 'electron'
import { localKey as defaultShortcuts } from '../lib/dexie/initData'
import { shell, clipboard, ipcRenderer } from 'electron'
const remote = require('@electron/remote')
import db from '../lib/dexie/dexie'
import zy from '../lib/site/tools'
export default {
@@ -328,14 +326,28 @@ export default {
this.d = res
this.setting = this.d
if (!this.setting.defaultParseURL) this.configDefaultParseURL()
if (!this.setting.sitesDataURL) this.getDefaultdeSitesDataURL()
if (!this.setting.sitesDataURL) this.resetDefaultSitesDataURL()
})
},
async getDefaultSites () {
const s = await setting.find()
zy.getDefaultSites(s.sitesDataURL).then(res => {
if (res && typeof res === 'string') {
const json = JSON.parse(res)
sites.clear().then(sites.bulkAdd(json))
}
if (res && typeof res === 'object') {
sites.clear().then(sites.bulkAdd(res))
}
}).catch(error => {
this.$message.error('获取云端源站失败. ' + error)
})
},
getSites () {
sites.all().then(res => {
if (res.length <= 0) {
this.$message.warning('检测到视频源未能正常加载, 即将重置源.')
sites.clear().then(sites.bulkAdd(defaultSites).then(this.getSites()))
this.getDefaultSites()
}
})
},
@@ -365,25 +377,20 @@ export default {
this.d.excludeRootClasses = !this.d.excludeRootClasses
this.updateSettingEvent()
},
async get7kParseURL () {
this.$message.info('正在获取7K源解析地址...')
const parseURL = await zy.get7kParseURL()
if (parseURL.startsWith('http')) {
this.$message.success('获取成功,更新应用默认解析接口地址...')
this.setting.defaultParseURL = parseURL
}
async resetDefaultParseURL () {
this.setting.defaultParseURL = 'https://jx.bpba.cc/?v='
},
async configDefaultParseURL () {
if (!this.setting.defaultParseURL) await this.get7kParseURL()
this.d.defaultParseURL = this.setting.defaultParseURL.trim()
if (!this.setting.defaultParseURL) await this.resetDefaultParseURL()
this.d.defaultParseURL = this.setting.defaultParseURL?.trim()
this.show.configDefaultParseUrlDialog = false
this.updateSettingEvent()
},
getDefaultdeSitesDataURL () {
this.setting.sitesDataURL = 'https://raw.githubusercontent.com/cuiocean/ZY-Player-Resources/main/Sites/Sites.json'
resetDefaultSitesDataURL () {
this.setting.sitesDataURL = 'https://raw.iqiq.io/Hunlongyu/ZY-Player-Resources/main/Sites/20220713.json'
},
configSitesDataURL () {
if (!this.setting.sitesDataURL) this.getDefaultdeSitesDataURL()
if (!this.setting.sitesDataURL) this.resetDefaultSitesDataURL()
this.d.sitesDataURL = this.setting.sitesDataURL
this.show.configSitesDataUrlDialog = false
this.updateSettingEvent()

View File

@@ -1,17 +1,56 @@
<template>
<div class="listpage" id="star">
<div class="listpage-header" id="star-header">
<el-switch v-model="setting.starViewMode" active-text="海报" active-value="picture" inactive-text="列表" inactive-value="table" @change="updateViewMode"></el-switch>
<el-button @click.stop="exportFavoritesEvent" icon="el-icon-upload2" title="导出全部,自动添加扩展名">导出</el-button>
<el-button @click.stop="importFavoritesEvent" icon="el-icon-download" title="支持同时导入多个文件">导入</el-button>
<el-button @click.stop="removeSelectedItems" icon="el-icon-delete-solid">{{ multipleSelection.length === 0 ? "清空" : "删除所选" }}</el-button>
<el-button @click.stop="updateAllEvent" icon="el-icon-refresh">同步所有收藏</el-button>
<b-button-group>
<el-switch v-model="onlyShowItemsHasUpdate" active-text="有更新" inactive-text="全部" @change="refreshFilteredList"></el-switch>
<el-button @click.stop="updateAllEvent" icon="el-icon-refresh">检查更新</el-button>
</b-button-group>
</div>
<div class="toolbar" v-show="showToolbar">
<el-select v-model="selectedAreas" size="small" multiple placeholder="地区" popper-class="popper" :popper-append-to-body="false" @remove-tag="refreshFilteredList" @change="refreshFilteredList">
<el-option
v-for="item in areas"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select>
<el-select v-model="selectedTypes" size="small" multiple placeholder="类型" popper-class="popper" :popper-append-to-body="false" @remove-tag="refreshFilteredList" @change="refreshFilteredList">
<el-option
v-for="item in types"
: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 class="listpage-header-divider" content-position="right">
<el-button type="text" size="mini" @click="toggleViewMode">视图切换</el-button>
<el-button type="text" size="mini" @click='() => { showToolbar = !showToolbar; if (!showToolbar) this.refreshFilteredList() }' title="收起工具栏会重置筛选排序">{{ showToolbar ? '隐藏工具栏' : '显示工具栏' }}</el-button>
<el-button type="text" size="mini" @click="backTop">回到顶部</el-button>
</el-divider>
<div class="listpage-body" id="star-body">
<div class="show-table" id="star-table" v-if="setting.starViewMode === 'table'">
<el-table size="mini" fit height="100%" row-key="id"
ref="starTable"
:data="list"
:data="filteredList"
:cell-class-name="checkUpdate"
@row-click="detailEvent"
@sort-change="handleSortChange"
@@ -84,7 +123,7 @@
</el-table>
</div>
<div class="show-picture" id="star-picture" v-if="setting.starViewMode === 'picture'">
<Waterfall ref="starWaterfall" :list="list" :gutter="20" :width="240"
<Waterfall ref="starWaterfall" :list="filteredList" :gutter="20" :width="240"
:breakpoints="{
1200: { //当屏幕宽度小于等于1200
rowPerView: 4,
@@ -140,7 +179,7 @@
import { mapMutations } from 'vuex'
import { history, star, sites, setting } from '../lib/dexie'
import zy from '../lib/site/tools'
import { remote } from 'electron'
const remote = require('@electron/remote')
import fs from 'fs'
import Sortable from 'sortablejs'
import Waterfall from 'vue-waterfall-plugin'
@@ -155,7 +194,18 @@ export default {
shiftDown: false,
selectionBegin: '',
selectionEnd: '',
multipleSelection: []
multipleSelection: [],
filteredList: [],
areas: [],
types: [],
// Toolbar
showToolbar: false,
selectedAreas: [],
selectedTypes: [],
sortKeyword: '',
sortKeywords: ['按片名', '按上映年份', '按更新时间'],
selectedYears: { start: 0, end: new Date().getFullYear() },
onlyShowItemsHasUpdate: false
}
},
components: {
@@ -225,10 +275,77 @@ export default {
this.numNoUpdate = 0
this.$message.warning('未查询到任何更新')
}
},
list: {
handler (list) {
this.areas = [...new Set(list.map(ele => ele.detail.area))].filter(x => x)
this.types = [...new Set(list.map(ele => ele.detail.type))].filter(x => x)
this.refreshFilteredList()
},
deep: true
}
},
methods: {
...mapMutations(['SET_VIEW', 'SET_DETAIL', 'SET_VIDEO', 'SET_SHARE', 'SET_SETTING']),
toggleViewMode () {
this.setting.starViewMode = this.setting.starViewMode === 'picture' ? 'table' : 'picture'
if (this.setting.starViewMode === 'table') {
setTimeout(() => { this.rowDrop() }, 100)
this.showShiftPrompt()
} else {
setTimeout(() => { if (this.$refs.starWaterfall) this.$refs.starWaterfall.refresh() }, 700)
}
setting.find().then(res => {
res.starViewMode = this.setting.starViewMode
setting.update(res)
})
},
backTop () {
if (this.setting.starViewMode === 'picture') {
document.getElementById('star-body').scrollTop = 0
} else {
this.$refs.starTable.bodyWrapper.scrollTop = 0
}
},
refreshFilteredList () {
if (!this.showToolbar) {
this.sortKeyword = ''
this.selectedAreas = []
this.selectedSearchClassNames = []
this.selectedYears.start = 0
this.selectedYears.end = new Date().getFullYear()
this.filteredList = this.list
} else {
let filteredData = this.list
filteredData = filteredData.filter(x => (this.selectedAreas.length === 0) || this.selectedAreas.includes(x.detail.area))
filteredData = filteredData.filter(x => (this.selectedTypes.length === 0) || this.selectedTypes.includes(x.detail.type))
filteredData = filteredData.filter(res => res.detail.year >= this.selectedYears.start)
filteredData = filteredData.filter(res => res.detail.year <= this.selectedYears.end)
switch (this.sortKeyword) {
case '按上映年份':
filteredData.sort(function (a, b) {
return b.detail.year - a.detail.year
})
break
case '按片名':
filteredData.sort(function (a, b) {
return a.detail.name.localeCompare(b.detail.name, 'zh')
})
break
case '按更新时间':
filteredData.sort(function (a, b) {
return new Date(b.detail.last) - new Date(a.detail.last)
})
break
default:
break
}
this.filteredList = filteredData
}
if (this.onlyShowItemsHasUpdate) {
this.filteredList = this.filteredList.filter(x => x.hasUpdate)
}
},
handleSortChange (column, prop, order) {
this.updateDatabase()
},
@@ -331,7 +448,7 @@ export default {
star.get(e.id).then(resStar => {
if (!e.hasUpdate && e.detail.last !== doc.detail.last) {
doc.hasUpdate = true
const msg = `同步"${e.name}"成功, 检查到更新。`
const msg = `检查到"${e.name}"更新。`
this.$message.success(msg)
} else {
this.numNoUpdate += 1
@@ -340,7 +457,7 @@ export default {
this.getFavorites()
})
} catch (err) {
const msg = `同步"${e.name}"失败, 请重试`
const msg = `更新"${e.name}"失败, 请重试`
this.$message.warning(msg, err)
}
},
@@ -488,18 +605,6 @@ export default {
}
})
},
updateViewMode () {
if (this.setting.starViewMode === 'table') {
setTimeout(() => { this.rowDrop() }, 100)
this.showShiftPrompt()
} else {
setTimeout(() => { if (this.$refs.starWaterfall) this.$refs.starWaterfall.refresh() }, 700)
}
setting.find().then(res => {
res.starViewMode = this.setting.starViewMode
setting.update(res)
})
},
showShiftPrompt () {
if (this.setting.shiftTooltipLimitTimes === undefined) this.setting.shiftTooltipLimitTimes = 5
if (this.setting.shiftTooltipLimitTimes) {

View File

@@ -10,7 +10,7 @@ import Share from './Share'
import History from './History'
import EditSites from './EditSites'
import IPTV from './IPTV'
import Recommendation from './Recommendation'
// import Recommendation from './Recommendation'
export default {
registerComponents () {
Vue.component('Aside', Aside)
@@ -24,6 +24,6 @@ export default {
Vue.component('History', History)
Vue.component('EditSites', EditSites)
Vue.component('IPTV', IPTV)
Vue.component('Recommendation', Recommendation)
// Vue.component('Recommendation', Recommendation)
}
}

View File

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

View File

@@ -1,8 +1,7 @@
import Dexie from 'dexie'
import { setting, sites, localKey, iptv, recommendations } from './initData'
import { sites, localKey, iptv, recommendations, iniSetting } from './initData'
const db = new Dexie('zy')
db.version(4).stores({
search: '++id, keywords',
setting: 'id, theme, site, shortcut, view, volume, externalPlayer, searchGroup, excludeRootClasses, excludeR18Films, forwardTimeInSec, starViewMode, recommandationViewMode, searchViewMode, password, proxy, allowPassWhenIptvCheck, autocleanWhenIptvCheck',
@@ -59,8 +58,59 @@ db.version(8).stores({
})
})
db.version(9).stores({
history: '++id, [site+ids], name, type, year, index, time, duration, detail, onlinePlay, hasUpdate'
})
db.version(10).stores({
setting: 'id, theme, shortcut, view, volume, externalPlayer, searchGroup, excludeRootClasses, excludeR18Films, forwardTimeInSec, starViewMode, recommandationViewMode, searchViewMode, password, proxy, allowPassWhenIptvCheck, autocleanWhenIptvCheck, rootClassFilter, r18ClassFilter, classFilter'
}).upgrade(trans => {
trans.setting.toCollection().modify(setting => {
delete setting.site
setting.rootClassFilter = ['电影', '电影片', '电视剧', '连续剧', '综艺', '动漫']
setting.r18ClassFilter = ['伦理', '论理', '倫理', '福利', '激情', '理论', '写真', '情色', '美女', '街拍', '赤足', '性感', '里番', 'VIP']
setting.classFilter = ['电影', '电影片', '电视剧', '连续剧', '综艺', '动漫', '伦理', '论理', '倫理', '福利', '激情', '理论', '写真', '情色', '美女', '街拍', '赤足', '性感', '里番', 'VIP']
})
})
db.version(11).stores({
setting: 'id, theme, shortcut, view, volume, externalPlayer, searchGroup, excludeRootClasses, excludeR18Films, forwardTimeInSec, starViewMode, recommandationViewMode,' +
'searchViewMode, password, proxy, allowPassWhenIptvCheck, autocleanWhenIptvCheck, rootClassFilter, r18ClassFilter, classFilter, restoreWindowPositionAndSize, windowPositionAndSize, pauseWhenMinimize',
cachedMovies: '++id, [key+ids], site, name, detail, index, rate, hasUpdate'
}).upgrade(trans => {
trans.setting.toCollection().modify(setting => {
setting.restoreWindowPositionAndSize = false
setting.windowPositionAndSize = {
x: 0,
y: 0,
width: 1080,
height: 720
}
setting.pauseWhenMinimize = false
})
})
db.version(11).stores({
setting: 'id, theme, shortcut, view, volume, externalPlayer, searchGroup, excludeRootClasses, excludeR18Films, forwardTimeInSec, starViewMode, recommandationViewMode,' +
'searchViewMode, password, proxy, allowPassWhenIptvCheck, autocleanWhenIptvCheck, rootClassFilter, r18ClassFilter, classFilter, restoreWindowPositionAndSize,' +
'windowPositionAndSize, pauseWhenMinimize, sitesDataURL, defaultParseURL'
}).upgrade(trans => {
trans.setting.toCollection().modify(setting => {
setting.sitesDataURL = 'https://raw.iqiq.io/Hunlongyu/ZY-Player-Resources/main/Sites/20220713.json'
setting.defaultParseURL = 'https://jx.bpba.cc/?v='
})
})
db.version(12).stores({
sites: '++id, key, name, api, download, jiexiUrl, isActive, group, reverseOrder'
}).upgrade(trans => {
trans.sites.toCollection().modify(site => {
site.reverseOrder = false
})
})
db.on('populate', () => {
db.setting.bulkAdd(setting)
db.setting.bulkAdd(iniSetting)
db.sites.bulkAdd(sites)
db.shortcut.bulkAdd(localKey)
db.iptv.bulkAdd(iptv)

View File

@@ -19,6 +19,9 @@ export default {
async remove (id) {
return await history.delete(id)
},
async get (id) {
return await history.get(id)
},
async clear () {
return await history.clear()
}

View File

@@ -8,6 +8,7 @@ import search from './search'
import iptv from './iptv'
import channelList from './channelList'
import recommendation from './recommendation'
import cachedMovies from './cachedMovies'
export {
history,
@@ -19,5 +20,6 @@ export {
iptv,
channelList,
search,
recommendation
recommendation,
cachedMovies
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,82 @@
[{
"id": 0,
"theme": "light",
"shortcut": true,
"view": "picture",
"externalPlayer": "",
"searchGroup": "全站",
"excludeRootClasses": true,
"excludeR18Films": true,
"forwardTimeInSec": 5,
"waitingTimeInSec": 15,
"starViewMode": "picture",
"recommendationViewMode": "picture",
"historyViewMode": "picture",
"searchViewMode": "picture",
"password": "",
"proxy": {
"type": "none",
"scheme": "",
"url": "",
"port": ""
},
"allowPassWhenIptvCheck": true,
"autocleanWhenIptvCheck": false,
"autoChangeSourceWhenIptvStalling": true,
"shortcutModified": false,
"sitesDataURL": "https://raw.iqiq.io/Hunlongyu/ZY-Player-Resources/main/Sites/20220713.json",
"rootClassFilter": [
"电影",
"电影片",
"电视剧",
"连续剧",
"综艺",
"动漫"
],
"r18ClassFilter": [
"伦理",
"论理",
"倫理",
"福利",
"激情",
"理论",
"写真",
"情色",
"美女",
"街拍",
"赤足",
"性感",
"里番",
"VIP"
],
"classFilter": [
"电影",
"电影片",
"电视剧",
"连续剧",
"综艺",
"动漫",
"伦理",
"论理",
"倫理",
"福利",
"激情",
"理论",
"写真",
"情色",
"美女",
"街拍",
"赤足",
"性感",
"里番",
"VIP"
],
"restoreWindowPositionAndSize": false,
"windowPositionAndSize": {
"x": 0,
"y": 0,
"width": 1080,
"height": 720
},
"pauseWhenMinimize": false
}]

View File

@@ -0,0 +1,112 @@
[
{
"name": "playAndPause",
"desc": "播放或暂停",
"key": "space"
},
{
"name": "forward",
"desc": "快进",
"key": "right"
},
{
"name": "back",
"desc": "快退",
"key": "left"
},
{
"name": "volumeUp",
"desc": "音量调高",
"key": "up"
},
{
"name": "volumeDown",
"desc": "音量调低",
"key": "down"
},
{
"name": "mute",
"desc": "静音",
"key": "m"
},
{
"name": "top",
"desc": "置顶或退出置顶",
"key": "t"
},
{
"name": "fullscreen",
"desc": "进入或退出全屏",
"key": "f"
},
{
"name": "escape",
"desc": "退出全屏/精简模式",
"key": "esc"
},
{
"name": "next",
"desc": "下一集",
"key": "alt+right"
},
{
"name": "prev",
"desc": "上一集",
"key": "alt+left"
},
{
"name": "home",
"desc": "跳到视频开始位置",
"key": "home"
},
{
"name": "end",
"desc": "跳到视频结束位置",
"key": "end"
},
{
"name": "startPosition",
"desc": "标记片头",
"key": "ctrl+home"
},
{
"name": "endPosition",
"desc": "标记片尾",
"key": "ctrl+end"
},
{
"name": "clearPosition",
"desc": "清除标记",
"key": "ctrl+del"
},
{
"name": "opacityUp",
"desc": "透明度调高",
"key": "alt+up"
},
{
"name": "opacityDown",
"desc": "透明度调低",
"key": "alt+down"
},
{
"name": "playbackRateUp",
"desc": "播放倍速加快",
"key": "pageup"
},
{
"name": "playbackRateDown",
"desc": "播放倍速减慢",
"key": "pagedown"
},
{
"name": "mini",
"desc": "进入或退出mini模式",
"key": "alt+m"
},
{
"name": "resetMini",
"desc": "重置mini窗口",
"key": "ctrl+0"
}
]

View File

@@ -1,145 +1,3 @@
const setting = [
{
id: 0,
theme: 'light',
shortcut: true,
view: 'picture',
externalPlayer: '',
searchGroup: '全站',
excludeRootClasses: true,
excludeR18Films: true,
forwardTimeInSec: 5,
waitingTimeInSec: 15,
starViewMode: 'picture',
recommendationViewMode: 'picture',
historyViewMode: 'picture',
searchViewMode: 'picture',
password: '',
proxy: {
type: 'none',
scheme: '',
url: '',
port: ''
},
allowPassWhenIptvCheck: true,
autocleanWhenIptvCheck: false,
autoChangeSourceWhenIptvStalling: true
}
]
const localKey = [
{
name: 'playAndPause',
desc: '播放或暂停',
key: 'space'
},
{
name: 'forward',
desc: '快进',
key: 'right'
},
{
name: 'back',
desc: '快退',
key: 'left'
},
{
name: 'volumeUp',
desc: '音量调高',
key: 'up'
},
{
name: 'volumeDown',
desc: '音量调低',
key: 'down'
},
{
name: 'mute',
desc: '静音',
key: 'm'
},
{
name: 'top',
desc: '置顶或退出置顶',
key: 't'
},
{
name: 'fullscreen',
desc: '进入或退出全屏',
key: 'f'
},
{
name: 'escape',
desc: '退出全屏/精简模式',
key: 'esc'
},
{
name: 'next',
desc: '下一集',
key: 'alt+right'
},
{
name: 'prev',
desc: '上一集',
key: 'alt+left'
},
{
name: 'home',
desc: '跳到视频开始位置',
key: 'home'
},
{
name: 'end',
desc: '跳到视频结束位置',
key: 'end'
},
{
name: 'startPosition',
desc: '标记片头',
key: 'ctrl+home'
},
{
name: 'endPosition',
desc: '标记片尾',
key: 'ctrl+end'
},
{
name: 'clearPosition',
desc: '清除标记',
key: 'ctrl+del'
},
{
name: 'opacityUp',
desc: '透明度调高',
key: 'alt+up'
},
{
name: 'opacityDown',
desc: '透明度调低',
key: 'alt+down'
},
{
name: 'playbackRateUp',
desc: '播放倍速加快',
key: 'pageup'
},
{
name: 'playbackRateDown',
desc: '播放倍速减慢',
key: 'pagedown'
},
{
name: 'mini',
desc: '进入或退出mini模式',
key: 'alt+m'
},
{
name: 'resetMini',
desc: '重置mini窗口',
key: 'ctrl+0'
}
]
const getSite = (key) => {
for (const i of sites) {
if (key === i.key) {
@@ -151,11 +9,13 @@ const getSite = (key) => {
const sites = require('./iniData/Sites.json')
const iptv = require('./iniData/Iptv.json')
const recommendations = require('./iniData/Recommendations.json')
const iniSetting = require('./iniData/iniSetting.json')
const localKey = require('./iniData/localKey.json')
export {
setting,
sites,
iptv,
recommendations,
iniSetting,
localKey,
getSite
}

View File

@@ -5,6 +5,12 @@ export default {
async find () {
return await setting.get({ id: 0 })
},
async bulkAdd (doc) {
return await setting.bulkAdd(doc)
},
async add (doc) {
return await setting.add(doc)
},
async update (docs) {
return await setting.update(0, docs)
}

View File

@@ -1,6 +1,8 @@
import Vue from 'vue'
import { Message, Button, Table, TableColumn, Tag, Input, InputNumber, Dialog, Form, FormItem, Switch, Select, Option, Checkbox, Autocomplete, Col, Tree, Divider, Progress } from 'element-ui'
import { Message, Button, Table, TableColumn, Tag, Input, InputNumber, Dialog, Form, FormItem, Switch, Select, Option, Checkbox, Autocomplete, Col, Tree, Divider, Progress, MessageBox } from 'element-ui'
import Plugin from 'v-fit-columns'
import { ButtonGroupPlugin } from 'bootstrap-vue'
Vue.use(ButtonGroupPlugin)
Vue.use(Button)
Vue.use(Col)
Vue.use(Table)
@@ -21,3 +23,4 @@ Vue.use(Tree)
Vue.use(Divider)
Vue.use(Progress)
Vue.prototype.$message = Message
Vue.prototype.$msgbox = MessageBox

View File

@@ -35,29 +35,29 @@ const onlineVideo = {
},
playVideoOnBde4 (videoName, videoIndex) {
videoName = videoName.replace(/\s/g, '')
var url = `https://bde4.com/search/${videoName}`
const url = `https://bde4.com/search/${videoName}`
axios.get(url).then(res => {
const $ = cheerio.load(res.data)
var e = $('div.search-list')
var searchResult = $(e).find('div>div>div>div>a').toArray()
const e = $('div.search-list')
const searchResult = $(e).find('div>div>div>div>a').toArray()
// 获取第一个搜索结果的视频链接
var detailPageLink = $(searchResult[0]).attr('href')
const detailPageLink = $(searchResult[0]).attr('href')
// 获取第一个搜索结果的title
var title = $(searchResult[0]).attr('title')
const title = $(searchResult[0]).attr('title')
if (title === null || title === undefined || !title.replace(/\s/g, '').includes(videoName)) {
// 如果第一个搜索结果不符合,打开搜索页面
open(url)
} else {
var detailPageFullLink = 'https://bde4.com/' + detailPageLink
const detailPageFullLink = 'https://bde4.com/' + detailPageLink
// 解析详情页面
axios.get(detailPageFullLink).then(res => {
const $ = cheerio.load(res.data)
var e = $('div.info1')
var videoList = $(e).find('a').toArray()
var videoFullLink = detailPageFullLink
const d = $('div.info1')
const videoList = $(d).find('a').toArray()
let videoFullLink = detailPageFullLink
// 获取index视频链接
if (videoIndex < videoList.length) {
var indexVideoLink = $(videoList[videoIndex]).attr('href')
const indexVideoLink = $(videoList[videoIndex]).attr('href')
if (indexVideoLink.includes('.htm')) {
videoFullLink = 'https://bde4.com' + indexVideoLink
}
@@ -69,31 +69,31 @@ const onlineVideo = {
},
playVideoOnK1080 (videoName, videoIndex) {
videoName = videoName.replace(/\s/g, '')
var url = `https://k1080.net/vodsearch123/-------------.html?wd=${videoName}&submit=`
const url = `https://k1080.net/vodsearch123/-------------.html?wd=${videoName}&submit=`
axios.get(url).then(res => {
const $ = cheerio.load(res.data)
var e = $('#searchList')
var searchResult = $(e).find('li>div>a').toArray()
const e = $('#searchList')
const searchResult = $(e).find('li>div>a').toArray()
// 获取第一个搜索结果的视频链接
var detailPageLink = $(searchResult[0]).attr('href')
const detailPageLink = $(searchResult[0]).attr('href')
// 获取第一个搜索结果的title
var title = $(searchResult[0]).attr('title')
const title = $(searchResult[0]).attr('title')
if (title === null || title === undefined || !title.replace(/\s/g, '').includes(videoName)) {
// 如果第一个搜索结果不符合,打开搜索页面
open(url)
} else {
// 解析详情页面
var detailPageFullLink = 'https://k1080.net' + detailPageLink
const detailPageFullLink = 'https://k1080.net' + detailPageLink
axios.get(detailPageFullLink).then(res2 => {
const $ = cheerio.load(res2.data)
// 获取playlist1
var e = $('#playlist1')
const d = $('#playlist1')
// 获取所有视频链接
var videoList = $(e).find('div>ul>li>a').toArray()
var videoFullLink = detailPageFullLink
const videoList = $(d).find('div>ul>li>a').toArray()
let videoFullLink = detailPageFullLink
// 获取index视频链接
if (videoIndex < videoList.length) {
var indexVideoLink = $(videoList[videoIndex]).attr('href')
const indexVideoLink = $(videoList[videoIndex]).attr('href')
if (indexVideoLink.includes('.htm')) {
videoFullLink = 'https://k1080.net' + indexVideoLink
}
@@ -105,31 +105,31 @@ const onlineVideo = {
},
playVideoOnSubaibai (videoName, videoIndex) {
videoName = videoName.replace(/\s/g, '')
var url = `https://www.subaibai.com/xssearch?q=${videoName}`
const url = `https://www.subaibai.com/xssearch?q=${videoName}`
axios.get(url).then(res => {
const $ = cheerio.load(res.data)
var e = $('div.search_list')
var searchResult = $(e).find('div>ul>li>h3>a').toArray()
const e = $('div.search_list')
const searchResult = $(e).find('div>ul>li>h3>a').toArray()
// 获取第一个搜索结果的视频链接
var detailPageLink = $(searchResult[0]).attr('href')
const detailPageLink = $(searchResult[0]).attr('href')
// 获取第一个搜索结果的title
var title = $(searchResult[0]).text()
const title = $(searchResult[0]).text()
if (title === null || title === undefined || !title.replace(/\s/g, '').includes(videoName)) {
// 如果第一个搜索结果不符合,打开搜索页面
open(url)
} else {
// 解析详情页面
var detailPageFullLink = detailPageLink
const detailPageFullLink = detailPageLink
axios.get(detailPageFullLink).then(res2 => {
const $ = cheerio.load(res2.data)
// 获取playlist1
var e = $('div.paly_list_btn')
const d = $('div.paly_list_btn')
// 获取所有视频链接
var videoList = $(e).find('a').toArray()
const videoList = $(d).find('a').toArray()
// 获取index视频链接
var videoFullLink = detailPageFullLink
let videoFullLink = detailPageFullLink
if (videoIndex < videoList.length) {
var indexVideoLink = $(videoList[videoIndex]).attr('href')
const indexVideoLink = $(videoList[videoIndex]).attr('href')
if (indexVideoLink.includes('.htm')) {
videoFullLink = indexVideoLink
}
@@ -141,31 +141,31 @@ const onlineVideo = {
},
playVideoOnYhdm (videoName, videoIndex) {
videoName = videoName.replace(/\s/g, '')
var url = `http://www.yhdm.tv/search/${videoName}`
const url = `http://www.yhdm.tv/search/${videoName}`
axios.get(url).then(res => {
const $ = cheerio.load(res.data)
var e = $('div.lpic')
var searchResult = $(e).find('div>ul>li>h2>a').toArray()
const e = $('div.lpic')
const searchResult = $(e).find('div>ul>li>h2>a').toArray()
// 获取第一个搜索结果的视频链接
var detailPageLink = $(searchResult[0]).attr('href')
const detailPageLink = $(searchResult[0]).attr('href')
// 获取第一个搜索结果的title
var title = $(searchResult[0]).attr('title')
const title = $(searchResult[0]).attr('title')
if (title === null || title === undefined || !title.replace(/\s/g, '').includes(videoName)) {
// 如果第一个搜索结果不符合,打开搜索页面
open(url)
} else {
// 解析详情页面
var detailPageFullLink = 'http://www.yhdm.tv/' + detailPageLink
const detailPageFullLink = 'http://www.yhdm.tv/' + detailPageLink
axios.get(detailPageFullLink).then(res2 => {
const $ = cheerio.load(res2.data)
// 获取playlist1
var e = $('div.movurl')
const d = $('div.movurl')
// 获取所有视频链接
var videoList = $(e).find('div>ul>li>a').toArray()
const videoList = $(d).find('div>ul>li>a').toArray()
// 获取index视频链接
var videoFullLink = detailPageFullLink
let videoFullLink = detailPageFullLink
if (videoIndex < videoList.length) {
var indexVideoLink = $(videoList[videoIndex]).attr('href')
const indexVideoLink = $(videoList[videoIndex]).attr('href')
if (indexVideoLink.includes('.htm')) {
videoFullLink = 'http://www.yhdm.tv/' + indexVideoLink
}
@@ -177,31 +177,31 @@ const onlineVideo = {
},
playVideoOndmdm2020 (videoName, videoIndex) {
videoName = videoName.replace(/\s/g, '')
var url = `http://www.dmdm2020.com/dongmansearch.html?wd=${videoName}&submit=`
const url = `http://www.dmdm2020.com/dongmansearch.html?wd=${videoName}&submit=`
axios.get(url).then(res => {
const $ = cheerio.load(res.data)
var e = $('#searchList')
var searchResult = $(e).find('ul>li>div>h4>a').toArray()
const e = $('#searchList')
const searchResult = $(e).find('ul>li>div>h4>a').toArray()
// 获取第一个搜索结果的视频链接
var detailPageLink = $(searchResult[0]).attr('href')
const detailPageLink = $(searchResult[0]).attr('href')
// 获取第一个搜索结果的title
var title = $(searchResult[0]).text()
const title = $(searchResult[0]).text()
if (title === null || title === undefined || !title.replace(/\s/g, '').includes(videoName)) {
// 如果第一个搜索结果不符合,打开搜索页面
open(url)
} else {
// 解析详情页面
var detailPageFullLink = 'http://www.dmdm2020.com' + detailPageLink
const detailPageFullLink = 'http://www.dmdm2020.com' + detailPageLink
axios.get(detailPageFullLink).then(res2 => {
const $ = cheerio.load(res2.data)
// 获取playlist1
var e = $('#playlist1')
const d = $('#playlist1')
// 获取所有视频链接
var videoList = $(e).find('div>ul>li>a').toArray()
const videoList = $(d).find('div>ul>li>a').toArray()
// 获取index视频链接
var videoFullLink = detailPageFullLink
let videoFullLink = detailPageFullLink
if (videoIndex < videoList.length) {
var indexVideoLink = $(videoList[videoIndex]).attr('href')
const indexVideoLink = $(videoList[videoIndex]).attr('href')
if (indexVideoLink.includes('.htm')) {
videoFullLink = 'http://www.dmdm2020.com' + indexVideoLink
}
@@ -213,31 +213,31 @@ const onlineVideo = {
},
playVideoOnSyrme (videoName, videoIndex) {
videoName = videoName.replace(/\s/g, '')
var url = `https://syrme.top/searchs?q=${videoName}`
const url = `https://syrme.top/searchs?q=${videoName}`
axios.get(url).then(res => {
const $ = cheerio.load(res.data)
var e = $('ul.MovieList')
var searchResult = $(e).find('ul>li>article>a').toArray()
const e = $('ul.MovieList')
const searchResult = $(e).find('ul>li>article>a').toArray()
// 获取第一个搜索结果的视频链接
var detailPageLink = $(searchResult[0]).attr('href')
const detailPageLink = $(searchResult[0]).attr('href')
// 获取第一个搜索结果的title
var title = $(searchResult[0]).find('a>h2').text()
const title = $(searchResult[0]).find('a>h2').text()
if (title === null || title === undefined || !title.replace(/\s/g, '').includes(videoName)) {
// 如果第一个搜索结果不符合,打开搜索页面
open(url)
} else {
// 解析详情页面
var detailPageFullLink = 'https://syrme.top' + detailPageLink
const detailPageFullLink = 'https://syrme.top' + detailPageLink
axios.get(detailPageFullLink).then(res2 => {
const $ = cheerio.load(res2.data)
// 获取playlist1
var e = $('#categories-2')
const d = $('#categories-2')
// 获取所有视频链接
var videoList = $(e).find('div>ul>li>a').toArray()
const videoList = $(d).find('div>ul>li>a').toArray()
// 获取index视频链接
var videoFullLink = detailPageFullLink
let videoFullLink = detailPageFullLink
if (videoIndex < videoList.length) {
var indexVideoLink = $(videoList[videoIndex]).attr('href')
const indexVideoLink = $(videoList[videoIndex]).attr('href')
videoFullLink = 'https://syrme.top' + indexVideoLink
}
open(videoFullLink)
@@ -247,31 +247,31 @@ const onlineVideo = {
},
playVideoOnJpysvip (videoName, videoIndex) {
videoName = videoName.replace(/\s/g, '')
var url = `https://www.jpysvip.net/vodsearch/-------------.html?wd=${videoName}&submit=`
const url = `https://www.jpysvip.net/vodsearch/-------------.html?wd=${videoName}&submit=`
axios.get(url).then(res => {
const $ = cheerio.load(res.data)
var e = $('#searchList')
var searchResult = $(e).find('ul>li>div>a').toArray()
const e = $('#searchList')
const searchResult = $(e).find('ul>li>div>a').toArray()
// 获取第一个搜索结果的视频链接
var detailPageLink = $(searchResult[0]).attr('href')
const detailPageLink = $(searchResult[0]).attr('href')
// 获取第一个搜索结果的title
var title = $(searchResult[0]).attr('title')
const title = $(searchResult[0]).attr('title')
if (title === null || title === undefined || !title.replace(/\s/g, '').includes(videoName)) {
// 如果第一个搜索结果不符合,打开搜索页面
open(url)
} else {
// 解析详情页面
var detailPageFullLink = 'https://www.jpysvip.net' + detailPageLink
const detailPageFullLink = 'https://www.jpysvip.net' + detailPageLink
axios.get(detailPageFullLink).then(res2 => {
const $ = cheerio.load(res2.data)
// 获取playlist1
var e = $('#playlist1')
const d = $('#playlist1')
// 获取所有视频链接
var videoList = $(e).find('div>ul>li>a').toArray()
const videoList = $(d).find('div>ul>li>a').toArray()
// 获取index视频链接
var videoFullLink = detailPageFullLink
let videoFullLink = detailPageFullLink
if (videoIndex < videoList.length) {
var indexVideoLink = $(videoList[videoIndex]).attr('href')
const indexVideoLink = $(videoList[videoIndex]).attr('href')
videoFullLink = 'https://www.jpysvip.net/' + indexVideoLink
}
open(videoFullLink)
@@ -281,31 +281,31 @@ const onlineVideo = {
},
playVideoOnXhkan (videoName, videoIndex) {
videoName = videoName.replace(/\s/g, '')
var url = `https://www.xhkan.com/vodsearch.html?wd=${videoName}&submit=`
const url = `https://www.xhkan.com/vodsearch.html?wd=${videoName}&submit=`
axios.get(url).then(res => {
const $ = cheerio.load(res.data)
var e = $('#searchList')
var searchResult = $(e).find('ul>li>div>a').toArray()
const e = $('#searchList')
const searchResult = $(e).find('ul>li>div>a').toArray()
// 获取第一个搜索结果的视频链接
var detailPageLink = $(searchResult[0]).attr('href')
const detailPageLink = $(searchResult[0]).attr('href')
// 获取第一个搜索结果的title
var title = $(searchResult[0]).attr('title')
const title = $(searchResult[0]).attr('title')
if (title === null || title === undefined || !title.replace(/\s/g, '').includes(videoName)) {
// 如果第一个搜索结果不符合,打开搜索页面
open(url)
} else {
// 解析详情页面
var detailPageFullLink = detailPageLink
const detailPageFullLink = detailPageLink
axios.get(detailPageFullLink).then(res2 => {
const $ = cheerio.load(res2.data)
// 获取playlist1
var e = $('#playlist1')
const d = $('#playlist1')
// 获取所有视频链接
var videoList = $(e).find('div>ul>li>a').toArray()
const videoList = $(d).find('div>ul>li>a').toArray()
// 获取index视频链接
var videoFullLink = detailPageFullLink
let videoFullLink = detailPageFullLink
if (videoIndex < videoList.length) {
var indexVideoLink = $(videoList[videoIndex]).attr('href')
const indexVideoLink = $(videoList[videoIndex]).attr('href')
videoFullLink = indexVideoLink
}
open(videoFullLink)

View File

@@ -11,7 +11,7 @@ import SocksProxyAgent from 'socks-proxy-agent'
// 要在设置中添加代理设置可参考https://stackoverflow.com/questions/37393248/how-connect-to-proxy-in-electron-webview
const http = require('http')
const https = require('http')
const { remote } = require('electron')
const remote = require('@electron/remote')
const win = remote.getCurrentWindow()
const session = win.webContents.session
const ElectronProxyAgent = require('electron-proxy-agent')
@@ -111,13 +111,16 @@ const zy = {
axios.get(url).then(res => {
const data = res.data
const json = parser.parse(data, this.xmlConfig)
const jsondata = json.rss === undefined ? json : json.rss
const jsondata = json?.rss === undefined ? json : json.rss
if (!jsondata?.class || !jsondata?.list) resolve()
const arr = []
if (jsondata.class) {
// 有些网站返回的分类名里会含有一串包含在{}内的字符串,移除掉
const regex = /\{.*\}/i
for (const i of jsondata.class.ty) {
const j = {
tid: i._id,
name: i._t
name: i._t.replace(regex, '')
}
arr.push(j)
}
@@ -216,16 +219,55 @@ const zy = {
axios.get(url, { timeout: 3000 }).then(res => {
const data = res.data
const json = parser.parse(data, this.xmlConfig)
const jsondata = json.rss === undefined ? json : json.rss
const jsondata = json?.rss === undefined ? json : json.rss
if (json && jsondata && jsondata.list) {
let videoList = jsondata.list.video
if (Object.prototype.toString.call(videoList) === '[object Object]') videoList = [].concat(videoList)
videoList = videoList.filter(e => e.name.toLowerCase().includes(wd.toLowerCase()))
if (videoList.length) {
videoList = videoList?.filter(e => e.name.toLowerCase().includes(wd.toLowerCase()))
if (videoList?.length) {
resolve(videoList)
} else {
resolve()
}
} else {
resolve()
}
}).catch(err => {
reject(err)
})
}).catch(err => {
reject(err)
})
})
},
/**
* 搜索资源详情
* @param {*} key 资源网 key
* @param {*} wd 搜索关键字
* @returns
*/
searchFirstDetail (key, wd) {
return new Promise((resolve, reject) => {
this.getSite(key).then(res => {
const site = res
const url = `${site.api}?wd=${encodeURI(wd)}`
axios.get(url, { timeout: 3000 }).then(res => {
const data = res.data
const json = parser.parse(data, this.xmlConfig)
const jsondata = json?.rss === undefined ? json : json.rss
if (json && jsondata && jsondata.list) {
let videoList = jsondata.list.video
if (Object.prototype.toString.call(videoList) === '[object Object]') videoList = [].concat(videoList)
videoList = videoList?.filter(e => e.name.toLowerCase().includes(wd.toLowerCase()))
if (videoList?.length) {
this.detail(key, videoList[0].id).then(detailRes => {
resolve(detailRes)
})
} else {
resolve()
}
} else {
resolve()
}
}).catch(err => {
reject(err)
@@ -248,8 +290,9 @@ const zy = {
axios.get(url).then(res => {
const data = res.data
const json = parser.parse(data, this.xmlConfig)
const jsondata = json.rss === undefined ? json : json.rss
const videoList = jsondata.list.video
const jsondata = json?.rss === undefined ? json : json.rss
const videoList = jsondata?.list?.video
if (!videoList) resolve()
// Parse video lists
let fullList = []
let index = 0
@@ -491,12 +534,39 @@ const zy = {
})
})
},
get7kParseURL () {
/**
* 获取豆瓣相关视频推荐列表
* @param {*} name 视频名称
* @param {*} year 视频年份
* @returns 豆瓣相关视频推荐列表
*/
doubanRecommendations (name, year) {
return new Promise((resolve, reject) => {
axios.get('https://zy.7kjx.com/').then(res => {
const $ = cheerio.load(res.data)
const parseURL = $('body > div.container > div > div.stui-pannel > div.col-pd > p:contains("解析接口:")').first().find('a').text()
resolve(parseURL)
const nameToSearch = name.replace(/\s/g, '')
const recommendations = []
this.doubanLink(nameToSearch, year).then(link => {
if (link.includes('https://www.douban.com/search')) {
resolve(recommendations)
} else {
axios.get(link).then(response => {
const $ = cheerio.load(response.data)
$('div.recommendations-bd').find('div>dl>dd>a').each(function (index, element) {
recommendations.push($(element).text())
})
resolve(recommendations)
}).catch(err => {
reject(err)
})
}
}).catch(err => {
reject(err)
})
})
},
getDefaultSites (url) {
return new Promise((resolve, reject) => {
axios.get(url).then(res => {
resolve(res.data)
}).catch(err => { reject(err) })
})
},

10045
yarn.lock

File diff suppressed because it is too large Load Diff