Compare commits

...

240 Commits

Author SHA1 Message Date
hunlongyu
26bcdd4101 🗃 修复download为空时下载出错 2020-11-14 12:46:44 +08:00
buvta
5104f9a85d v2.6.4.1 2020-11-14 11:47:36 +08:00
hunlongyu
d61ee76e58 Merge branch 'master' of https://github.com/Hunlongyu/ZY-Player 2020-11-13 21:33:13 +08:00
hunlongyu
b1a683a8db 🗑 修复 developer 报错 2020-11-13 21:33:07 +08:00
buvta
5d0dc1bed7 补上落下的async 2020-11-13 21:26:03 +08:00
buvta
3481a5346e 取消时等待数据库更新再刷新代理 2020-11-13 21:05:49 +08:00
buvta
c957fe33e2 取消时更新代理 2020-11-13 21:00:57 +08:00
buvta
51aa21e551 稍微调整 2020-11-13 20:55:11 +08:00
buvta
a887968458 设置增加代理,功能实现 2020-11-13 20:36:33 +08:00
Hunlongyu
380d31c0d3 🌿 新增代理设置界面 ( 功能未完成 ) 2020-11-13 16:28:11 +08:00
Hunlongyu
46b5f82348 Merge branch 'master' of https://github.com/Hunlongyu/ZY-Player into master 2020-11-13 13:52:45 +08:00
Hunlongyu
675622e9ee npm yarn 2020-11-13 13:52:36 +08:00
haiyangcui
9a67821984 移除无用log 2020-11-12 23:35:21 +01:00
haiyangcui
e457574755 开启airplay选项 2020-11-12 22:58:45 +01:00
haiyangcui
50f5154628 Merge branch 'master' of https://github.com/Hunlongyu/ZY-Player 2020-11-12 17:35:43 +01:00
haiyangcui
9da7ffc451 Revert "移除"搜索所有资源"开关,搜索变总是搜索所有资源", 解决推荐排序不工作的问题 2020-11-12 17:35:31 +01:00
buvta
35adae51cc 调整"正在直播"样式 2020-11-12 23:52:47 +08:00
haiyangcui
fe75edd738 v2.6.4 2020-11-12 10:51:29 +01:00
haiyangcui
362dccb167 固定"备注"宽度,"最近更新"列宽度自适应 2020-11-12 10:45:54 +01:00
buvta
08e95611ea 修复频道当前源被包含的bug 2020-11-12 12:09:58 +08:00
buvta
739b3fe30f 调整iptvList加载时机,清除残余代码 2020-11-12 11:37:50 +08:00
buvta
3ba2dc9993 表格列样式调整 2020-11-12 11:26:18 +08:00
buvta
6543d8baf0 推荐页相应调整 2020-11-12 08:34:40 +08:00
buvta
a1c9c657e3 film搜索框样式优化终结版,弹框样式统一为popper 2020-11-12 08:27:19 +08:00
haiyangcui
9306adb60e '全部'改名为'全站' 2020-11-11 21:42:40 +01:00
haiyangcui
682c706618 Revert "film页面el-table引入电影追剧模式" 2020-11-11 21:40:51 +01:00
haiyangcui
02c04c3d46 再次改进搜索框的样式 2020-11-11 17:09:17 +01:00
haiyangcui
17c78522bb 播放页面出现的列表页面,都实现v-on-clickaway 2020-11-11 16:30:22 +01:00
hunlongyu
7af6c73084 ⏱ 修改下拉菜单三角箭头的样式 2020-11-11 22:46:26 +08:00
hunlongyu
d31e0daca9 Merge branch 'master' of https://github.com/Hunlongyu/ZY-Player 2020-11-11 21:41:46 +08:00
hunlongyu
9a7534ba57 ⏲ 移除 child_process 依赖, 使用 node 自带模块 2020-11-11 21:41:39 +08:00
buvta
a73e679b72 Revert "改进搜索框的样式"
This reverts commit b72886fbe6.
2020-11-11 21:36:31 +08:00
buvta
4f6c248345 Revert "引入需要的bootstrap-vue依赖"
This reverts commit 59a89e280b.
2020-11-11 21:36:28 +08:00
hunlongyu
68a0226759 🕰 修改 Film 表格模式样式 2020-11-11 21:26:55 +08:00
haiyangcui
e72af95c75 更新源列表,把检测后不可用的放到最下部 2020-11-11 12:54:04 +01:00
buvta
559e85785f film页面el-table引入电影追剧模式 2020-11-11 13:04:55 +08:00
Hunlongyu
2bf69fb0b9 修复 Play 组件无法弹出侧边栏的BUG 2020-11-11 11:10:48 +08:00
buvta
c082986e09 精简模式引入mode 2020-11-11 08:29:56 +08:00
buvta
05d71a62aa 搜索结果过滤器重置时只给选定列添加 2020-11-11 08:29:12 +08:00
buvta
bb537d789d 解决菜单更新bug 2020-11-11 07:11:30 +08:00
buvta
11baacc778 直播支持精简模式 2020-11-11 07:11:30 +08:00
buvta
9dbc0e00dc 支持频道换源 2020-11-11 07:11:30 +08:00
buvta
23e5c569b1 调整Play直播时播放器下方菜单,支持使用第三方播放器 2020-11-11 07:11:30 +08:00
haiyangcui
59a89e280b 引入需要的bootstrap-vue依赖 2020-11-10 20:39:33 +01:00
haiyangcui
b72886fbe6 改进搜索框的样式 2020-11-10 20:16:06 +01:00
haiyangcui
75bac6582c 简化el-select样式定义 2020-11-10 15:20:48 +01:00
Hunlongyu
7cc7e4e0e6 移除赞助, 移除多余排序文字 2020-11-10 17:15:30 +08:00
buvta
b1707f88d6 Merge pull request #345 from Hunlongyu/buvta
分组搜索
2020-11-10 16:56:39 +08:00
buvta
9ca946eb66 搜索默认设置调整为全部 2020-11-10 15:48:14 +08:00
buvta
76ed091c78 取消IPTV检测时的播放限制 2020-11-10 14:34:14 +08:00
buvta
5965c55773 搜索结果过滤器遵守限制 2020-11-10 14:33:04 +08:00
buvta
6631b8f568 避免后台还在运行的搜索被添加到新搜索中 2020-11-10 13:30:18 +08:00
buvta
b7bb5f85a3 搜索结果不能同时用多个过滤器 2020-11-10 13:03:48 +08:00
buvta
c8795e2aa9 优化分组搜索 2020-11-10 12:21:32 +08:00
buvta
2d7f012180 加搜索按钮 2020-11-10 12:21:32 +08:00
buvta
95ae729df8 Play页面换源由“所有”替换为同组资源站 2020-11-10 12:21:32 +08:00
buvta
40218521ac Film重构搜索以支持分组搜索 2020-11-10 12:21:28 +08:00
buvta
f4396cb69f 调整搜索配置 2020-11-10 12:15:30 +08:00
buvta
2dfbc8a8a2 调整搜索框样式 2020-11-10 12:12:58 +08:00
buvta
f94e8f0bec 改写Film.vue搜索框,预备支持分组搜索 2020-11-10 12:12:55 +08:00
haiyangcui
a9011abdf0 加入Waterfall元素的null check 2020-11-09 18:31:19 +01:00
haiyangcui
843a8dd1fc 移除"搜索所有资源"开关,搜索变总是搜索所有资源 2020-11-09 18:26:07 +01:00
haiyangcui
9b5aae095e Revert "搜索结果加过滤器", 搜索后默认按源站排序 2020-11-09 14:59:49 +01:00
buvta
24e890d1ab 统一操作列风格 2020-11-09 08:19:40 +08:00
buvta
959f515f55 iptv初始化数据加isActive 2020-11-09 08:06:16 +08:00
haiyangcui
f97d63cf68 更新animationEffect为fadein 2020-11-08 22:27:57 +01:00
buvta
c2f3a60198 搜索结果加过滤器 2020-11-09 00:17:08 +08:00
haiyangcui
9128f407ce 获取豆瓣评分时,移除空格 2020-11-08 12:31:00 +01:00
haiyangcui
c5c6e5e34f 修复推荐数据 2020-11-08 12:29:15 +01:00
haiyangcui
b12cdf25d5 改进排序 2020-11-08 12:28:12 +01:00
haiyangcui
7c08627e6f 支持搜索结果排序 2020-11-08 12:18:42 +01:00
haiyangcui
68c3687da3 getSites时无需再设置isActive 2020-11-08 11:35:58 +01:00
haiyangcui
00d6f2d218 更新默认源站数据 2020-11-08 11:33:23 +01:00
buvta
a918713bf7 Merge pull request #343 from Hunlongyu/buvta
增加代理及直播源检测功能
2020-11-08 18:03:52 +08:00
buvta
ae7aaec623 统一editSites状态开关数据类型为Boolean 2020-11-08 18:02:08 +08:00
buvta
81476e0f20 Merge remote-tracking branch 'co/master' 2020-11-08 17:56:48 +08:00
haiyangcui
4136b0f3ce 代理功能,作者:buvta 2020-11-08 00:13:08 +01:00
haiyangcui
c3a4cf5cc5 IPTV检测功能,作者:buvta 2020-11-07 23:55:44 +01:00
haiyangcui
d2263f3f76 添加推荐 2020-11-07 23:18:04 +01:00
haiyangcui
71df73fbd3 推荐页面排序功能 2020-11-07 23:16:00 +01:00
haiyangcui
ba6f3df9b1 升级依赖 2020-11-07 19:56:38 +01:00
haiyangcui
35c205fd86 刷新历史页面瀑布流,改进自适应 2020-11-07 19:29:40 +01:00
haiyangcui
30796af5f8 收藏页面,海报添加观看进度信息 2020-11-07 19:25:49 +01:00
haiyangcui
fde5dbb89d 改进历史视图 2020-11-07 19:14:06 +01:00
buvta
df3b43d8ac 进一步完善shift多选 2020-11-08 01:07:09 +08:00
buvta
8f94a5604d 批处理多选时支持shift快捷键 2020-11-08 00:35:05 +08:00
buvta
c6a39591d5 批量检测时增加进度提示 2020-11-08 00:28:07 +08:00
buvta
051d6b7701 修复导入直播源时的错误 2020-11-08 00:28:02 +08:00
buvta
51ba1d87ad 批量检测时继续限制删除功能 2020-11-08 00:26:45 +08:00
buvta
9af55df310 支持导入同名频道 2020-11-07 21:39:10 +08:00
buvta
d82251fb02 批量删除时重置ID及过滤器 2020-11-07 21:39:10 +08:00
buvta
4d192a4c3a 调整源状态开关列 2020-11-07 21:39:10 +08:00
buvta
1f25219cdc 批量检测时未检查过的优先 2020-11-07 21:39:10 +08:00
buvta
25d65866ae 改动syncTableData以便删除可用 2020-11-07 21:39:10 +08:00
buvta
11559ca164 资源站及直播源编辑页面"清空"替换为批量删除 2020-11-07 21:39:10 +08:00
buvta
6c82178604 完善直播源批量检测时的功能限制 2020-11-07 21:39:10 +08:00
buvta
029d1d9b49 完善源批量检测的功能限制 2020-11-07 21:39:10 +08:00
buvta
c10f7b98d9 去除多余的editSites属性 2020-11-07 21:39:10 +08:00
buvta
48d4b369a8 修正直播源检测出错时返回结果 2020-11-07 21:39:10 +08:00
buvta
42d2b5c20f 添加直播源检测功能 2020-11-07 21:39:09 +08:00
buvta
ccbafaae39 增加代理功能,默认使用系统代理设置 2020-11-07 21:39:09 +08:00
haiyangcui
fb3b908fe8 继续播放时,隐藏进度条,无需检查是否全屏 2020-11-07 21:39:09 +08:00
haiyangcui
4c4cc6d81b 当全屏暂停再继续播放时,隐藏进度条 2020-11-07 21:39:09 +08:00
haiyangcui
9ccfefaafb 历史页面,改进进度展示 2020-11-07 21:39:09 +08:00
haiyangcui
15a38f1b9c 支持历史视图模式 2020-11-07 21:39:09 +08:00
haiyangcui
967657e0ac 修正拼写 2020-11-07 21:39:09 +08:00
Hunlongyu
cd08e9e14b 🥀 新增任务栏显示播放进度 2020-11-07 21:39:09 +08:00
Hunlongyu
7e5bd534ef 🌿 修改样式 2020-11-07 21:39:09 +08:00
Hunlongyu
dce2e36ef0 🍀 修复瀑布流不自动自适应 2020-11-07 21:39:09 +08:00
haiyangcui
8a72b30f79 切换源的时候无需隐藏再显示类型列表 2020-11-07 21:39:09 +08:00
haiyangcui
bbe0d157f4 改进代码 2020-11-07 21:39:09 +08:00
haiyangcui
f44f8ea6cf 统一样式,el-select选择或划过的背景色也用背景色之一 2020-11-07 21:39:09 +08:00
haiyangcui
cd6f9f1f53 删除zy-checkbox的css样式定义 2020-11-07 21:39:09 +08:00
haiyangcui
74d084cb7b zy-table已经被el-table取代,删除无用的样式 2020-11-07 21:39:09 +08:00
haiyangcui
e60962a0f5 删除无用的console输出 2020-11-07 21:39:09 +08:00
haiyangcui
459a54382f el-select实现源站列表和分类列表 2020-11-07 21:39:09 +08:00
haiyangcui
e08a90d87a 修正Recommendation的拼写 2020-11-07 21:39:09 +08:00
haiyangcui
c676159cc7 继续播放时,隐藏进度条,无需检查是否全屏 2020-11-07 12:39:12 +01:00
haiyangcui
0fc8e54d26 当全屏暂停再继续播放时,隐藏进度条 2020-11-07 12:35:35 +01:00
haiyangcui
fe858a0cd9 历史页面,改进进度展示 2020-11-07 12:29:34 +01:00
haiyangcui
2238ddd109 支持历史视图模式 2020-11-07 11:29:03 +01:00
Hunlongyu
cc1c100075 Merge branch 'master' of https://github.com/Hunlongyu/ZY-Player into master 2020-11-06 17:38:48 +08:00
Hunlongyu
81ba6de6cb 🥀 新增任务栏显示播放进度 2020-11-06 17:38:42 +08:00
haiyangcui
28baca56c4 修正拼写 2020-11-06 10:29:50 +01:00
Hunlongyu
3493831729 🌿 修改样式 2020-11-06 10:09:25 +08:00
Hunlongyu
42fce7d137 🍀 修复瀑布流不自动自适应 2020-11-06 10:02:01 +08:00
haiyangcui
c7a4b389e1 切换源的时候无需隐藏再显示类型列表 2020-11-05 23:47:57 +01:00
haiyangcui
5f47789a1a 改进代码 2020-11-05 22:57:29 +01:00
haiyangcui
7591c30b59 统一样式,el-select选择或划过的背景色也用背景色之一 2020-11-05 22:40:53 +01:00
haiyangcui
dd43c18491 删除zy-checkbox的css样式定义 2020-11-05 22:23:07 +01:00
haiyangcui
6949eb16d6 zy-table已经被el-table取代,删除无用的样式 2020-11-05 22:20:53 +01:00
haiyangcui
4a369a755e 删除无用的console输出 2020-11-05 22:15:05 +01:00
haiyangcui
e1b1742424 el-select实现源站列表和分类列表 2020-11-05 22:14:42 +01:00
haiyangcui
de31c4c0bb 修正Recommendation的拼写 2020-11-05 21:28:21 +01:00
cuiocean
c85910edd0 Merge pull request #342 from buvta/forPR
部分功能优化
2020-11-05 21:06:51 +01:00
buvta
b8d78bab10 改动film源站列表加载方式 2020-11-06 00:45:46 +08:00
buvta
9eed5ce0b7 源检测并发执行 2020-11-05 22:08:49 +08:00
buvta
4b11cab4bf axios增加配置 2020-11-05 22:07:38 +08:00
buvta
6ffbc2a63c 优化Film加载提示 2020-11-05 21:19:14 +08:00
haiyangcui
c6f4917cdc 改进瀑布流的样式及鼠标划过的效果 2020-11-05 12:44:30 +01:00
haiyangcui
fe37b32a0f 鼠标移动到卡片上时,添加上移动画效果 2020-11-05 12:38:38 +01:00
Hunlongyu
7fb295d34c 升级依赖 2020-11-05 18:03:31 +08:00
haiyangcui
e8c5c0ec72 改进瀑布流设置,更好的适应宽度 2020-11-04 14:52:47 +01:00
haiyangcui
64dc9c98d2 v2.6.3 2020-11-04 12:13:05 +01:00
haiyangcui
ca36841f5d 打开换源页面时,记录当前时间,换源时使用该时间。否则,如果换源失败,this.xg.currentTime 会被重置为0 2020-11-04 12:11:49 +01:00
haiyangcui
59d33d201c 如果时间进度已经设定,无需读取历史数据 2020-11-04 09:43:20 +01:00
haiyangcui
bf3b6d4088 再次解决换源时间进度问题 2020-11-04 09:06:48 +01:00
haiyangcui
bf2567bfde 修复推荐里豆瓣评分2 2020-11-03 22:56:55 +01:00
haiyangcui
3499fb5937 修复推荐里错误的评分 2020-11-03 22:49:13 +01:00
haiyangcui
dec12c77d0 添加两个新源,牛牛和百度云 2020-11-03 22:11:58 +01:00
haiyangcui
17be5d45f1 v2.6.2 2020-11-03 17:16:51 +01:00
haiyangcui
f493fcd24e 屏蔽福利片checkbox可以直接关联setting.excludeR18Films 2020-11-03 17:06:05 +01:00
haiyangcui
d040bc01fc 更新收藏导出时的提示 2020-11-03 16:45:38 +01:00
haiyangcui
6644c97811 导入收藏时,deep copy当前的list,否则列表会在没有排序好之前就被展示 2020-11-03 16:39:00 +01:00
haiyangcui
68960ab5bb 改进star的导入导出时的排序问题 2020-11-03 16:34:12 +01:00
haiyangcui
46de044214 统一海报视图 2020-11-03 15:46:48 +01:00
haiyangcui
0cbf9ca7fb 改进推荐页面排序问题 2020-11-03 15:41:15 +01:00
haiyangcui
6fa40af9bd 更新推荐 2020-11-03 15:23:38 +01:00
haiyangcui
7343f1824a 集中豆瓣评分和豆瓣链接获取功能到tools中 2020-11-03 14:57:07 +01:00
haiyangcui
3df0665950 改进过滤关键词 2020-11-03 14:13:26 +01:00
haiyangcui
022b1b28ad 改进Film页面刷新的逻辑,避免不必要的刷新 2020-11-03 13:56:41 +01:00
haiyangcui
55d1740354 移动"屏蔽福利片"到源编辑页面 2020-11-03 12:58:34 +01:00
haiyangcui
9d71991103 如果开启屏蔽福利片选项,也过滤搜索结果 2020-11-02 22:08:38 +01:00
haiyangcui
361e24ecad 引入vue-clickaway 2020-11-02 21:28:29 +01:00
haiyangcui
53f80d2cce 点击换源后,不需要关闭换源窗口.用户可以等待新源确定工作后自行关闭 2020-11-02 21:09:53 +01:00
haiyangcui
880dd9ff35 重新解决换源时间进度问题,发现记录this.video.info.time的话,视频会卡一下 2020-11-02 18:03:47 +01:00
haiyangcui
42c89120da 如果没有任何收藏有更新时,发消息提醒用户'未查询到任何更新' 2020-11-02 17:54:43 +01:00
haiyangcui
d990aa92b0 记录当前播放时间this.video.info.time, 解决换源时时间进度定位问题 2020-11-02 16:23:05 +01:00
haiyangcui
e117564ecb 在style.css里统一定义el-select的样式 2020-11-02 12:11:45 +01:00
haiyangcui
99592e3fcb 改进el-select样式,设置不同主题下的背景色等 2020-11-02 11:21:33 +01:00
Hunlongyu
adc8fd4329 🍁 修复因为分类异常, 导致资源加载不出来. 2020-11-02 13:44:10 +08:00
haiyangcui
579caddaeb 更新推荐 2020-11-01 23:29:49 +01:00
haiyangcui
1d5344f292 更新推荐 2020-11-01 23:19:32 +01:00
haiyangcui
22dc74ea3a 更新推荐 2020-11-01 23:15:39 +01:00
haiyangcui
72d7c91540 更新推荐 2020-11-01 22:38:46 +01:00
haiyangcui
ef874d1831 v2.6.1 2020-11-01 18:36:08 +01:00
haiyangcui
bb9a8ca65d 获取其他源时,排除当前源 2020-11-01 18:03:33 +01:00
haiyangcui
747abf3b26 设置密码对话框的宽度 2020-11-01 17:41:20 +01:00
haiyangcui
1078cf3c63 修复自动更新功能 2020-11-01 17:29:57 +01:00
haiyangcui
22b877b0fb 定义不同的waterfall的ref 2020-11-01 17:24:29 +01:00
haiyangcui
34e6b8bd08 更新推荐 2020-11-01 14:02:11 +01:00
haiyangcui
4d039e9a63 更新推荐后刷新分类过滤数据 2020-11-01 14:01:48 +01:00
haiyangcui
16f3954959 删除无用的style 2020-11-01 12:17:20 +01:00
haiyangcui
17845e6ab4 改进换源功能,在新源中打开当前剧集和时间进度 2020-11-01 12:07:54 +01:00
hunlongyu
292f932130 Merge branch 'master' of https://github.com/Hunlongyu/ZY-Player 2020-11-01 15:29:24 +08:00
hunlongyu
127ef9ad43 ⛸ 设置界面样式微调 2020-11-01 15:26:31 +08:00
cuiocean
11f0ae27fd v2.6.0 2020-11-01 08:22:24 +01:00
hunlongyu
2599343943 样式优化, 修复film table 错误提示 2020-11-01 14:57:49 +08:00
haiyangcui
0fb5903416 v2.5.9 2020-10-31 22:56:40 +01:00
haiyangcui
ce89720c55 调换收藏页面'源站'列的位置 2020-10-31 22:51:37 +01:00
haiyangcui
8ff7fa588a 恢复el-table滚动条 2020-10-31 22:45:19 +01:00
haiyangcui
8d5bbedfd8 解决el-table刷新自动跳到顶端的问题 2020-10-31 22:40:52 +01:00
haiyangcui
713e0affae 更新推荐 2020-10-31 22:31:25 +01:00
haiyangcui
0f55f3b2ea 显示推荐视频总数 2020-10-31 22:12:58 +01:00
haiyangcui
c98e41201d 不显示导演信息,有时导演名字字符太多 2020-10-31 22:12:45 +01:00
haiyangcui
2cfd31806d 修复搜索后打开详情页错误的问题 2020-10-31 22:06:33 +01:00
haiyangcui
d54dab4e90 改进豆瓣评分样式 2020-10-31 22:04:25 +01:00
haiyangcui
2af85fbfd1 Film页面,列表视图用el-table实现,感谢buvta贡献 2020-10-31 21:44:05 +01:00
haiyangcui
15c542db82 Film页面搜索用el-table实现 2020-10-31 21:34:32 +01:00
haiyangcui
1a3ccaa3ba 统一editsite页面的格式 2020-10-31 21:23:55 +01:00
haiyangcui
3d01fd045f 统一优化listpage格式 2020-10-31 12:28:36 +01:00
haiyangcui
f6636a7864 重置软件也受密码保护 2020-10-30 23:06:24 +01:00
haiyangcui
dd108d3b09 避免不必要的刷新 2020-10-30 18:27:04 +01:00
haiyangcui
0b24ded61f 同步时,如果没有更新,不再提示 2020-10-30 18:17:13 +01:00
haiyangcui
d21494cf86 集中在style中定义pictureView的格式 2020-10-30 18:13:12 +01:00
haiyangcui
76add8f87a "编辑源"可以设置密码 2020-10-30 17:48:10 +01:00
haiyangcui
5a115700e3 收藏视图添加有更新提示,优化格式 2020-10-30 15:16:05 +01:00
haiyangcui
16e8ef2c4a 收藏页面播放,无需再查看历史记录,收藏数据已包含 2020-10-30 13:52:09 +01:00
haiyangcui
483449aad8 v2.5.8 2020-10-30 11:52:31 +01:00
haiyangcui
2b7a425f6f 影视推荐位置上移,更靠近Film页面 2020-10-30 11:50:17 +01:00
haiyangcui
a06c9e9d32 缩小地区和类型的按钮大小 2020-10-30 11:28:35 +01:00
haiyangcui
32a21952a2 推荐页面,视图添加地区信息 2020-10-30 11:25:47 +01:00
haiyangcui
ff01abe88c 改进推荐页面的过滤功能 2020-10-30 11:22:09 +01:00
haiyangcui
962f6b46c3 推荐页面,支持地区,类型的过滤 2020-10-30 10:58:31 +01:00
haiyangcui
b16604add6 更新推荐列表 2020-10-30 10:03:47 +01:00
haiyangcui
3028939ed9 改进豆瓣评分获取的算法 2020-10-30 09:43:04 +01:00
haiyangcui
1ffcb38b4b 优化'豆瓣评分'样式 2020-10-30 09:11:12 +01:00
Hunlongyu
2ec05b6ab5 🎳 移除request, 使用已有同样功能的axios重写.优化豆瓣评分样式 2020-10-30 10:05:45 +08:00
Hunlongyu
9cbd37d143 Merge branch 'master' of https://github.com/Hunlongyu/ZY-Player into master 2020-10-30 09:30:59 +08:00
Hunlongyu
b9ab1b11f4 🎱 关闭有可能导致安全软件报警的代码 2020-10-30 09:30:53 +08:00
haiyangcui
428f49a2e8 更新推荐电影 2020-10-29 23:50:29 +01:00
haiyangcui
2e8941c6cc 记录推荐页的视图模式 2020-10-29 23:12:40 +01:00
haiyangcui
91e2fc56b7 添加recommandation数据库,支持更新推荐 2020-10-29 22:55:14 +01:00
haiyangcui
e2b124e4ac 添加“影视推荐”页面 2020-10-29 21:51:34 +01:00
haiyangcui
6b37e3ebd5 定义pictureView样式并复用 2020-10-29 21:36:12 +01:00
haiyangcui
5dcdb6a410 记录sartViewMode 2020-10-29 18:29:23 +01:00
haiyangcui
5d41f783bc 统一海报视图的格式 2020-10-29 15:47:12 +01:00
haiyangcui
28ad8f3313 详情页面收藏的话,如果收藏已存在,更新收藏信息 2020-10-29 12:49:30 +01:00
haiyangcui
c475fbdf46 收藏视图页面添加豆瓣评分信息 2020-10-29 12:46:06 +01:00
Hunlongyu
ee622f88da 🏉 收藏新增海报模式. 2020-10-29 18:12:54 +08:00
haiyangcui
1b2461c423 Merge branch 'master' of https://github.com/Hunlongyu/ZY-Player 2020-10-29 10:10:37 +01:00
Hunlongyu
3044bfcbc4 🏈 mini 界面优化 2020-10-29 16:59:25 +08:00
haiyangcui
4038e5e6be Merge branch 'dev_improveStar' 2020-10-29 09:32:28 +01:00
haiyangcui
bea1ef4c73 收藏页面添加视图开关 2020-10-29 09:12:33 +01:00
Hunlongyu
7af9a6d76d 🏐 编辑源增加状态排序, 修复换源功能里源的标识问题. 优化搜索结果样式变形 2020-10-29 15:32:56 +08:00
Hunlongyu
2140d90a87 🏀 源编辑,加入单个源检测功能. 2020-10-29 14:45:46 +08:00
Hunlongyu
e86eef1b05 添加快捷键指南, 修复换源功能阻塞问题 2020-10-29 14:35:58 +08:00
haiyangcui
42dd8fe5e4 star添加豆瓣评分记录 2020-10-29 00:09:29 +01:00
haiyangcui
9fd8c60dd5 "获取豆瓣评分"功能到tools.js 2020-10-28 23:29:39 +01:00
haiyangcui
49c480061b 收藏数据里记录detail所有内容 2020-10-28 18:09:10 +01:00
32 changed files with 13816 additions and 1845 deletions

View File

@@ -29,6 +29,7 @@
### ✨特性
- 🍕 全平台支持. Windows, Mac, Linux
- 🍥 支持 IPTV, 卫视直播
- 🍔 视频源支持自定义, 支持导入, 导出
- 🍟 支持海报模式和列表模式浏览资源
- 🌭 播放历史, 自动跳转历史进度
@@ -84,9 +85,3 @@
| :----------------------------------------------------------: | :----------------------------------------------------------: |
| <img width="120" src="https://avatars2.githubusercontent.com/u/15273630?s=460&u=48cf3299e2a842c0252233d8be42ef4c5d792138&v=4"/> | <img width="120" src="https://avatars0.githubusercontent.com/u/5760235?s=460&u=9d969dd8d83f069ce7ebd60516770c93ac07a330&v=4" /> |
| 💻 🎨 🐛 | 💻 🐛 |
### 🧧 赞助
[![LATOPAY](https://latopay.com/w/lt-bg-2062.png)](https://latopay.com/@Hunlongyu)

View File

@@ -1,6 +1,6 @@
{
"name": "zy",
"version": "2.5.7",
"version": "2.6.5",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
@@ -17,29 +17,33 @@
},
"main": "background.js",
"dependencies": {
"axios": "^0.20.0",
"axios": "^0.21.0",
"cheerio": "^1.0.0-rc.3",
"child_process": "^1.0.2",
"core-js": "^3.6.5",
"core-js": "^3.7.0",
"cors": "^2.8.5",
"dexie": "^3.0.2",
"electron-localshortcut": "^3.2.1",
"electron-proxy-agent": "^1.2.0",
"electron-updater": "^4.3.5",
"element-ui": "^2.13.2",
"element-ui": "^2.14.0",
"express": "^4.17.1",
"fast-xml-parser": "^3.17.4",
"html2canvas": "^1.0.0-rc.7",
"iptv-playlist-parser": "^0.5.0",
"m3u": "0.0.2",
"m3u8-parser": "^4.5.0",
"memcached": "^2.2.2",
"modern-normalize": "^1.0.0",
"mousetrap": "^1.6.5",
"qrcode.vue": "^1.7.0",
"randomstring": "^1.1.5",
"session": "^0.1.0",
"v-fit-columns": "^0.2.0",
"vue": "^2.6.12",
"vue-clickaway": "^2.2.2",
"vue-infinite-loading": "^2.4.5",
"vue-waterfall-plugin": "^1.1.0",
"vuedraggable": "^2.24.2",
"vuedraggable": "^2.24.3",
"vuex": "^3.5.1",
"xgplayer": "^2.13.0",
"xgplayer-hls.js": "^2.2.5"
@@ -52,15 +56,15 @@
"@vue/eslint-config-standard": "^5.1.2",
"babel-eslint": "^10.1.0",
"babel-plugin-component": "^1.1.1",
"electron": "^10.1.4",
"electron": "^10.1.5",
"electron-devtools-installer": "^3.1.0",
"eslint": "^6.7.2",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.0",
"eslint-plugin-standard": "^4.0.2",
"eslint-plugin-vue": "^6.2.2",
"sass": "^1.26.5",
"sass": "^1.29.0",
"sass-loader": "^8.0.2",
"vue-cli-plugin-electron-builder": "2.0.0-rc.4",
"vue-template-compiler": "^2.6.12"

View File

@@ -10,6 +10,7 @@
<History v-show="view === 'History'" />
<Setting v-show="view === 'Setting'" />
<EditSites v-if="view === 'EditSites'"/>
<Recommendation v-show="view === 'Recommendation'" />
</div>
<transition name="slide">
<Detail v-if="detail.show"/>
@@ -43,6 +44,9 @@ export default {
},
editSites () {
return this.$store.getters.getEditSites
},
recommendation () {
return this.$store.getters.recommendation
}
},
watch: {

View File

@@ -98,91 +98,6 @@
.zy-highlighted{
color: var(--highlight-color);
}
// table
.zy-table{
display: flex;
flex-direction: column;
height: 100%;
font-size: 15px;
.tHeader{
display: flex;
align-items: center;
justify-content: space-between;
height: 50px;
min-height: 50px;
width: 100%;
border-bottom: 1px solid;
.btn{
user-select: none;
margin-left: 15px;
margin-right: 15px;
cursor: pointer;
font-size: 14px;
}
}
.tBody{
flex: 1;
border-bottom: 1px solid;
overflow: auto;
.el-table__row td{
border: none;
}
.el-table::before{
height: 0px;
}
ul{
list-style: none;
padding: 0;
margin: 0;
li{
display: flex;
justify-content: flex-start;
align-items: center;
flex-direction: row;
height: 50px;
border-bottom: 1px solid;
cursor: pointer;
span{
display: flex;
font-size: 13px;
height: 50px;
line-height: 50px;
overflow: hidden;
margin-right: 5px;
&.name{
flex: 1;
min-width: 100px;
white-space: nowrap;
margin-left: 10px;
}
&.type{
width: 10%;
}
&.time{
width: 10%;
}
&.last{
width: 10%;
}
&.site{
width: 10%;
}
&.note{
width: 10%;
}
&.info{
width: 10%;
}
&.operate{
.btn{
width: 40px;
}
}
}
}
}
}
}
// scroll
.zy-scroll{
&::-webkit-scrollbar{
@@ -209,47 +124,96 @@
width: calc(100% - 100px);
height: calc(100% - 60px);
border-radius: 5px;
.listpage-content{
height: 100%;
position: relative;
font-size: 1rem;
.listpage-header{
display: flex;
flex-direction: column;
.listpage-header{
height: 60px;
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
z-index: 10;
.header-box{
height: 100%;
width: 100%;
height: 40px;
display: flex;
align-items: center;
justify-content: space-between;
padding-left: 50px;
padding-right: 50px;
.el-button{
font-size: 1rem;
border: none;
&:hover{
cursor: pointer;
}
}
.is-loading:before {
background-color: none !important;
}
.el-input{
width: 200px;
}
.el-button{
font-size: 1rem;
border: none;
&:hover{
cursor: pointer;
}
}
.listpage-body{
height: calc(100% - 40px);
overflow-y: auto;
.el-autocomplete{
.el-input-group__prepend{
border: none;
.el-select{
width: 100px;
.el-input, .el-input__inner{
width: 100%;
border: none;
}
}
}
.el-input .el-input__inner{
width: 200px;
}
.el-input-group__append{
border: none;
}
}
.is-loading:before {
background-color: none !important;
}
.el-input{
font-size: 1rem;
width: 200px;
}
.popper {
font-size: 1rem;;
border: none;
li {
font-size: 1rem;
border: none;
}
}
}
.listpage-body{
height: calc(100% - 60px);
overflow-y: auto;
position: relative;
font-size: 1rem;
&::-webkit-scrollbar{
width: 5px;
height: 1px;
}
&::-webkit-scrollbar-thumb {
border-radius: 10px;
position: absolute;
}
&::-webkit-scrollbar-track {
border-radius: 10px;
position: absolute;
}
.show-table{
height: 100%;
width: 100%;
.el-table::before{
height: 0px;
}
.el-table{
height: 100%;
width: 100%;
overflow-y: auto;
overflow: hidden;
font-size: 1rem;
}
.el-table__body-wrapper{
height: 100%;
width: 100%;
&::-webkit-scrollbar{
width: 10px;
width: 5px;
height: 1px;
}
&::-webkit-scrollbar-thumb {
@@ -271,14 +235,122 @@
transform: scale(1.02);
}
.el-table .highlight{
color: var(--highlight-color) !important;
background-color: var(--highlight-color) !important; // 改为背景色,原来某些主题下看不清字
}
.el-button{
font-size: 1rem;
}
}
.show-picture{
height: 100%;
width: 100%;
padding: 10px;
.card{
border-radius: 6px;
overflow: hidden;
position: relative;
cursor: pointer;
transition: 0.2s;
&:hover {
top: -3px;
}
.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);
}
.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;
}
}
}
}
}
}
// loading
.zy-loading{
width: 100%;
@@ -323,4 +395,4 @@
box-shadow: 0em -3em 0 0, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 0, -3em 0em 0 0, -2em -2em 0 0.2em;
}
}
}
}

View File

@@ -41,40 +41,6 @@
color: var(--d-fc-1);
}
}
.zy-checkbox{
color: var(--d-fc-1);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
}
.zy-table{
color: var(--d-fc-2);
.tHeader{
border-bottom-color: var(--d-c-3);
.btn{
&:hover{
color: var(--d-fc-3)
}
}
}
.tBody{
border-bottom-color: var(--d-c-3);
ul{
li{
border-bottom-color: var(--d-c-2);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
&:hover{
box-shadow: var(--d-bsc);
background-color: var(--d-bgc-2);
color: #fff;
}
span{
&.btn:hover{
color: var(--d-fc-3)
}
}
}
}
}
}
.zy-scroll{
&:hover{
&::-webkit-scrollbar-thumb {
@@ -170,23 +136,6 @@
}
}
}
.film{
.body{
background-color: var(--d-bgc-1);
box-shadow: var(--d-bsc);
.show-img{
color: var(--d-fc-1);
.card{
background-color: var(--d-bgc-1);
box-shadow: var(--d-bsc);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
&:hover{
box-shadow: var(--d-bsc-hover);
}
}
}
}
}
.play{
background-color: var(--d-bgc-1);
box-shadow: var(--d-bsc);
@@ -286,10 +235,6 @@
}
}
}
.star{
background-color: var(--d-bgc-1);
box-shadow: var(--d-bsc);
}
.setting{
background-color: var(--d-bgc-1);
box-shadow: var(--d-bsc);
@@ -355,49 +300,68 @@
background-color: var(--d-bgc-1);
box-shadow: var(--d-bsc);
}
// Page of list using el-table
// Page of list using table and picture
.listpage{
color: var(--d-fc-2);
.listpage-content{
.listpage-header{
border-bottom-color: var(--d-c-3);
.btn{
&:hover{
color: var(--d-fc-3)
}
.listpage-header{
border-bottom-color: var(--d-c-3);
.btn{
&:hover{
color: var(--d-fc-3)
}
.el-button{
background-color: var(--d-bgc-2);
}
.el-button{
background-color: var(--d-bgc-2);
color: var(--d-fc-2);
&:hover{
color: var(--d-fc-3)
}
}
.el-input{
input{
background-color: var(--d-bgc-1);
border: 1px solid var(--d-bgc-1);
color: var(--d-fc-2);
&:hover{
color: var(--d-fc-3)
}
}
.el-input{
input{
background-color: var(--d-bgc-1);
border: 1px solid var(--d-bgc-1);
color: var(--d-fc-2);
}
.el-input-group__prepend{
background-color: var(--d-bgc-1);
}
.popper {
color: var(--d-fc-1);
background-color: var(--d-bgc-1);
box-shadow: var(--d-bsc);
li {
color: var(--d-fc-1);
background-color: var(--d-bgc-1);
&:hover{
background-color: var(--d-bgc-2);
}
}
}
.listpage-body{
/* 设置el-table的样式*/
.popper__arrow, .popper__arrow::after{
border-bottom-color: var(--d-bgc-1);
}
}
.listpage-body{
color: var(--d-fc-1);
background-color: var(--d-bgc-1);
&:hover{
&::-webkit-scrollbar-thumb {
box-shadow: var(--d-bsc-scroll);
background: var(--d-c-5);
}
&::-webkit-scrollbar-track {
box-shadow: var(--d-bsc-scroll);
background: var(--d-bgc-1);
}
}
/* 设置el-table的样式*/
.show-table{
.el-table{
color: var(--d-fc-1);
background-color: var(--d-bgc-1);
}
.el-input{
input{
background-color: var(--d-bgc-2);
border: 1px solid var(--d-bgc-2);
color: var(--d-fc-1);
}
}
.el-table__header th, .el-table__header tr, .el-table__body td,.el-table__body th{
color: var(--d-fc-1);
background-color: var(--d-bgc-1);
border-bottom-color: var(--d-c-2);
}
.el-table__body-wrapper{
&:hover{
@@ -411,6 +375,18 @@
}
}
}
.el-input{
input{
background-color: var(--d-bgc-2);
border: 1px solid var(--d-bgc-2);
color: var(--d-fc-1);
}
}
.el-table__header th, .el-table__header tr, .el-table__body td,.el-table__body th{
color: var(--d-fc-1);
background-color: var(--d-bgc-1);
border-bottom-color: var(--d-c-2);
}
.el-table--enable-row-hover .el-table__body tr:hover>td{
background-color: var(--d-bgc-2);
}
@@ -421,6 +397,17 @@
}
}
}
.show-picture{
color: var(--d-fc-1);
.card{
background-color: var(--d-bgc-1);
box-shadow: var(--d-bsc);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
&:hover{
box-shadow: var(--d-bsc-hover);
}
}
}
}
}
}

View File

@@ -24,6 +24,8 @@
}
}
.vs-input{
color: var(--g-fc-1);
background-color: var(--g-bgc-1);
input{
color: var(--g-fc-1);
&::-webkit-input-placeholder{
@@ -37,38 +39,6 @@
background-color: var(--g-bgc-1);
input{
color: var(--g-fc-1);
background-color: var(--g-bgc-1);
}
}
.zy-checkbox{
color: var(--g-fc-1);
}
.zy-table{
color: var(--g-fc-2);
.tHeader{
border-bottom-color: var(--g-c-3);
.btn{
&:hover{
color: var(--g-fc-3)
}
}
}
.tBody{
border-bottom-color: var(--g-c-3);
ul{
li{
border-bottom-color: var(--g-c-2);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
&:hover{
box-shadow: var(--g-bsc-hover);
}
span{
&.btn:hover{
color: var(--g-fc-3)
}
}
}
}
}
}
.zy-scroll{
@@ -166,23 +136,6 @@
}
}
}
.film{
.body{
background-color: var(--g-bgc-1);
box-shadow: var(--g-bsc);
.show-img{
color: var(--g-fc-1);
.card{
background-color: var(--g-bgc-1);
box-shadow: var(--g-bsc);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
&:hover{
box-shadow: var(--g-bsc-hover);
}
}
}
}
}
.play{
background-color: var(--g-bgc-1);
box-shadow: var(--g-bsc);
@@ -282,10 +235,6 @@
}
}
}
.star{
background-color: var(--g-bgc-1);
box-shadow: var(--g-bsc);
}
.setting{
background-color: var(--g-bgc-1);
box-shadow: var(--g-bsc);
@@ -351,49 +300,68 @@
background-color: var(--g-bgc-1);
box-shadow: var(--g-bsc);
}
// Page of list using el-table
// Page of list using table and picture
.listpage{
color: var(--g-fc-2);
.listpage-content{
.listpage-header{
border-bottom-color: var(--g-c-3);
.btn{
&:hover{
color: var(--g-fc-3)
}
.listpage-header{
border-bottom-color: var(--g-c-3);
.btn{
&:hover{
color: var(--g-fc-3)
}
.el-button{
background-color: var(--g-bgc-2);
}
.el-button{
background-color: var(--g-bgc-2);
color: var(--g-fc-2);
&:hover{
color: var(--g-fc-3)
}
}
.el-input{
input{
background-color: var(--g-bgc-1);
border: 1px solid var(--g-bgc-1);
color: var(--g-fc-2);
&:hover{
color: var(--g-fc-3)
}
}
.el-input{
input{
background-color: var(--g-bgc-1);
border: 1px solid var(--g-bgc-1);
color: var(--g-fc-2);
}
.el-input-group__prepend{
background-color: var(--g-bgc-1);
}
.popper {
color: var(--g-fc-1);
background-color: var(--g-bgc-1);
box-shadow: var(--g-bsc);
li {
color: var(--g-fc-1);
background-color: var(--g-bgc-1);
&:hover{
background-color: var(--g-bgc-2);
}
}
}
.listpage-body{
/* 设置el-table的样式*/
.popper__arrow, .popper__arrow::after{
border-bottom-color: var(--g-bgc-1);
}
}
.listpage-body{
color: var(--g-fc-1);
background-color: var(--g-bgc-1);
&:hover{
&::-webkit-scrollbar-thumb {
box-shadow: var(--g-bsc-scroll);
background: var(--g-c-5);
}
&::-webkit-scrollbar-track {
box-shadow: var(--g-bsc-scroll);
background: var(--g-bgc-1);
}
}
/* 设置el-table的样式*/
.show-table{
.el-table{
color: var(--g-fc-1);
background-color: var(--g-bgc-1);
}
.el-input{
input{
background-color: var(--g-bgc-2);
border: 1px solid var(--g-bgc-2);
color: var(--g-fc-1);
}
}
.el-table__header th, .el-table__header tr, .el-table__body td,.el-table__body th{
color: var(--g-fc-1);
background-color: var(--g-bgc-1);
border-bottom-color: var(--g-c-2);
}
.el-table__body-wrapper{
&:hover{
@@ -407,6 +375,18 @@
}
}
}
.el-input{
input{
background-color: var(--g-bgc-2);
border: 1px solid var(--g-bgc-2);
color: var(--g-fc-1);
}
}
.el-table__header th, .el-table__header tr, .el-table__body td,.el-table__body th{
color: var(--g-fc-1);
background-color: var(--g-bgc-1);
border-bottom-color: var(--g-c-2);
}
.el-table--enable-row-hover .el-table__body tr:hover>td{
background-color: var(--g-bgc-2);
}
@@ -417,6 +397,17 @@
}
}
}
.show-picture{
color: var(--g-fc-1);
.card{
background-color: var(--g-bgc-1);
box-shadow: var(--g-bsc);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
&:hover{
box-shadow: var(--g-bsc-hover);
}
}
}
}
}
}

View File

@@ -24,6 +24,8 @@
}
}
.vs-input{
color: var(--l-fc-1);
background-color: var(--l-bgc-1);
input{
color: var(--l-fc-1);
&::-webkit-input-placeholder{
@@ -37,38 +39,6 @@
background-color: var(--l-bgc-1);
input{
color: var(--l-fc-1);
background-color: var(--l-bgc-1);
}
}
.zy-checkbox{
color: var(--l-fc-1);
}
.zy-table{
color: var(--l-fc-2);
.tHeader{
border-bottom-color: var(--l-c-3);
.btn{
&:hover{
color: var(--l-fc-3)
}
}
}
.tBody{
border-bottom-color: var(--l-c-3);
ul{
li{
border-bottom-color: var(--l-c-2);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
&:hover{
box-shadow: var(--l-bsc-hover);
}
span{
&.btn:hover{
color: var(--l-fc-3)
}
}
}
}
}
}
.zy-scroll{
@@ -166,23 +136,6 @@
}
}
}
.film{
.body{
background-color: var(--l-bgc-1);
box-shadow: var(--l-bsc);
.show-img{
color: var(--l-fc-1);
.card{
background-color: var(--l-bgc-1);
box-shadow: var(--l-bsc);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
&:hover{
box-shadow: var(--l-bsc-hover);
}
}
}
}
}
.play{
background-color: var(--l-bgc-1);
box-shadow: var(--l-bsc);
@@ -282,10 +235,6 @@
}
}
}
.star{
background-color: var(--l-bgc-1);
box-shadow: var(--l-bsc);
}
.setting{
background-color: var(--l-bgc-1);
box-shadow: var(--l-bsc);
@@ -351,49 +300,68 @@
background-color: var(--l-bgc-1);
box-shadow: var(--l-bsc);
}
// Page of list using el-table
// Page of list using table and picture
.listpage{
color: var(--l-fc-2);
.listpage-content{
.listpage-header{
border-bottom-color: var(--l-c-3);
.btn{
&:hover{
color: var(--l-fc-3)
}
.listpage-header{
border-bottom-color: var(--l-c-3);
.btn{
&:hover{
color: var(--l-fc-3)
}
.el-button{
background-color: var(--l-bgc-2);
}
.el-button{
background-color: var(--l-bgc-2);
color: var(--l-fc-2);
&:hover{
color: var(--l-fc-3)
}
}
.el-input{
input{
background-color: var(--l-bgc-1);
border: 1px solid var(--l-bgc-1);
color: var(--l-fc-2);
&:hover{
color: var(--l-fc-3)
}
}
.el-input{
input{
background-color: var(--l-bgc-1);
border: 1px solid var(--l-bgc-1);
color: var(--l-fc-2);
}
.el-input-group__prepend{
background-color: var(--l-bgc-1);
}
.popper {
color: var(--l-fc-1);
background-color: var(--l-bgc-1);
box-shadow: var(--l-bsc);
li {
color: var(--l-fc-1);
background-color: var(--l-bgc-1);
&:hover{
background-color: var(--l-bgc-2);
}
}
}
.listpage-body{
/* 设置el-table的样式*/
.popper__arrow, .popper__arrow::after{
border-bottom-color: var(--l-bgc-1);
}
}
.listpage-body{
color: var(--l-fc-1);
background-color: var(--l-bgc-1);
&:hover{
&::-webkit-scrollbar-thumb {
box-shadow: var(--l-bsc-scroll);
background: var(--l-c-5);
}
&::-webkit-scrollbar-track {
box-shadow: var(--l-bsc-scroll);
background: var(--l-bgc-1);
}
}
/* 设置el-table的样式*/
.show-table{
.el-table{
color: var(--l-fc-1);
background-color: var(--l-bgc-1);
}
.el-input{
input{
background-color: var(--l-bgc-2);
border: 1px solid var(--l-bgc-2);
color: var(--l-fc-1);
}
}
.el-table__header th, .el-table__header tr, .el-table__body td,.el-table__body th{
color: var(--l-fc-1);
background-color: var(--l-bgc-1);
border-bottom-color: var(--l-c-2);
}
.el-table__body-wrapper{
&:hover{
@@ -407,6 +375,18 @@
}
}
}
.el-input{
input{
background-color: var(--l-bgc-2);
border: 1px solid var(--l-bgc-2);
color: var(--l-fc-1);
}
}
.el-table__header th, .el-table__header tr, .el-table__body td,.el-table__body th{
color: var(--l-fc-1);
background-color: var(--l-bgc-1);
border-bottom-color: var(--l-c-2);
}
.el-table--enable-row-hover .el-table__body tr:hover>td{
background-color: var(--l-bgc-2);
}
@@ -417,6 +397,17 @@
}
}
}
.show-picture{
color: var(--l-fc-1);
.card{
background-color: var(--l-bgc-1);
box-shadow: var(--l-bsc);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
&:hover{
box-shadow: var(--l-bsc-hover);
}
}
}
}
}
}

View File

@@ -24,6 +24,8 @@
}
}
.vs-input{
color: var(--p-fc-1);
background-color: var(--p-bgc-1);
input{
color: var(--p-fc-1);
&::-webkit-input-placeholder{
@@ -39,37 +41,6 @@
color: var(--p-fc-1);
}
}
.zy-checkbox{
color: var(--p-fc-1);
}
.zy-table{
color: var(--p-fc-2);
.tHeader{
border-bottom-color: var(--p-c-3);
.btn{
&:hover{
color: var(--p-fc-3)
}
}
}
.tBody{
border-bottom-color: var(--p-c-3);
ul{
li{
border-bottom-color: var(--p-c-2);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
&:hover{
box-shadow: var(--p-bsc-hover);
}
span{
&.btn:hover{
color: var(--p-fc-3)
}
}
}
}
}
}
.zy-scroll{
&:hover{
&::-webkit-scrollbar-thumb {
@@ -165,23 +136,6 @@
}
}
}
.film{
.body{
background-color: var(--p-bgc-1);
box-shadow: var(--p-bsc);
.show-img{
color: var(--p-fc-1);
.card{
background-color: var(--p-bgc-1);
box-shadow: var(--p-bsc);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
&:hover{
box-shadow: var(--p-bsc-hover);
}
}
}
}
}
.play{
background-color: var(--p-bgc-1);
box-shadow: var(--p-bsc);
@@ -281,10 +235,6 @@
}
}
}
.star{
background-color: var(--p-bgc-1);
box-shadow: var(--p-bsc);
}
.setting{
background-color: var(--p-bgc-1);
box-shadow: var(--p-bsc);
@@ -350,49 +300,68 @@
background-color: var(--p-bgc-1);
box-shadow: var(--p-bsc);
}
// Page of list using el-table
// Page of list using table and picture
.listpage{
color: var(--p-fc-2);
.listpage-content{
.listpage-header{
border-bottom-color: var(--p-c-3);
.btn{
&:hover{
color: var(--p-fc-3)
}
.listpage-header{
border-bottom-color: var(--p-c-3);
.btn{
&:hover{
color: var(--p-fc-3)
}
.el-button{
background-color: var(--p-bgc-2);
}
.el-button{
background-color: var(--p-bgc-2);
color: var(--p-fc-2);
&:hover{
color: var(--p-fc-3)
}
}
.el-input{
input{
background-color: var(--p-bgc-1);
border: 1px solid var(--p-bgc-1);
color: var(--p-fc-2);
&:hover{
color: var(--p-fc-3)
}
}
.el-input{
input{
background-color: var(--p-bgc-1);
border: 1px solid var(--p-bgc-1);
color: var(--p-fc-2);
}
.el-input-group__prepend{
background-color: var(--p-bgc-1);
}
.popper {
color: var(--p-fc-1);
background-color: var(--p-bgc-1);
box-shadow: var(--p-bsc);
li {
color: var(--p-fc-1);
background-color: var(--p-bgc-1);
&:hover{
background-color: var(--p-bgc-2);
}
}
}
.listpage-body{
/* 设置el-table的样式*/
.popper__arrow, .popper__arrow::after{
border-bottom-color: var(--p-bgc-1);
}
}
.listpage-body{
color: var(--p-fc-1);
background-color: var(--p-bgc-1);
&:hover{
&::-webkit-scrollbar-thumb {
box-shadow: var(--p-bsc-scroll);
background: var(--p-c-5);
}
&::-webkit-scrollbar-track {
box-shadow: var(--p-bsc-scroll);
background: var(--p-bgc-1);
}
}
/* 设置el-table的样式*/
.show-table{
.el-table{
color: var(--p-fc-1);
background-color: var(--p-bgc-1);
}
.el-input{
input{
background-color: var(--p-bgc-2);
border: 1px solid var(--p-bgc-2);
color: var(--p-fc-1);
}
}
.el-table__header th, .el-table__header tr, .el-table__body td,.el-table__body th{
color: var(--p-fc-1);
background-color: var(--p-bgc-1);
border-bottom-color: var(--p-c-2);
}
.el-table__body-wrapper{
&:hover{
@@ -406,6 +375,18 @@
}
}
}
.el-input{
input{
background-color: var(--p-bgc-2);
border: 1px solid var(--p-bgc-2);
color: var(--p-fc-1);
}
}
.el-table__header th, .el-table__header tr, .el-table__body td,.el-table__body th{
color: var(--p-fc-1);
background-color: var(--p-bgc-1);
border-bottom-color: var(--p-c-2);
}
.el-table--enable-row-hover .el-table__body tr:hover>td{
background-color: var(--p-bgc-2);
}
@@ -416,6 +397,17 @@
}
}
}
.show-picture{
color: var(--p-fc-1);
.card{
background-color: var(--p-bgc-1);
box-shadow: var(--p-bsc);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
&:hover{
box-shadow: var(--p-bsc-hover);
}
}
}
}
}
}

View File

@@ -8,7 +8,7 @@ import { initUpdater } from './lib/update/update'
const isDevelopment = process.env.NODE_ENV !== 'production'
app.commandLine.appendSwitch('disable-features', 'OutOfBlinkCors') // 允许跨域
app.commandLine.appendSwitch('--ignore-certificate-errors', 'true') // 忽略证书相关错误
// app.commandLine.appendSwitch('--ignore-certificate-errors', 'true') // 忽略证书相关错误
let win
let mini

View File

@@ -14,6 +14,13 @@
</g>
</svg>
</span>
<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 :class="[view === 'IPTV' ? 'active ': ''] + 'zy-svg'" @click="changeView('IPTV')">
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-labelledby="tvIconTitle">
<title id="tvIconTitle">电视直播</title>

View File

@@ -128,33 +128,23 @@ export default {
close () {
this.detail.show = false
},
m3u8Parse (e) {
const dd = e.dl.dd
const type = Object.prototype.toString.call(dd)
if (type === '[object Array]') {
for (const i of dd) {
if (i._flag.indexOf('m3u8') >= 0) {
this.m3u8List = i._t.split('#')
}
}
} else {
this.m3u8List = dd._t.split('#')
}
},
async playEvent (n) {
if (!this.playOnline) {
console.log(this.detail)
const db = await history.find({ site: this.detail.key, ids: this.detail.info.id })
if (db) {
this.video = { key: db.site, info: { id: db.ids, name: db.name, index: n, site: this.detail.site } }
} else {
this.video = { key: this.detail.key, info: { id: this.detail.info.id, name: this.detail.info.name, index: n, site: this.detail.site } }
}
this.video.detail = this.info
this.view = 'Play'
this.detail.show = false
} else {
const db = await history.find({ site: this.detail.key, ids: this.detail.info.id })
if (db) {
db.index = n
db.detail = this.info
history.update(db.id, db)
} else {
const doc = {
@@ -164,7 +154,8 @@ export default {
type: this.detail.info.type,
year: this.detail.info.year,
index: n,
time: ''
time: '',
detail: this.info
}
history.add(doc)
}
@@ -173,21 +164,19 @@ export default {
},
async starEvent () {
const db = await star.find({ key: this.detail.key, ids: this.info.id })
const doc = {
key: this.detail.key,
ids: this.info.id,
site: this.detail.site,
name: this.info.name,
detail: this.info,
rate: this.info.rate
}
if (db) {
this.$message.info('该影片已被收藏')
star.update(db.id, doc)
this.$message.success('收藏更新成功')
} else {
const docs = {
key: this.detail.key,
ids: this.info.id,
site: this.detail.site,
name: this.info.name,
type: this.info.type,
year: this.info.year,
note: this.info.note,
last: this.info.last
}
star.add(docs).then(res => {
star.add(doc).then(res => {
this.$message.success('收藏成功')
})
}
@@ -258,61 +247,16 @@ export default {
}
},
doubanLinkEvent () {
const open = require('open')
const axios = require('axios')
const cheerio = require('cheerio')
const name = this.detail.info.name.trim()
// 豆瓣搜索链接
var doubanSearchLink = 'https://www.douban.com/search?q=' + name
var link = doubanSearchLink
axios.get(doubanSearchLink).then(res => {
const $ = cheerio.load(res.data)
// 比较第一和第二豆瓣搜索结果, 如果名字相符, 就打开该链接,否则打开搜索页面
var nameInDouban = $($('div.result')[0]).find('div>div>h3>a').first()
if (name.replace(/\s/g, '') === nameInDouban.text().replace(/\s/g, '')) {
link = nameInDouban.attr('href')
} else {
nameInDouban = $($('div.result')[1]).find('div>div>h3>a').first()
if (name.replace(/\s/g, '') === nameInDouban.text().replace(/\s/g, '')) {
link = nameInDouban.attr('href')
}
}
zy.doubanLink(name).then(link => {
const open = require('open')
open(link)
})
},
getDoubanRate () {
const axios = require('axios')
const cheerio = require('cheerio')
const name = this.detail.info.name.trim()
// 豆瓣搜索链接
var doubanSearchLink = 'https://www.douban.com/search?q=' + name
axios.get(doubanSearchLink).then(res => {
const $ = cheerio.load(res.data)
// 比较第一和第二给豆瓣搜索结果, 看名字是否相符
var link = ''
var nameInDouban = $($('div.result')[0]).find('div>div>h3>a').first()
if (name.replace(/\s/g, '') === nameInDouban.text().replace(/\s/g, '')) {
link = nameInDouban.attr('href')
} else {
nameInDouban = $($('div.result')[1]).find('div>div>h3>a').first()
if (name.replace(/\s/g, '') === nameInDouban.text().replace(/\s/g, '')) {
link = nameInDouban.attr('href')
}
}
// 如果找到链接,就打开该链接获取评分
if (link) {
axios.get(link).then(response => {
const parsedHtml = cheerio.load(response.data)
var rating = parsedHtml('body').find('#interest_sectl').first().find('strong').first()
if (rating.text()) {
this.info.rate = rating.text()
} else {
this.info.rate = '暂无评分'
}
})
} else {
this.info.rate = '暂无评分'
}
zy.doubanRate(name).then(res => {
this.info.rate = res
})
},
getDetailInfo () {
@@ -321,7 +265,7 @@ export default {
if (res) {
this.info = res
this.$set(this.info, 'rate', '')
this.m3u8Parse(res)
this.m3u8List = res.m3u8List
this.getDoubanRate()
this.loading = false
}

View File

@@ -1,27 +1,27 @@
<template>
<div class="listpage" id="editSites">
<div class="listpage-content">
<div class="listpage-header" v-show="!enableBatchEdit">
<el-switch v-model="enableBatchEdit" active-text="批处理分组">></el-switch>
<el-button @click="addSite" icon="el-icon-document-add">新增</el-button>
<el-button @click="exportSites" icon="el-icon-upload2" >导出</el-button>
<el-button @click="importSites" icon="el-icon-download">导入</el-button>
<el-button @click="checkAllSite" icon="el-icon-refresh" :loading="checkAllSiteLoading">检测</el-button>
<el-button @click="removeAllSites" icon="el-icon-delete-solid">清空</el-button>
<el-button @click="resetSitesEvent" icon="el-icon-refresh-left">重置</el-button>
</div>
<div class="listpage-header" v-show="enableBatchEdit">
<el-switch v-model="enableBatchEdit" active-text="批处理分组"></el-switch>
<el-input placeholder="新组名" v-model="batchGroupName"></el-input>
<el-switch v-model="batchIsActive" :active-value="1" :inactive-value="0" active-text="自选源"></el-switch>
<el-button type="primary" icon="el-icon-edit" @click.stop="saveBatchEdit">保存</el-button>
</div>
<div class="listpage-body" id="sites-table">
<el-table
<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="addSite" icon="el-icon-document-add">新增</el-button>
<el-button @click="exportSites" icon="el-icon-upload2" >导出</el-button>
<el-button @click="importSites" icon="el-icon-download">导入</el-button>
<el-button @click="checkAllSite" icon="el-icon-refresh" :loading="checkAllSitesLoading">检测{{ this.checkAllSitesLoading ? this.checkProgress + '/' + this.sites.length : '' }}</el-button>
<el-button @click="resetSitesEvent" icon="el-icon-refresh-left">重置</el-button>
</div>
<div class="listpage-header" v-show="enableBatchEdit">
<el-switch v-model="enableBatchEdit" active-text="批处理分组"></el-switch>
<el-input placeholder="新组名" v-model="batchGroupName"></el-input>
<el-switch v-model="batchIsActive" active-text="启用"></el-switch>
<el-button type="primary" icon="el-icon-edit" @click.stop="saveBatchEdit">保存</el-button>
<el-button @click="removeSelectedSites" icon="el-icon-delete-solid">删除</el-button>
</div>
<div class="listpage-body" id="sites-body">
<div class="show-table" id="sites-table">
<el-table size="mini" fit height="100%" row-key="id"
ref="editSitesTable"
size="mini" fit height="100%" row-key="id"
:data="sites"
:key="tableKey"
@select="selectionCellClick"
@selection-change="handleSelectionChange"
@sort-change="handleSortChange">
<el-table-column
@@ -34,13 +34,14 @@
</el-table-column>
<el-table-column
prop="isActive"
label="自选源">
width="120"
:filters = "[{text:'启用', value: true}, {text:'停用', value: false}]"
:filter-method="(value, row) => value === row.isActive"
label="启用">
<template slot-scope="scope">
<el-switch
v-model="scope.row.isActive"
:active-value="1"
:inactive-value="0"
@change='isActiveChangeEvent'>
@click.native.stop='isActiveChangeEvent(scope.row)'>
</el-switch>
</template>
</el-table-column>
@@ -48,33 +49,38 @@
prop="group"
label="分组"
:filters="getFilters"
:filter-method="filterHandle"
:filter-method="(value, row) => value === row.group"
filter-placement="bottom-end">
<template slot-scope="scope">
<el-button type="text">{{scope.row.group}}</el-button>
</template>
</el-table-column>
<el-table-column label="状态" width="120">
<el-table-column
label="状态"
sortable
:sort-by="['status']"
width="120">
<template slot-scope="scope">
<span v-show="scope.row.status === ''">
<span v-if="scope.row.status === ' '">
<i class="el-icon-loading"></i>
检测中...
</span>
<span v-show="scope.row.status !== ''">{{scope.row.status}}</span>
<span v-else>{{scope.row.status}}</span>
</template>
</el-table-column>
<el-table-column
label="操作"
header-align="right"
align="right">
header-align="center"
align="right"
:width="sites.every(site => site.status) && !checkAllSitesLoading ? 200 : 150">
<template slot-scope="scope">
<el-button size="mini" @click.stop="moveToTopEvent(scope.row)" type="text">置顶</el-button>
<el-button size="mini" @click.stop="editSite(scope.row)" type="text">编辑</el-button>
<!-- 检测时先强制批量检测一遍,如果不强制直接单个检测时第一次不会显示“检测中” -->
<el-button size="mini" v-if="sites.every(site => site.status)" v-show="!checkAllSitesLoading" @click.stop="checkSingleSite(scope.row)" type="text">检测</el-button>
<el-button size="mini" @click.stop="removeEvent(scope.row)" type="text">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
<!-- 编辑页面 -->
<div>
<el-dialog :visible.sync="dialogVisible" v-if='dialogVisible' :title="dialogType==='edit'?'编辑源':'新增源'" :append-to-body="true" @close="closeDialog">
@@ -103,12 +109,11 @@
</span>
</el-dialog>
</div>
</div>
</div>
</template>
<script>
import { mapMutations } from 'vuex'
import { sites } from '../lib/dexie'
import { sites, setting } from '../lib/dexie'
import zy from '../lib/site/tools'
import { remote } from 'electron'
import { sites as defaultSites } from '../lib/dexie/initData'
@@ -129,7 +134,7 @@ export default {
api: '',
download: '',
group: '',
isActive: 1
isActive: true
},
siteGroup: [],
rules: {
@@ -138,18 +143,19 @@ export default {
],
api: [
{ required: true, message: 'API地址不能为空', trigger: 'blur' }
],
download: [
{ required: false, trigger: 'blur' }
]
},
enableBatchEdit: false,
batchGroupName: '',
batchIsActive: 1,
batchIsActive: true,
shiftDown: false,
selectionBegin: '',
selectionEnd: '',
multipleSelection: [],
tableKey: 1,
checkAllSiteLoading: false,
editeOldkey: ''
checkAllSitesLoading: false,
checkProgress: 0,
stopFlag: false,
editOldkey: ''
}
},
computed: {
@@ -161,14 +167,6 @@ export default {
this.SET_SETTING(val)
}
},
editSites: {
get () {
return this.$store.getters.getEditSites
},
set (val) {
this.SET_EDITSITES(val)
}
},
getFilters () {
const groups = [...new Set(this.sites.map(site => site.group))]
var filters = []
@@ -182,15 +180,48 @@ export default {
return filters
}
},
watch: {
enableBatchEdit () {
if (this.checkAllSitesLoading) {
this.$message.info('正在检测, 请勿操作.')
this.enableBatchEdit = false
}
}
},
methods: {
...mapMutations(['SET_SETTING', 'SET_EDITSITES']),
filterHandle (value, row) {
return row.group === value
...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
const start = Math.min(this.selectionBegin, this.selectionEnd) - 1
const end = Math.max(this.selectionBegin, this.selectionEnd)
const selections = this.sites.slice(start, end)
this.$nextTick(() => {
selections.forEach(e => this.$refs.editSitesTable.toggleRowSelection(e, true))
})
this.selectionBegin = this.selectionEnd = ''
return
}
if (selection.includes(row)) {
this.selectionBegin = row.id
} else {
this.selectionBegin = ''
}
},
handleSelectionChange (rows) {
this.multipleSelection = rows
},
handleSortChange (column, prop, order) {
if (this.checkAllSitesLoading) {
this.$message.info('正在检测, 请勿操作.')
return false
}
this.updateDatabase(this.sites)
},
saveBatchEdit () {
@@ -205,13 +236,7 @@ export default {
getSites () {
sites.all().then(res => {
this.sites = res
this.editSites = {
sites: res
}
})
for (const i of this.sites) {
delete i.status
}
},
getSitesGroup () {
const arr = []
@@ -223,6 +248,10 @@ export default {
this.siteGroup = arr
},
addSite () {
if (this.checkAllSitesLoading) {
this.$message.info('正在检测, 请勿操作.')
return false
}
this.getSitesGroup()
this.dialogType = 'new'
this.dialogVisible = true
@@ -232,26 +261,26 @@ export default {
api: '',
download: '',
group: '',
isActive: 1
isActive: true
}
},
editSite (siteInfo) {
this.getSitesGroup()
if (this.checkAllSiteLoading) {
if (this.checkAllSitesLoading) {
this.$message.info('正在检测, 请勿操作.')
return false
}
this.getSitesGroup()
this.dialogType = 'edit'
this.dialogVisible = true
this.siteInfo = siteInfo
this.editeOldkey = siteInfo.key
this.editOldkey = siteInfo.key
},
closeDialog () {
this.dialogVisible = false
this.getSites()
},
removeEvent (e) {
if (this.checkAllSiteLoading) {
if (this.checkAllSitesLoading) {
this.$message.info('正在检测, 请勿操作.')
return false
}
@@ -261,19 +290,8 @@ export default {
this.$message.warning('删除源失败, 错误信息: ' + err)
})
},
listUpdatedEvent () {
sites.clear().then(res1 => {
// 重新排序
var id = 1
this.sites.forEach(element => {
element.id = id
sites.add(element)
id += 1
})
})
},
checkSiteKey (e) {
if (this.dialogType === 'edit' && this.editeOldkey === this.siteInfo.key) {
if (this.dialogType === 'edit' && this.editOldkey === this.siteInfo.key) {
return true
} else {
for (const i of this.sites) {
@@ -316,7 +334,7 @@ export default {
this.dialogVisible = false
this.getSites()
})
this.editeOldkey = ''
this.editOldkey = ''
},
exportSites () {
this.getSites()
@@ -339,6 +357,10 @@ export default {
})
},
importSites () {
if (this.checkAllSitesLoading) {
this.$message.info('正在检测, 请勿操作.')
return false
}
const options = {
filters: [
{ name: 'JSON file', extensions: ['json'] },
@@ -356,7 +378,7 @@ export default {
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 = 1
ele.isActive = true
}
if (ele.group === undefined) {
ele.group = '导入'
@@ -373,11 +395,16 @@ export default {
})
},
resetSitesEvent () {
this.stopFlag = true
if (this.checkAllSitesLoading) {
this.$message.info('部分检测还未完全终止, 请稍等...')
return
}
sites.clear().then(sites.bulkAdd(defaultSites).then(this.getSites()))
this.$message.success('重置源成功')
},
moveToTopEvent (i) {
if (this.checkAllSiteLoading) {
if (this.checkAllSitesLoading) {
this.$message.info('正在检测, 请勿操作.')
return false
}
@@ -385,12 +412,13 @@ export default {
this.updateDatabase()
},
syncTableData () {
if (this.$refs.editSitesTable.tableData && this.$refs.editSitesTable.tableData.length === this.sites.length) {
if (this.$refs.editSitesTable.tableData) {
this.sites = this.$refs.editSitesTable.tableData
}
},
isActiveChangeEvent (row) {
this.updateDatabase()
sites.remove(row.id)
sites.add(row)
},
resetId (inArray) {
var id = 1
@@ -411,10 +439,18 @@ export default {
sites.bulkAdd(this.sites).then(this.getSites())
})
},
removeAllSites () {
sites.clear().then(this.getSites())
removeSelectedSites () {
this.multipleSelection.forEach(e => sites.remove(e.id))
this.$refs.editSitesTable.clearFilter()
this.getSites()
this.updateDatabase()
this.enableBatchEdit = false
},
rowDrop () {
if (this.checkAllSitesLoading) {
this.$message.info('正在检测, 请勿操作.')
return false
}
const tbody = document.getElementById('sites-table').querySelector('.el-table__body-wrapper tbody')
var _this = this
Sortable.create(tbody, {
@@ -426,26 +462,40 @@ export default {
})
},
async checkAllSite () {
this.checkAllSiteLoading = true
for (const i of this.sites) {
i.status = ''
this.tableKey = Math.random()
const flag = await zy.check(i.key)
if (flag) {
i.status = '可用'
} else {
i.status = '失效'
i.isActive = 0
}
this.tableKey = Math.random()
this.checkAllSitesLoading = true
this.stopFlag = false
this.checkProgress = 0
const uncheckedList = this.sites.filter(e => e.status === undefined || e.status === ' ') // 未检测过的优先
const other = this.sites.filter(e => !uncheckedList.includes(e))
await Promise.all(uncheckedList.map(site => this.checkSingleSite(site)))
await Promise.all(other.map(site => this.checkSingleSite(site))).then(res => {
this.checkAllSitesLoading = false
this.getSites()
})
},
async checkSingleSite (row) {
row.status = ' '
if (this.stopFlag) {
this.checkProgress += 1
return row.status
}
this.checkAllSiteLoading = false
this.updateDatabase()
const flag = await zy.check(row.key)
this.checkProgress += 1
if (flag) {
row.status = '可用'
} else {
row.status = '失效'
row.isActive = false
}
sites.remove(row.id)
sites.add(row)
return row.status
}
},
mounted () {
this.rowDrop()
this.checkAllSiteLoading = false
addEventListener('keydown', code => { if (code.keyCode === 16) this.shiftDown = true })
addEventListener('keyup', code => { if (code.keyCode === 16) this.shiftDown = false })
},
created () {
this.getSites()

View File

@@ -1,43 +1,70 @@
<template>
<div class="film">
<div class="header">
<div class="zy-select" @mouseleave="show.site = false">
<div class="vs-placeholder" @click="show.site = true">{{site.name}}</div>
<div class="vs-options" v-show="show.site">
<ul class="zy-scroll" style="max-height: 600px;">
<li :class="site.key === i.key ? 'active' : ''" v-for="i in sites" :key="i.key" @click="siteClick(i)">{{ i.name }}</li>
</ul>
</div>
</div>
<div class="zy-select" @mouseleave="show.classList = false" v-show="show.class">
<div class="vs-placeholder" @click="show.classList = true">{{type.name}}</div>
<div class="vs-options" v-show="show.classList">
<ul class="zy-scroll" style="max-height: 600px;">
<li :class="type.tid === i.tid ? 'active' : ''" v-for="i in classList" :key="i.tid" @click="classClick(i)">{{ i.name | classNameFilter }}</li>
</ul>
</div>
</div>
<div class="zy-select" @mouseleave="show.search = false">
<div class="vs-input" @click="show.search = true"><input v-model.trim="searchTxt" type="text" placeholder="搜索" @keyup.enter="searchEvent(searchTxt)"></div>
<div class="vs-options" v-show="show.search">
<ul class="zy-scroll" style="max-height: 600px">
<li v-for="(i, j) in searchList" :key="j" @click="searchEvent(i.keywords)">{{i.keywords}}</li>
<li v-show="searchList.length >= 1" @click="clearSearch">清空历史记录</li>
</ul>
</div>
</div>
<div class="listpage" id="film">
<div class="listpage-header" id="film-header">
<el-select v-model="selectedSiteName" size="small" placeholder="源站" :popper-append-to-body="false" popper-class="popper" @change="siteClick">
<el-option
v-for="item in sites"
:key="item.key"
:label="item.name"
:value="item.name">
</el-option>
</el-select>
<el-select v-model="selectedClassName" size="small" placeholder="类型" :popper-append-to-body="false" popper-class="popper" @change="classClick" v-show="show.class">
<el-option
v-for="item in classList"
:key="item.tid"
:label="item.name"
:value="item.name">
</el-option>
</el-select>
<el-autocomplete
clearable
size="small"
v-model.trim="searchTxt"
value-key="keywords"
:fetch-suggestions="querySearch"
:popper-append-to-body="false"
popper-class="popper"
placeholder="搜索"
@keyup.enter.native="searchAndRecord"
@select="searchEvent"
@change="searchChangeEvent">
<el-select v-model="searchGroup" size="small" slot="prepend"
:popper-append-to-body="false"
popper-class="popper"
default-first-option placeholder="请选择"
@change="searchEvent">
<el-option
v-for="item in searchGroups"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select>
<!--方便触屏-->
<el-button icon="el-icon-search" @click.stop="searchEvent" slot="append" />
</el-autocomplete>
</div>
<div class="body zy-scroll" infinite-wrapper>
<div class="body-box" v-show="!show.find">
<div class="show-img" v-if="setting.view === 'picture'">
<Waterfall ref="waterfall" :list="list" :gutter="20" :width="240"
:breakpoints="{ 1200: { rowPerView: 4 } }"
animationEffect="fadeInUp"
<div class="listpage-body" id="film-body" infinite-wrapper>
<div class="show-picture" v-if="setting.view === 'picture' && !show.find">
<Waterfall ref="filmWaterfall" :list="list" :gutter="20" :width="240"
: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" v-show="!setting.excludeR18Films || !containsR18Keywords(props.data.type)">
<div class="img">
<img style="width: 100%" :src="props.data.pic" alt="" @load="$refs.waterfall.refresh()" @click="detailEvent(site, props.data)">
<img style="width: 100%" :src="props.data.pic" alt="" @load="$refs.filmWaterfall.refresh()" @click="detailEvent(site, props.data)">
<div class="operate">
<div class="operate-wrap">
<span class="o-play" @click="playEvent(site, props.data)">播放</span>
@@ -48,6 +75,7 @@
</div>
<div class="name" @click="detailEvent(site, props.data)">{{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>
@@ -56,62 +84,152 @@
</template>
</Waterfall>
<infinite-loading force-use-infinite-wrapper :identifier="infiniteId" @infinite="infiniteHandler"></infinite-loading>
</div>
<div class="show-table" v-if="setting.view === 'table'">
<div class="zy-table">
<div class="tBody">
<ul>
<li v-for="(i, j) in list" :key="j" @click="detailEvent(site, i)" v-show="!setting.excludeR18Films || !containsR18Keywords(i.type)">
<span class="name">{{i.name}}</span>
<span class="type">{{i.type}}</span>
<span class="time">{{i.year}}</span>
<span class="note">{{i.note}}</span>
<span class="last">{{i.last}}</span>
<span class="operate">
<span class="btn" @click.stop="playEvent(site, i)">播放</span>
<span class="btn" @click.stop="starEvent(site, i)">收藏</span>
<span class="btn" @click.stop="shareEvent(site, i)">分享</span>
<span class="btn" @click.stop="downloadEvent(site, i)">下载</span>
</span>
</li>
</ul>
<infinite-loading force-use-infinite-wrapper :identifier="infiniteId" @infinite="infiniteHandler"></infinite-loading>
</div>
</div>
</div>
</div>
<div class="body-box" v-show="show.find">
<div class="show-table">
<div class="zy-table">
<div class="tBody zy-scroll">
<ul>
<li v-for="(i, j) in searchContents" :key="j" @click="detailEvent(i.site, i)">
<span class="name">{{i.name}}</span>
<span class="info">{{i.site.name}}</span>
<span class="info">{{i.director}}</span>
<span class="info">{{i.type}}</span>
<span class="info">{{i.area}}</span>
<span class="info">{{i.lang}}</span>
<span class="info">{{i.year}}</span>
<span class="info">{{i.note}}</span>
<span class="operate">
<span class="btn" @click.stop="playEvent(i.site, i)">播放</span>
<span class="btn" @click.stop="starEvent(i.site, i)">收藏</span>
<span class="btn" @click.stop="shareEvent(i.site, i)">分享</span>
<span class="btn" @click.stop="downloadEvent(i.site, i)">下载</span>
</span>
</li>
</ul>
</div>
</div>
</div>
<div class="show-table" v-if="setting.view === 'table' && !show.find">
<el-table
size="mini"
:data="list.filter(res => !setting.excludeR18Films || !containsR18Keywords(res.type))"
height="100%"
:empty-text="statusText"
@row-click="(row) => detailEvent(site, row)"
style="width: 100%">
<el-table-column
prop="name"
label="片名">
</el-table-column>
<el-table-column
prop="type"
label="类型"
width="100">
</el-table-column>
<el-table-column
prop="year"
label="上映"
align="center"
width="100">
</el-table-column>
<el-table-column
prop="area"
label="地区"
width="100">
</el-table-column>
<el-table-column
prop="lang"
label="语言"
width="100">
</el-table-column>
<el-table-column
prop="note"
label="备注"
width="120">
</el-table-column>
<el-table-column
prop="last"
label="最近更新"
:formatter="dateFormat"
align="left">
</el-table-column>
<el-table-column
label="操作"
header-align="center"
align="right"
width="200">
<template slot-scope="scope">
<el-button @click.stop="playEvent(site, scope.row)" type="text">播放</el-button>
<el-button @click.stop="starEvent(site, scope.row)" type="text">收藏</el-button>
<el-button @click.stop="shareEvent(site, scope.row)" type="text">分享</el-button>
<el-button @click.stop="downloadEvent(site, scope.row)" type="text">下载</el-button>
</template>
</el-table-column>
<infinite-loading
slot="append"
:identifier="infiniteId"
@infinite="infiniteHandler"
force-use-infinite-wrapper=".el-table__body-wrapper">
<div slot="no-more">数据量过少时请重复操作一次,以防网站抽风</div>
</infinite-loading>
</el-table>
</div>
<div class="show-table" v-show="show.find">
<el-table size="mini"
ref="searchResultTable"
:data="searchContents.filter(res => !setting.excludeR18Films || (res.type !== undefined && !containsR18Keywords(res.type)))"
height="100%"
:empty-text="statusText"
@filter-change="filterChange"
@row-click="(row) => detailEvent(row.site, row)"
style="width: 100%">
<el-table-column
sortable
:sort-method="(a , b) => sortByLocaleCompare(a.name, b.name)"
prop="name"
label="片名">
</el-table-column>
<el-table-column v-if="searchGroup !== '站内'"
sortable
:sort-method="(a , b) => sortByLocaleCompare(a.site.name, b.site.name)"
:filters="getFilters('siteName')"
:filter-method="(value, row, column) => { this.currentColumn = column; return value === row.site.name }"
prop="site"
label="源站"
width="120">
<template slot-scope="scope">
<span>{{ scope.row.site.name }}</span>
</template>
</el-table-column>
<el-table-column
prop="type"
:filters="getFilters('type')"
:filter-method="(value, row, column) => { this.currentColumn = column; return value === row.type }"
label="类型"
width="90">
</el-table-column>
<el-table-column
sortable
prop="year"
label="上映"
width="90">
</el-table-column>
<el-table-column
prop="area"
:filters="getFilters('area')"
:filter-method="(value, row, column) => { this.currentColumn = column; return value === row.area }"
label="地区"
width="90">
</el-table-column>
<el-table-column
:filters="getFilters('lang')"
:filter-method="(value, row, column) => { this.currentColumn = column; return value === row.lang }"
prop="lang"
label="语言"
width="70">
</el-table-column>
<el-table-column
sortable
prop="note"
label="备注"
width="120">
</el-table-column>
<el-table-column
label="操作"
header-align="center"
align="right"
width="200">
<template slot-scope="scope">
<el-button @click.stop="playEvent(scope.row.site, scope.row)" type="text">播放</el-button>
<el-button @click.stop="starEvent(scope.row.site, scope.row)" type="text">收藏</el-button>
<el-button @click.stop="shareEvent(scope.row.site, scope.row)" type="text">分享</el-button>
<el-button @click.stop="downloadEvent(scope.row.site, scope.row)" type="text">下载</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</template>
<script>
import { mapMutations } from 'vuex'
import { star, history, search, sites } from '../lib/dexie'
import { star, history, search, sites, setting } from '../lib/dexie'
import zy from '../lib/site/tools'
import Waterfall from 'vue-waterfall-plugin'
import InfiniteLoading from 'vue-infinite-loading'
@@ -125,19 +243,25 @@ export default {
site: false,
class: false,
classList: false,
search: false,
find: false
},
sites: [],
site: {},
classList: [],
type: {},
selectedClassName: '最新',
selectedSiteName: '',
pagecount: 0,
list: [],
statusText: ' ',
infiniteId: +new Date(),
searchID: 0,
searchList: [],
searchTxt: '',
searchContents: [],
currentColumn: '',
searchGroup: '',
searchGroups: [],
// 福利片关键词
r18KeyWords: ['伦理', '论理', '倫理', '福利', '激情', '理论', '写真', '情色', '美女', '街拍', '赤足', '性感', '里番']
}
@@ -179,16 +303,22 @@ export default {
this.SET_SHARE(val)
}
},
setting () {
return this.$store.getters.getSetting
setting: {
get () {
return this.$store.getters.getSetting
},
set (val) {
this.SET_SETTING(val)
}
},
sitesList () {
return this.$store.getters.getEditSites.sites // 需要监听的数据
filterSettings () {
return this.$store.getters.getSetting.excludeR18Films // 需要监听的数据
}
},
filters: {
classNameFilter: (name) => {
return name.replace(/[^\u4e00-\u9fa5]/gi, '')
const clsName = name.toString()
return clsName.replace(/[^\u4e00-\u9fa5]/gi, '')
}
},
watch: {
@@ -196,36 +326,64 @@ export default {
this.changeView()
},
searchTxt () {
this.searchChangeEvent()
if (this.searchTxt === '清除历史记录...') {
this.clearSearchHistory()
this.searchTxt = ''
this.searchChangeEvent()
}
},
sitesList () {
this.getAllsites()
filterSettings () {
this.siteClick(this.site.name)
}
},
methods: {
...mapMutations(['SET_VIEW', 'SET_DETAIL', 'SET_VIDEO', 'SET_SHARE']),
siteClick (e) {
this.list = []
this.site = e
this.show.site = false
this.show.class = false
if (this.searchTxt.length > 0) {
this.searchSingleSiteEvent(this.site, this.searchTxt)
...mapMutations(['SET_VIEW', 'SET_DETAIL', 'SET_VIDEO', 'SET_SHARE', 'SET_SETTING']),
sortByLocaleCompare (a, b) {
return a.localeCompare(b, 'zh')
},
dateFormat (row, column) {
var date = row[column.property]
if (date === undefined) {
return ''
}
return date.split(/\s/)[0]
},
getFilters (column) {
const searchContents = this.searchContents.filter(res => !this.setting.excludeR18Films || (res.type !== undefined && !this.containsR18Keywords(res.type)))
if (column === 'siteName') return [...new Set(searchContents.map(row => row.site.name))].map(e => { return { text: e, value: e } }) // 有方法合并这两行吗?
return [...new Set(searchContents.map(row => row[column]))].map(e => { return { text: e, value: e } })
},
filterChange (filters) {
// 一次只能一列
if (Object.values(filters)[0].length) {
const otherColumns = this.$refs.searchResultTable.columns.filter(col => col.id !== this.currentColumn.id)
otherColumns.forEach(col => { col.filterable = false })
} else {
const filterLabels = ['源站', '类型', '地区', '语言']
const columns = this.$refs.searchResultTable.columns.filter(col => filterLabels.includes(col.label))
columns.forEach(col => { col.filterable = true })
}
},
siteClick (siteName) {
this.list = []
this.site = this.sites.find(x => x.name === siteName)
if (this.searchTxt.length > 0 && this.searchGroup === '站内') {
this.searchEvent()
} else {
this.searchTxt = ''
this.show.find = false
this.classList = []
this.type = {}
this.getClass().then(res => {
if (res) {
this.show.class = true
this.infiniteId += 1
}
this.infiniteId += 1
this.classClick(this.classList[0].name)
})
}
},
classClick (e) {
classClick (className) {
this.show.classList = false
this.list = []
this.type = e
this.type = this.classList.find(x => x.name === className)
this.getPage().then(res => {
if (res) {
this.infiniteId += 1
@@ -285,8 +443,10 @@ export default {
const key = this.site.key
const type = this.type.tid
const page = this.pagecount
if (page < 1) {
this.statusText = ' '
if (key && page < 1) { // OK资源前几类硬是去不掉
$state.complete()
this.statusText = '暂无数据'
return false
}
zy.list(key, page, type).then(res => {
@@ -306,6 +466,7 @@ export default {
$state.loaded()
} else {
$state.complete()
this.statusText = '暂无数据'
}
})
},
@@ -324,6 +485,9 @@ export default {
} else {
this.video = { key: site.key, info: { id: e.id, name: e.name, index: 0, site: site } }
}
zy.detail(site.key, e.id).then(detailRes => {
this.video.detail = detailRes
})
this.view = 'Play'
},
async starEvent (site, e) {
@@ -331,18 +495,17 @@ export default {
if (db) {
this.$message.info('已存在')
} else {
const docs = {
key: site.key,
ids: e.id,
site: site,
name: e.name,
type: e.type,
year: e.year,
last: e.last,
note: e.note
}
star.add(docs).then(res => {
this.$message.success('收藏成功')
zy.detail(site.key, e.id).then(detailRes => {
const docs = {
key: site.key,
ids: e.id,
site: site,
name: e.name,
detail: detailRes
}
star.add(docs).then(res => {
this.$message.success('收藏成功')
})
})
}
},
@@ -353,9 +516,9 @@ export default {
info: e
}
},
downloadEvent (site, e) {
zy.download(site.key, e.id).then(res => {
if (res && res.length > 0 && res.dl && res.dl.dd) {
downloadEvent (site, row) {
zy.download(site.key, row.id).then(res => {
if (res && res.length > 0) {
const text = res.dl.dd._t
if (text) {
const list = text.split('#')
@@ -371,7 +534,7 @@ export default {
}
} else {
let m3u8List = []
const dd = res.dl.dd
const dd = row.dl.dd
const type = Object.prototype.toString.call(dd)
if (type === '[object Array]') {
for (const i of dd) {
@@ -382,7 +545,7 @@ export default {
} else {
m3u8List = dd._t.split('#')
}
let downloadUrl = e.name + '\n'
let downloadUrl = row.name + '\n'
for (const i of m3u8List) {
const url = encodeURI(i.split('$')[1])
downloadUrl += (url + '\n')
@@ -394,76 +557,107 @@ export default {
},
changeView () {
if (this.view === 'Film') {
this.getAllSites()
if (this.setting.view === 'picture') {
this.$refs.waterfall.refresh()
if (this.$refs.filmWaterfall) {
this.$refs.filmWaterfall.refresh()
}
this.getPage().then(() => {
this.infiniteId += 1
})
}
this.getPage().then(() => {
this.infiniteId += 1
})
}
},
getAllSearch () {
search.all().then(res => {
this.searchList = res.reverse()
})
querySearch (queryString, cb) {
if (this.searchList.length === 0) return
var searchList = this.searchList.slice(0, -1)
var results = queryString ? searchList.filter(this.createFilter(queryString)) : this.searchList
// 调用 callback 返回建议列表的数据
cb(results)
},
searchEvent (wd) {
if (this.setting.searchAllSites) {
this.searchAllSitesEvent(this.sites, wd)
} else {
this.searchSingleSiteEvent(this.site, wd)
createFilter (queryString) {
return (item) => {
return (item.keywords.toLowerCase().indexOf(queryString.toLowerCase()) === 0)
}
},
searchAllSitesEvent (sites, wd) {
this.searchTxt = wd
this.searchContents = []
this.pagecount = 0
this.show.search = false
this.show.find = true
addSearchRecord () {
const wd = this.searchTxt
if (wd) {
search.find({ keywords: wd }).then(res => {
if (!res) {
search.add({ keywords: wd })
}
this.getAllSearch()
this.getSearchHistory()
})
sites.forEach(site => {
}
},
clearSearchHistory () {
search.clear().then(res => {
this.getSearchHistory()
})
},
getSearchHistory () {
search.all().then(res => {
this.searchList = res.reverse()
this.searchList.push({ id: this.searchList.length + 1, keywords: '清除历史记录...' })
})
},
searchEvent () {
const wd = this.searchTxt
if (this.setting.searchGroup !== this.searchGroup) {
this.setting.searchGroup = this.searchGroup
setting.update(this.setting)
}
if (!wd) return
this.searchID += 1
var searchSites = []
if (this.searchGroup === '站内') searchSites.push(this.site)
if (this.searchGroup === '全站') searchSites = this.sites
if (!searchSites.length) {
searchSites = this.sites.filter(site => site.group === this.searchGroup)
}
this.searchContents = []
this.pagecount = 0
this.show.find = true
this.show.class = false
this.statusText = ' '
if (wd) {
searchSites.forEach(site => {
const id = this.searchID
zy.search(site.key, wd).then(res => {
if (id !== this.searchID) return
const type = Object.prototype.toString.call(res)
if (type === '[object Array]') {
res.forEach(element => {
zy.detail(site.key, element.id).then(detailRes => {
detailRes.site = site
if (id !== this.searchID) return
this.searchContents.push(detailRes)
this.searchContents.sort(function (a, b) {
return a.site.id - b.site.id
})
this.statusText = '暂无数据'
})
})
}
if (type === '[object Object]') {
zy.detail(site.key, res.id).then(detailRes => {
detailRes.site = site
if (id !== this.searchID) return
this.searchContents.push(detailRes)
this.searchContents.sort(function (a, b) {
return a.site.id - b.site.id
})
this.statusText = '暂无数据'
})
}
})
})
} else {
this.show.find = false
this.getClass().then(res => {
if (res) {
this.infiniteId += 1
}
})
}
},
searchSingleSiteEvent (site, wd) {
var sites = []
sites.push(this.site)
this.searchAllSitesEvent(sites, wd)
},
clearSearch () {
search.clear().then(res => {
this.getAllSearch()
})
searchAndRecord () {
this.addSearchRecord()
this.searchEvent()
},
searchChangeEvent () {
if (this.searchTxt.length >= 1) {
@@ -472,130 +666,53 @@ export default {
this.show.class = true
this.searchContents = []
this.show.find = false
if (this.setting.view === 'picture') {
this.$refs.waterfall.refresh()
if (this.setting.view === 'picture' && this.$refs.filmWaterfall) {
this.$refs.filmWaterfall.refresh()
} else {
this.getClass().then(res => {
if (res) {
this.infiniteId += 1
}
})
}
}
},
getAllsites () {
getAllSites () {
sites.all().then(res => {
if (res.length <= 0) {
this.site = {}
this.type = {}
this.list = []
} else {
this.sites = res.filter((item, index, self) => {
return self.indexOf(item) >= 0 && item.isActive
})
this.site = this.sites[0]
this.siteClick(this.site)
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
}
}
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 })
})
}
},
created () {
this.getAllSearch()
this.getAllSites()
this.getSearchHistory()
},
mounted () {
window.addEventListener('resize', () => {
if (this.$refs.filmWaterfall && this.view === 'Film') {
this.$refs.filmWaterfall.resize()
this.$refs.filmWaterfall.refresh()
setTimeout(() => {
this.$refs.filmWaterfall.refresh()
}, 500)
}
}, false)
}
}
</script>
<style lang="scss" scoped>
.film{
height: calc(100% - 40px);
width: 100%;
display: flex;
flex-direction: column;
.header{
height: 30px;
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
z-index: 10;
}
.body{
margin-top: 20px;
flex: 1;
width: 100%;
border-radius: 0 0 5px 5px;
overflow-y: scroll;
&::-webkit-scrollbar{
width: 5px;
height: 1px;
}
&::-webkit-scrollbar-thumb {
border-radius: 10px;
position: absolute;
}
&::-webkit-scrollbar-track {
border-radius: 10px;
position: absolute;
}
.body-box{
height: 100%;
width: 100%;
}
.show-img{
height: 100%;
width: 100%;
padding: 10px;
.card{
border-radius: 6px;
overflow: hidden;
.img{
position: relative;
min-height: 40px;
img{
width: 100%;
height: auto;
cursor: pointer;
}
.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;
cursor: pointer;
}
.info{
display: flex;
justify-content: space-between;
font-size: 12px;
padding: 10px;
}
&:hover{
.operate{
display: block;
}
}
}
}
}
}
</style>

View File

@@ -1,12 +1,13 @@
<template>
<div class="listpage" id="history">
<div class="listpage-content">
<div class="listpage-header">
<div class="listpage-header" id="history-header">
<el-switch v-model="viewMode" active-text="海报" active-value="picture" inactive-text="列表" inactive-value="list" @change="updateViewMode"></el-switch>
<el-button @click.stop="exportHistory" icon="el-icon-upload2">导出</el-button>
<el-button @click.stop="importHistory" icon="el-icon-download">导入</el-button>
<el-button @click.stop="clearAllHistory" icon="el-icon-delete-solid">清空</el-button>
</div>
<div class="listpage-body" id="history-table">
</div>
<div class="listpage-body" id="history-body">
<div class="show-table" id="history-table" v-show="viewMode === 'list'">
<el-table size="mini" fit height="100%" :data="history" row-key="id" @row-click="detailEvent">
<el-table-column
prop="name"
@@ -22,35 +23,87 @@
</el-table-column>
<el-table-column
prop="index"
width="120"
width="180"
label="观看至">
<template slot-scope="scope">
<span>{{ scope.row.index + 1 }}</span>
<span v-if="scope.row.detail && scope.row.detail.m3u8List && scope.row.detail.m3u8List.length > 1">
{{ scope.row.index + 1 }}({{scope.row.detail.m3u8List.length}})
</span>
</template>
</el-table-column>
<el-table-column v-if="history.some(e => e.time)"
width="150"
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>
</template>
</el-table-column>
<el-table-column
label="操作"
header-align="right"
width="200"
header-align="center"
align="right">
<template slot-scope="scope">
<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="removeHistoryItem(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-show="viewMode === 'picture'">
<Waterfall ref="historyWaterfall" :list="history" :gutter="20" :width="240"
:breakpoints="{
1200: { //当屏幕宽度小于等于1200
rowPerView: 4,
},
800: { //当屏幕宽度小于等于800
rowPerView: 3,
},
500: { //当屏幕宽度小于等于500
rowPerView: 2,
}
}"
animationDuration="0.5s"
backgroundColor="rgba(0, 0, 0, 0)">
<template slot="item" slot-scope="props">
<div class="card">
<div class="img">
<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">
<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>
<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))}}
</span>
<span v-if="props.data.detail && props.data.detail.m3u8List !== undefined && props.data.detail.m3u8List.length > 1">
{{ props.data.index + 1 }}({{props.data.detail.m3u8List.length}})
</span>
</div>
</div>
</template>
</Waterfall>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapMutations } from 'vuex'
import { history, sites } from '../lib/dexie'
import { history, sites, setting } from '../lib/dexie'
import zy from '../lib/site/tools'
import Sortable from 'sortablejs'
import { remote } from 'electron'
import fs from 'fs'
import Waterfall from 'vue-waterfall-plugin'
const { clipboard } = require('electron')
export default {
@@ -58,9 +111,13 @@ export default {
data () {
return {
history: [],
sites: []
sites: [],
viewMode: setting.historyViewMode
}
},
components: {
Waterfall
},
computed: {
view: {
get () {
@@ -99,10 +156,16 @@ export default {
view () {
this.getAllhistory()
this.getAllsites()
if (this.$refs.historyWaterfall) {
this.$refs.historyWaterfall.refresh()
}
}
},
methods: {
...mapMutations(['SET_VIEW', 'SET_DETAIL', 'SET_VIDEO', 'SET_SHARE']),
fmtMSS (s) {
return (s - (s %= 60)) / 60 + (s > 9 ? ':' : ':0') + s
},
detailEvent (e) {
this.detail = {
show: true,
@@ -120,6 +183,9 @@ export default {
} else {
this.video = { key: e.site, info: { id: e.ids, name: e.name, index: 0 } }
}
zy.detail(e.site, e.ids).then(detailRes => {
this.video.detail = detailRes
})
this.view = 'Play'
},
shareEvent (e) {
@@ -230,7 +296,7 @@ export default {
return site.name
}
},
removeHistoryItem (e) {
deleteEvent (e) {
history.remove(e.id).then(res => {
this.getAllhistory()
}).catch(err => {
@@ -257,13 +323,34 @@ export default {
_this.updateDatabase(_this.history)
}
})
},
getViewMode () {
setting.find().then(res => {
this.viewMode = res.historyViewMode
})
},
updateViewMode () {
setting.find().then(res => {
res.historyViewMode = this.viewMode
setting.update(res)
})
}
},
mounted () {
this.rowDrop()
window.addEventListener('resize', () => {
if (this.$refs.historyWaterfall && this.view === 'History') {
this.$refs.historyWaterfall.resize()
this.$refs.historyWaterfall.refresh()
setTimeout(() => {
this.$refs.historyWaterfall.refresh()
}, 500)
}
}, false)
},
created () {
this.getAllhistory()
this.getViewMode()
}
}
</script>

View File

@@ -1,24 +1,27 @@
<template>
<div class="listpage" id="IPTV">
<div class="listpage-content">
<div class="listpage-header" v-show="!enableBatchEdit">
<div class="listpage" id="iptv">
<div class="listpage-header" id="iptv-header" v-show="!enableBatchEdit">
<el-switch v-model="enableBatchEdit" active-text="批处理分组"></el-switch>
<el-button @click.stop="exportChannels" icon="el-icon-upload2" >导出</el-button>
<el-button @click.stop="importChannels" icon="el-icon-download">导入</el-button>
<el-button @click.stop="removeAllChannels" icon="el-icon-delete-solid">清空</el-button>
<el-button @click="checkAllChannels" icon="el-icon-refresh" :loading="checkAllChannelsLoading">检测{{ this.checkAllChannelsLoading ? this.checkProgress + '/' + this.iptvList.length : '' }}</el-button>
<el-button @click.stop="resetChannelsEvent" icon="el-icon-refresh-left">重置</el-button>
</div>
<div class="listpage-header" v-show="enableBatchEdit">
</div>
<div class="listpage-header" id="iptv-header" v-show="enableBatchEdit">
<el-switch v-model="enableBatchEdit" active-text="批处理分组"></el-switch>
<el-input placeholder="新组名" v-model="batchGroupName"></el-input>
<el-switch v-model="batchIsActive" active-text="启用"></el-switch>
<el-button type="primary" icon="el-icon-edit" @click.stop="saveBatchEdit">保存</el-button>
</div>
<div class="listpage-body" id="iptv-table">
<el-button @click.stop="removeSelectedChannels" icon="el-icon-delete-solid">删除</el-button>
</div>
<div class="listpage-body" id="iptv-table">
<div class="show-table" id="iptv-table">
<el-table
ref="iptvTable"
size="mini" fit height="100%" row-key="id"
:data="filteredTableData"
@row-click="playEvent"
@select="selectionCellClick"
@selection-change="handleSelectionChange"
@sort-change="handleSortChange">>
<el-table-column
@@ -39,27 +42,55 @@
</template>
</el-table-column>
<el-table-column
sort-by="['group', 'name']"
prop="isActive"
width="120"
align="center"
:filters = "[{text:'启用', value: true}, {text:'停用', value: false}]"
:filter-method="(value, row) => value === row.isActive"
label="启用">
<template slot-scope="scope">
<el-switch
v-model="scope.row.isActive"
@click.native.stop='isActiveChangeEvent(scope.row)'>
</el-switch>
</template>
</el-table-column>
<el-table-column
sortable
:sort-method="sortByGroup"
:sort-method="(a , b) => sortByLocaleCompare(a.group, b.group)"
prop="group"
label="分组"
:filters="getFilters"
:filter-method="filterHandle"
:filter-method="(value, row) => value === row.group"
filter-placement="bottom-end">
<template slot-scope="scope">
<el-button type="text">{{scope.row.group}}</el-button>
</template>
</el-table-column>
<el-table-column
label="状态"
sortable
:sort-by="['status']"
width="120">
<template slot-scope="scope">
<span v-if="scope.row.status === ' '">
<i class="el-icon-loading"></i>
检测中...
</span>
<span v-else>{{scope.row.status}}</span>
</template>
</el-table-column>
<el-table-column
label="操作"
header-align="right"
align="right">
align="right"
:width="200">
<template #header>
<span>总频道数:{{ iptvList.length }}</span>
</template>
<template slot-scope="scope">
<el-button @click.stop="moveToTopEvent(scope.row)" type="text">置顶</el-button>
<!-- 检测时先强制批量检测一遍,如果不强制直接单个检测时第一次不会显示“检测中”-->
<el-button size="mini" v-if="iptvList.every(channel => channel.status)" v-show="!checkAllChannelsLoading" @click.stop="checkSingleChannel(scope.row)" type="text">检测</el-button>
<el-button @click.stop="removeEvent(scope.row)" type="text">删除</el-button>
</template>
</el-table-column>
@@ -71,7 +102,8 @@
<script>
import { mapMutations } from 'vuex'
import { iptv, iptvSearch } from '../lib/dexie'
import { iptv as defaultSites } from '../lib/dexie/initData'
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'
@@ -84,7 +116,14 @@ export default {
searchRecordList: [],
enableBatchEdit: false,
batchGroupName: '',
batchIsActive: true,
shiftDown: false,
selectionBegin: '',
selectionEnd: '',
multipleSelection: [],
checkAllChannelsLoading: false,
checkProgress: 0,
stopFlag: false,
show: {
search: false
}
@@ -132,36 +171,62 @@ export default {
},
watch: {
view () {
this.getChannels()
if (this.view === 'IPTV') {
this.getChannels()
}
},
searchTxt () {
enableBatchEdit () {
if (this.checkAllChannelsLoading) {
this.$message.info('正在检测, 请勿操作.')
this.enableBatchEdit = false
}
}
},
methods: {
...mapMutations(['SET_VIEW', 'SET_DETAIL', 'SET_VIDEO', 'SET_SHARE']),
sortByGroup (a, b) {
return a.group.localeCompare(b.group, 'zh')
sortByLocaleCompare (a, b) {
return a.localeCompare(b, 'zh')
},
selectionCellClick (selection, row) {
if (this.shiftDown && this.selectionBegin !== '' && selection.includes(row)) {
this.selectionEnd = row.id
const start = Math.min(this.selectionBegin, this.selectionEnd) - 1
const end = Math.max(this.selectionBegin, this.selectionEnd)
const selections = this.iptvList.slice(start, end)
this.$nextTick(() => {
selections.forEach(e => this.$refs.iptvTable.toggleRowSelection(e, true))
})
this.selectionBegin = this.selectionEnd = ''
return
}
if (selection.includes(row)) {
this.selectionBegin = row.id
} else {
this.selectionBegin = ''
}
},
handleSelectionChange (rows) {
this.multipleSelection = rows
},
handleSortChange (column, prop, order) {
this.updateDatabase()
},
saveBatchEdit () {
if (this.multipleSelection && this.batchGroupName) {
this.multipleSelection.forEach(ele => {
ele.group = this.batchGroupName
})
if (this.checkAllChannelsLoading) {
this.$message.info('正在检测, 请勿操作.')
this.enableBatchEdit = false
}
this.updateDatabase()
},
playEvent (e) {
this.video = { iptv: { name: e.name, url: e.url } }
this.view = 'Play'
saveBatchEdit () {
this.multipleSelection.forEach(ele => {
if (this.batchGroupName) {
ele.group = this.batchGroupName
}
ele.isActive = this.batchIsActive
})
this.updateDatabase()
},
filterHandle (value, row) {
return row.group === value
playEvent (e) {
this.video = { iptv: { name: e.name, url: e.url, id: e.id } }
this.view = 'Play'
},
containsearchTxt (i) {
if (this.searchTxt) {
@@ -171,23 +236,16 @@ export default {
}
},
removeEvent (e) {
if (this.checkAllChannelsLoading) {
this.$message.info('正在检测, 请勿操作.')
return false
}
iptv.remove(e.id).then(res => {
this.getChannels()
}).catch(err => {
this.$message.warning('删除频道失败, 错误信息: ' + err)
})
},
listUpdatedEvent () {
iptv.clear().then(res1 => {
// 重新排序
var id = 1
this.iptvList.forEach(element => {
element.id = id
iptv.add(element)
id += 1
})
})
},
exportChannels () {
const options = {
filters: [
@@ -216,6 +274,10 @@ export default {
})
},
importChannels () {
if (this.checkAllChannelsLoading) {
this.$message.info('正在检测, 请勿操作.')
return false
}
const options = {
filters: [
{ name: 'm3u file', extensions: ['m3u', 'm3u8'] },
@@ -226,7 +288,7 @@ export default {
remote.dialog.showOpenDialog(options).then(result => {
if (!result.canceled) {
var docs = this.iptvList
var id = docs.length
var id = docs.length + 1
result.filePaths.forEach(file => {
if (file.endsWith('m3u') || file.endsWith('m3u8')) {
const parser = require('iptv-playlist-parser')
@@ -238,6 +300,7 @@ export default {
id: id,
name: ele.name,
url: ele.url,
isActive: true,
group: this.determineGroup(ele.name)
}
id += 1
@@ -254,6 +317,7 @@ export default {
id: id,
name: ele.name,
url: ele.url,
isActive: ele.isActive === undefined ? true : ele.isActive,
group: this.determineGroup(ele.name)
}
id += 1
@@ -263,9 +327,9 @@ export default {
}
})
// 获取name不重复的列表
const uniqueList = [...new Map(docs.map(item => [item.name, item])).values()]
// const uniqueList = [...new Map(docs.map(item => [item.name, item])).values()]
iptv.clear().then(res => {
iptv.bulkAdd(uniqueList).then(e => {
iptv.bulkAdd(docs).then(e => { // 支持导入同名频道,群里反馈
this.getChannels()
this.$message.success('导入成功')
})
@@ -289,19 +353,27 @@ export default {
}
},
resetChannelsEvent () {
this.resetChannels(defaultSites)
this.stopFlag = true
if (this.checkAllChannelsLoading) {
this.$message.info('部分检测还未完全终止, 请稍等...')
return
}
iptv.clear().then(iptv.bulkAdd(defaultChannels).then(this.getChannels()))
},
resetChannels (newSites) {
this.resetId(newSites)
iptv.clear().then(iptv.bulkAdd(newSites).then(this.getChannels()))
},
removeAllChannels () {
iptv.clear().then(res => {
this.getChannels()
})
removeSelectedChannels () {
this.multipleSelection.forEach(e => iptv.remove(e.id))
this.$refs.iptvTable.clearFilter()
this.getChannels()
this.updateDatabase()
this.enableBatchEdit = false
},
getChannels () {
iptv.all().then(res => {
res.forEach(ele => {
if (ele.isActive === undefined) {
ele.isActive = true
}
})
this.iptvList = res
})
},
@@ -328,11 +400,15 @@ export default {
}
},
moveToTopEvent (i) {
if (this.checkAllChannelsLoading) {
this.$message.info('正在检测, 请勿操作.')
return false
}
this.iptvList.sort(function (x, y) { return (x.name === i.name && x.url === i.url) ? -1 : (y.name === i.name && y.url === i.url) ? 1 : 0 })
this.updateDatabase()
},
syncTableData () {
if (this.$refs.iptvTable.tableData && this.$refs.iptvTable.tableData.length === this.iptvList.length) {
if (this.$refs.iptvTable.tableData) {
this.iptvList = this.$refs.iptvTable.tableData
}
},
@@ -351,6 +427,10 @@ export default {
})
},
rowDrop () {
if (this.checkAllChannelsLoading) {
this.$message.info('正在检测, 请勿操作.')
return false
}
const tbody = document.getElementById('iptv-table').querySelector('.el-table__body-wrapper tbody')
const _this = this
Sortable.create(tbody, {
@@ -360,10 +440,64 @@ export default {
_this.updateDatabase()
}
})
},
isActiveChangeEvent (row) {
iptv.remove(row.id)
iptv.add(row)
},
async checkAllChannels () {
this.checkAllChannelsLoading = true
this.stopFlag = false
this.checkProgress = 0
const uncheckedList = this.iptvList.filter(e => e.status === undefined || e.status === ' ') // 未检测过的优先
const other = this.iptvList.filter(e => !uncheckedList.includes(e))
await this.checkChannelList(uncheckedList)
await this.checkChannelList(other).then(res => {
this.checkAllChannelsLoading = false
this.getChannels()
})
},
async checkChannelList (channelList) {
var siteList = {}
channelList.forEach(channel => {
const site = channel.url.split('/')[2]
if (siteList[site]) {
siteList[site].push(channel)
} else {
siteList[site] = [channel]
}
})
await Promise.all(Object.values(siteList).map(site => this.checkSingleSite(site)))
},
async checkSingleSite (channelArray) {
for (const c of channelArray) {
if (this.stopFlag) return false
await this.checkSingleChannel(c)
}
},
async checkSingleChannel (row) {
row.status = ' '
if (this.stopFlag) {
this.checkProgress += 1
return row.status
}
const flag = await zy.checkChannel(row.url)
this.checkProgress += 1
if (flag) {
row.status = '可用'
} else {
row.status = '失效'
row.isActive = false
}
iptv.remove(row.id)
iptv.add(row)
return row.status
}
},
mounted () {
this.rowDrop()
addEventListener('keydown', code => { if (code.keyCode === 16) this.shiftDown = true })
addEventListener('keyup', code => { if (code.keyCode === 16) this.shiftDown = false })
},
created () {
this.getChannels()

View File

@@ -7,7 +7,7 @@
<div class="player">
<div id="xgplayer"></div>
</div>
<div class="more">
<div class="more" v-if="!video.iptv" :key="Boolean(video.iptv)">
<span class="zy-svg" @click="otherEvent" v-show="name !== ''">
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-labelledby="coloursIconTitle">
<title id="coloursIconTitle">换源</title>
@@ -84,6 +84,12 @@
<rect x="17" y="6" width="1" height="1"></rect>
</svg>
</span>
<span class="zy-svg" @click="showShortcutEvent" v-show="right.list.length > 0">
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-labelledby="sendIconTitle">
<title id="sendIconTitle">快捷键指南</title>
<polygon points="21.368 12.001 3 21.609 3 14 11 12 3 9.794 3 2.394"></polygon>
</svg>
</span>
<span class="zy-svg" @click="issueEvent" v-show="right.list.length > 0">
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-labelledby="infoIconTitle">
<title id="infoIconTitle">复制调试信息</title>
@@ -94,11 +100,44 @@
</span>
<span class="last-tip" v-if="!video.key && right.history.length > 0" @click="historyItemEvent(right.history[0])">上次播放到{{right.history[0].site}}{{right.history[0].name}} {{right.history[0].index+1}}</span>
</div>
<div class="more" v-if="video.iptv" :key="Boolean(video.iptv)">
<span class="zy-svg" @click="otherEvent" v-if="right.otherChannels.length">
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-labelledby="coloursIconTitle">
<title id="coloursIconTitle">换源</title>
<circle cx="12" cy="9" r="5"></circle>
<circle cx="9" cy="14" r="5"></circle>
<circle cx="15" cy="14" r="5"></circle>
</svg>
</span>
<span class="zy-svg" @click="miniEvent">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-labelledby="diamondIconTitle">
<title id="diamondIconTitle">精简模式</title>
<path d="M12 20L3 11M12 20L21 11M12 20L8 11M12 20L16 11M3 11L7 5M3 11H8M7 5L8 11M7 5H12M17 5L21 11M17 5L16 11M17 5H12M21 11H16M8 11H16M8 11L12 5M16 11L12 5"></path>
</svg>
</span>
<span class="zy-svg" @click="playWithExternalPalyerEvent">
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-labelledby="tvIconTitle">
<title id="tvIconTitle" >使用第三方播放器</title>
<polygon points="20 8 20 20 4 20 4 8"></polygon>
<polyline stroke-linejoin="round" points="8 4 12 7.917 16 4"></polyline>
</svg>
</span>
<span class="zy-svg" @click="showShortcutEvent">
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-labelledby="sendIconTitle">
<title id="sendIconTitle">快捷键指南</title>
<polygon points="21.368 12.001 3 21.609 3 14 11 12 3 9.794 3 2.394"></polygon>
</svg>
</span>
</div>
</div>
<transition name="slideX">
<div v-if="right.show" class="list">
<div class="list-top">
<span class="list-top-title">{{ right.type === 'list' ? '播放列表' : right.type === 'history' ? '历史记录' : '其他相同资源' }}</span>
<span class="list-top-title" v-if="right.type === 'list'">播放列表</span>
<span class="list-top-title" v-if="right.type === 'history'">历史记录</span>
<span class="list-top-title" v-if="right.type === 'shortcut'">快捷键指南{{ this.video.iptv ? '(直播时部分功能不可用)' : '' }}</span>
<span class="list-top-title" v-if="right.type === 'other'">同组其他源的视频</span>
<span class="list-top-title" v-if="right.type === 'otherChannels'">该频道其它源</span>
<span class="list-top-close zy-svg" @click="closeListEvent">
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-labelledby="closeIconTitle">
<title id="closeIconTitle">关闭</title>
@@ -107,19 +146,26 @@
</span>
</div>
<div class="list-body zy-scroll" :style="{overflowY:scroll? 'auto' : 'hidden',paddingRight: scroll ? '0': '5px' }" @mouseenter="scroll = true" @mouseleave="scroll = false">
<ul v-show="right.type === 'list'" class="list-item">
<li v-show="right.list.length > 0" @click="exportM3u8">导出</li>
<li v-show="right.list.length === 0">无数据</li>
<ul v-if="right.type === 'list'" class="list-item" v-on-clickaway="closeListEvent">
<li v-if="right.list.length > 0" @click="exportM3u8">导出</li>
<li v-if="right.list.length === 0">无数据</li>
<li @click="listItemEvent(j)" :class="video.info.index === j ? 'active' : ''" v-for="(i, j) in right.list" :key="j">{{i | ftName(j)}}</li>
</ul>
<ul v-show="right.type === 'history'" class="list-history">
<li v-show="right.history.length > 0" @click="clearAllHistory">清空</li>
<li v-show="right.history.length === 0">无数据</li>
<ul v-if="right.type === 'history'" class="list-history" v-on-clickaway="closeListEvent">
<li v-if="right.history.length > 0" @click="clearAllHistory">清空</li>
<li v-if="right.history.length === 0">无数据</li>
<li @click="historyItemEvent(m)" :class="video.info.id === m.ids ? 'active' : ''" v-for="(m, n) in right.history" :key="n"><span class="title" :title="'【' + m.site + '】' + m.name + ' 第' + (m.index+1) + '集'">【{{m.site}}】{{m.name}} 第{{m.index+1}}集</span><span @click.stop="removeHistoryItem(m)" class="detail-delete">删除</span></li>
</ul>
<ul v-show="right.type === 'other'" class="list-other">
<li v-show="right.other.length === 0">无数据</li>
<li @click="otherItemEvent(m)" v-for="(m, n) in right.other" :key="n"><span class="title">{{m.name}} - [{{m.site}}]</span></li>
<ul v-if="right.type === 'shortcut'" class="list-shortcut" v-on-clickaway="closeListEvent">
<li v-for="(m, n) in right.shortcut" :key="n"><span class="title">{{m.desc}} -- [ {{m.key}} ]</span></li>
</ul>
<ul v-if="right.type === 'other'" class="list-other" v-on-clickaway="closeListEvent">
<li v-if="right.other.length === 0">无数据</li>
<li @click="otherItemEvent(m)" v-for="(m, n) in right.other" :key="n"><span class="title">{{m.name}} - [{{m.site.name}}]</span></li>
</ul>
<ul v-if="right.type === 'otherChannels'" class="list-other" v-on-clickaway="closeListEvent">
<li v-if="right.otherChannels.length === 0">无数据</li>
<li @click="playChannel(channel)" v-for="(channel, index) in right.otherChannels" :key="index"><span class="title">{{channel.name}}</span></li>
</ul>
</div>
</div>
@@ -133,6 +179,9 @@ import zy from '../lib/site/tools'
import Player from 'xgplayer'
import Hls from 'xgplayer-hls.js'
import mt from 'mousetrap'
import { directive as onClickaway } from 'vue-clickaway'
import { exec, execFile } from 'child_process'
const { remote, ipcRenderer, clipboard } = require('electron')
const VIDEO_DETAIL_CACHE = {}
@@ -185,9 +234,12 @@ export default {
right: {
show: false,
type: '',
other: [],
list: [],
history: []
history: [],
shortcut: [],
other: [],
otherChannels: [],
currentTime: 0
},
config: {
id: 'xgplayer',
@@ -208,7 +260,8 @@ export default {
videoStop: true,
showList: true,
showHistory: true,
videoTitle: true
videoTitle: true,
airplay: true
},
state: {
showList: false,
@@ -234,6 +287,9 @@ export default {
}
}
},
directives: {
onClickaway: onClickaway
},
computed: {
view: {
get () {
@@ -317,23 +373,27 @@ export default {
if (this.video.iptv) {
// 是直播源,直接播放
this.playUrl(this.video.iptv.url)
this.name = this.video.iptv.name
this.getIptvList()
this.playChannel(this.video.iptv)
} else {
const index = this.video.info.index | 0
let time = 0
const db = await history.find({ site: this.video.key, ids: this.video.info.id })
if (db) {
if (db.index === index) {
time = db.time
var time = this.video.info.time
if (!time) {
// 如果video.info.time没有设定的话从历史中读取时间进度
const db = await history.find({ site: this.video.key, ids: this.video.info.id })
if (db) {
if (db.index === index) {
time = db.time
}
}
}
this.playVideo(index, time)
}
},
playUrl (url) {
this.xg.src = url
playChannel (channel) {
this.getIptvList()
this.video.iptv = channel
this.name = channel.name
this.xg.src = channel.url
this.xg.play()
},
playVideo (index = 0, time = 0) {
@@ -415,10 +475,10 @@ export default {
type: db.type,
year: db.year,
index: this.video.info.index,
time: db.time
time: db.time,
detail: this.video.detail
}
history.remove(db.id)
history.add(doc)
history.update(db.id, doc)
} else {
const doc = {
site: this.video.key,
@@ -427,7 +487,8 @@ export default {
type: this.video.info.type,
year: this.video.info.year,
index: this.video.info.index,
time: ''
time: '',
detail: this.video.detail
}
history.add(doc)
}
@@ -435,15 +496,23 @@ export default {
this.timerEvent()
},
changeVideo () {
const win = remote.getCurrentWindow()
win.setProgressBar(-1)
this.checkStar()
this.checkTop()
},
timerEvent () {
this.timer = setInterval(async () => {
const endTime = this.xg.duration
const currentTime = this.xg.currentTime
const progress = parseFloat((currentTime / endTime).toFixed(2))
const win = remote.getCurrentWindow()
win.setProgressBar(progress)
const db = await history.find({ site: this.video.key, ids: this.video.info.id })
if (db) {
const doc = { ...db }
doc.time = this.xg.currentTime
doc.duration = this.xg.duration
delete doc.id
history.update(db.id, doc)
}
@@ -454,8 +523,7 @@ export default {
var index = this.iptvList.findIndex(obj => obj.name === this.video.iptv.name && obj.url === this.video.iptv.url)
if (index >= 1) {
var channel = this.iptvList[index - 1]
this.video.iptv = channel
this.playUrl(channel.url)
this.playChannel(channel)
} else {
this.$message.warning('这已经是第一个频道了。')
}
@@ -473,8 +541,7 @@ export default {
var index = this.iptvList.findIndex(obj => obj.name === this.video.iptv.name && obj.url === this.video.iptv.url)
if (index < (this.iptvList.length - 1)) {
var channel = this.iptvList[index + 1]
this.video.iptv = channel
this.playUrl(channel.url)
this.playChannel(channel)
} else {
this.$message.warning('这已经是最后一个频道了。')
}
@@ -532,19 +599,18 @@ export default {
}
})
} else {
const docs = {
key: this.video.key,
ids: info.id,
name: info.name,
type: info.type,
year: info.year,
last: info.last,
note: info.note,
index: info.index
}
star.add(docs).then(res => {
this.$message.success('收藏成功')
this.isStar = true
zy.detail(this.video.key, info.id).then(detailRes => {
const docs = {
key: this.video.key,
ids: info.id,
name: info.name,
detail: detailRes,
index: info.index
}
star.add(docs).then(res => {
this.$message.success('收藏成功')
this.isStar = true
})
})
}
},
@@ -560,13 +626,23 @@ export default {
this.xg.pause()
}
mini.find().then(res => {
const doc = {
id: 0,
site: this.video.key,
ids: this.video.info.id,
name: this.video.info.name,
index: this.video.info.index,
time: this.xg.currentTime
var doc = {}
if (!this.video.iptv) {
doc = {
id: 0,
mode: 'video',
site: this.video.key,
ids: this.video.info.id,
name: this.video.info.name,
index: this.video.info.index,
time: this.xg.currentTime
}
} else {
doc = {
id: 0,
mode: 'iptv',
url: this.video.iptv.url
}
}
if (res) {
mini.update(doc)
@@ -600,8 +676,21 @@ export default {
this.$message.success('视频信息复制成功')
},
playWithExternalPalyerEvent () {
const fs = require('fs')
if (this.video.iptv) {
var externalPlayer = this.setting.externalPlayer
if (!externalPlayer) {
this.$message.error('请设置第三方播放器路径')
return
}
if (fs.existsSync(externalPlayer)) {
execFile(externalPlayer, [this.video.iptv.url])
} else {
exec(externalPlayer, [this.video.iptv.url])
}
return
}
this.fetchM3u8List().then(m3u8Arr => {
const fs = require('fs')
var externalPlayer = this.setting.externalPlayer
if (!externalPlayer) {
this.$message.error('请设置第三方播放器路径')
@@ -612,10 +701,8 @@ export default {
} else {
var m3uFile = this.generateM3uFile(this.video.info.name, m3u8Arr, this.video.info.index)
if (fs.existsSync(externalPlayer)) {
var execFile = require('child_process').execFile
execFile(externalPlayer, [m3uFile])
} else {
var exec = require('child_process').exec
exec(externalPlayer, [m3uFile])
}
}
@@ -698,10 +785,8 @@ export default {
listItemEvent (n) {
if (this.video.iptv) {
var channel = this.iptvList[n]
this.video.iptv = channel
this.name = this.video.iptv.name
// 是直播源,直接播放
this.playUrl(channel.url)
this.playChannel(channel)
} else {
this.video.info.time = 0
this.video.info.index = n
@@ -732,69 +817,45 @@ export default {
this.$message.warning('删除历史记录失败, 错误信息: ' + err)
})
},
getAllsitestest () {
this.name = '喜宝'
sites.all().then(res => {
const sites = res
const arr = []
for (const i of sites) {
zy.search(i.key, this.name).then(res => {
const type = Object.prototype.toString.call(res)
async getOtherSites () {
this.right.other = []
const currentSite = await sites.find({ key: this.video.key })
sites.all().then(sitesRes => {
// 排除已关闭的源和当前源
for (const siteItem of sitesRes.filter(x => x.isActive && x.group === currentSite.group && x.key !== this.video.key)) {
zy.search(siteItem.key, this.name).then(searchRes => {
const type = Object.prototype.toString.call(searchRes)
if (type === '[object Array]') {
res.forEach(element => {
zy.detail(i.key, element.id).then(detailRes => {
arr.push(detailRes)
})
searchRes.forEach(async item => {
const detailRes = item
detailRes.key = siteItem.key
detailRes.site = siteItem
this.right.other.push(detailRes)
})
}
if (type === '[object Object]') {
zy.detail(i.key, res.id).then(detailRes => {
arr.push(detailRes)
})
const detailRes = searchRes
detailRes.key = siteItem.key
detailRes.site = siteItem
this.right.other.push(detailRes)
}
})
}
console.log(arr, 'arr')
})
},
async getAllsites () {
const all = await sites.all()
this.right.other = []
for (const i of all) {
if (i.isActive) {
const searchRes = await zy.search(i.key, this.name)
const type = Object.prototype.toString.call(searchRes)
if (type === '[object Array]') {
searchRes.forEach(async element => {
const detailRes = await zy.detail(i.key, element.id)
detailRes.key = i.key
detailRes.site = i.name
this.right.other.push(detailRes)
})
}
if (type === '[object Object]') {
const detailRes = await zy.detail(i.key, searchRes.id)
detailRes.key = i.key
detailRes.site = i.name
this.right.other.push(detailRes)
}
}
}
},
otherEvent (m) {
this.right.type = 'other'
this.getAllsites()
if (!this.video.iptv) {
this.right.type = 'other'
this.getOtherSites()
this.right.currentTime = this.xg.currentTime
} else {
this.right.type = 'otherChannels'
}
this.right.show = true
},
async otherItemEvent (e) {
const db = await history.find({ site: e.key, ids: e.id })
if (db) {
this.video = { key: db.site, info: { id: db.ids, name: db.name, index: db.index, site: e.key } }
} else {
this.video = { key: e.key, info: { id: e.id, name: e.name, index: 0, site: e.key } }
}
this.right.show = false
this.right.type = ''
// 打开当前播放的剧集index, 定位到当前的时间
this.video = { key: e.key, info: { id: e.id, name: e.name, site: e.site, index: this.video.info.index, time: this.right.currentTime } }
},
mtEvent () {
setting.find().then(res => {
@@ -822,6 +883,8 @@ export default {
if (this.xg) {
if (this.xg.paused) {
this.xg.play()
// 继续播放时,隐藏进度条
remote.getCurrentWindow().setProgressBar(-1)
} else {
this.xg.pause()
}
@@ -972,6 +1035,7 @@ export default {
let li = ''
if (this.video.iptv) {
// 直播频道列表
this.getIptvList()
let index = 0
this.iptvList.forEach(e => {
if (e.name === this.video.iptv.name && e.url === this.video.iptv.url) {
@@ -1048,7 +1112,20 @@ export default {
},
getIptvList () {
iptv.all().then(res => {
this.iptvList = res
this.iptvList = res.filter(e => e.isActive)
this.right.otherChannels = []
const iptvList = JSON.parse(JSON.stringify(this.iptvList))
var currentChannelName = this.video.iptv.name.trim().replace(/[- ]?(1080p|蓝光|超清|高清|标清|hd|cq|4k)(\d{1,2})?/i, '')
if (currentChannelName.match(/cctv/i)) currentChannelName = currentChannelName.replace('-', '')
const matchRule = new RegExp(`${currentChannelName}(1080p|4k|(?!\\d))`, 'i')
for (var i = 0; i < iptvList.length; i++) {
if (iptvList[i].name.match(/cctv/i)) {
iptvList[i].name = iptvList[i].name.replace('-', '')
}
if (matchRule.test(iptvList[i].name) && iptvList[i].id !== this.video.iptv.id) {
this.right.otherChannels.push(this.iptvList[i])
}
}
})
},
bindEvent () {
@@ -1095,6 +1172,8 @@ export default {
})
},
videoStop () {
const win = remote.getCurrentWindow()
win.setProgressBar(-1)
if (this.xg.fullscreen) {
this.xg.exitFullscreen()
}
@@ -1152,6 +1231,13 @@ export default {
}
addPlayerView.bind(this, 'videoTitle', `<span>${title}</span>`, {})()
})
},
showShortcutEvent () {
this.right.show = !this.right.show
shortcut.all().then(res => {
this.right.type = 'shortcut'
this.right.shortcut = res
})
}
},
created () {
@@ -1180,6 +1266,14 @@ export default {
}
</script>
<style>
.xgplayer-skin-default .xgplayer-live {
width: 100px;
position: absolute;
top:50%;
left:50%;
transform: translate(-50%, -50%);
font-size: 18px !important;
}
.xgplayer-skin-default .xg-btn-playPrev,
.xgplayer-skin-default .xg-btn-playNextOne,
.xgplayer-skin-default .xg-btn-showList,

View File

@@ -0,0 +1,363 @@
<template>
<div class="listpage" id="recommendataions">
<div class="listpage-header" id="recommendataions-header">
<el-switch v-model="viewMode" active-text="海报" active-value="picture" inactive-text="列表" inactive-value="list" @change="updateViewMode"></el-switch>
<el-button type="text">视频数{{ recommendations.length }}</el-button>
<el-select v-model="selectedAreas" size="small" multiple collapse-tags 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 collapse-tags 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="listpage-body" id="recommendataions-body" >
<div class="show-table" id="star-table" v-show="viewMode === 'list'">
<el-table size="mini" fit height="100%" row-key="id"
ref="recommendataionsTable"
:data="filteredRecommendations"
@row-click="detailEvent">
<el-table-column
prop="name"
label="片名">
</el-table-column>
<el-table-column
prop="detail.area"
label="地区"
width="100">
</el-table-column>
<el-table-column
prop="detail.type"
label="类型"
width="100">
</el-table-column>
<el-table-column
prop="detail.year"
label="上映"
width="100"
align="center">
</el-table-column>
<el-table-column v-if="filteredRecommendations.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)"
prop="detail.note"
label="备注">
</el-table-column>
<el-table-column
label="操作"
header-align="center"
align="right"
width="200">
<template slot-scope="scope">
<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-show="viewMode === 'picture'">
<Waterfall ref="recommendataionsWaterfall" :list="filteredRecommendations" :gutter="20" :width="240"
:breakpoints="{
1200: { //当屏幕宽度小于等于1200
rowPerView: 4,
},
800: { //当屏幕宽度小于等于800
rowPerView: 3,
},
500: { //当屏幕宽度小于等于500
rowPerView: 2,
}
}"
animationDuration="0.5s"
backgroundColor="rgba(0, 0, 0, 0)">
<template slot="item" slot-scope="props">
<div class="card">
<div class="img">
<div class="rate" v-if="props.data.rate && props.data.rate !== '暂无评分'">
<span>{{props.data.rate}}</span>
</div>
<img style="width: 100%" :src="props.data.detail.pic" alt="" @load="$refs.recommendataionsWaterfall.refresh()" @click="detailEvent(props.data)">
<div class="operate">
<div class="operate-wrap">
<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>
<div class="name" @click="detailEvent(props.data)">{{props.data.name}}</div>
<div class="info">
<span>{{props.data.detail.area}}</span>
<span>{{props.data.detail.year}}</span>
<span>{{props.data.detail.note}}</span>
<span>{{props.data.detail.type}}</span>
</div>
</div>
</template>
</Waterfall>
</div>
</div>
</div>
</template>
<script>
import { mapMutations } from 'vuex'
import { history, recommendation, setting } from '../lib/dexie'
import zy from '../lib/site/tools'
import Waterfall from 'vue-waterfall-plugin'
const { clipboard } = require('electron')
export default {
name: 'recommendations',
data () {
return {
recommendations: [],
sites: [],
viewMode: 'picture',
loading: false,
types: [],
selectedTypes: [],
areas: [],
selectedAreas: [],
sortKeyword: '',
sortKeywords: ['上映', '评分', '默认']
}
},
components: {
Waterfall
},
computed: {
view: {
get () {
return this.$store.getters.getView
},
set (val) {
this.SET_VIEW(val)
}
},
video: {
get () {
return this.$store.getters.getVideo
},
set (val) {
this.SET_VIDEO(val)
}
},
detail: {
get () {
return this.$store.getters.getDetail
},
set (val) {
this.SET_DETAIL(val)
}
},
share: {
get () {
return this.$store.getters.getShare
},
set (val) {
this.SET_SHARE(val)
}
},
filteredRecommendations () {
var 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: {
view () {
if (this.view === 'Recommendation') {
this.getRecommendations()
if (this.$refs.recommendataionsWaterfall) {
this.$refs.recommendataionsWaterfall.refresh()
}
}
},
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
}
}
},
methods: {
...mapMutations(['SET_VIEW', 'SET_DETAIL', 'SET_VIDEO', 'SET_SHARE']),
detailEvent (e) {
this.detail = {
show: true,
key: e.key,
info: {
id: e.ids,
name: e.name
}
}
},
updateEvent () {
const url = 'https://raw.githubusercontent.com/Hunlongyu/ZY-Player/master/src/lib/dexie/iniData/Recommendations.json'
this.loading = true
const axios = require('axios')
axios.get(url).then(res => {
if (res.status === 200) {
if (res.data.length > 0) {
this.recommendations = res.data.sort(function (a, b) {
return b.detail.year - a.detail.year
})
recommendation.clear().then(recommendation.bulkAdd(this.recommendations))
this.getFilterData()
this.$message.success('更新推荐成功')
}
}
this.loading = false
}).catch(error => {
this.loading = false
this.$message.error('更新推荐失败. ' + error)
})
},
async playEvent (e) {
const db = await history.find({ site: e.key, ids: e.ids })
if (db) {
this.video = { key: e.key, info: { id: db.ids, name: db.name, index: db.index }, detail: db.detail }
} else {
this.video = { key: e.key, info: { id: e.ids, name: e.name, index: 0 }, detail: e.detail }
}
this.view = 'Play'
},
deleteEvent (e) {
recommendation.remove(e.id).then(res => {
if (res) {
this.$message.warning('删除失败')
} else {
this.$message.success('删除成功')
}
this.getRecommendations()
})
},
shareEvent (e) {
this.share = {
show: true,
key: e.key,
info: e
}
},
downloadEvent (e) {
zy.download(e.key, e.ids).then(res => {
if (res && res.dl && res.dl.dd) {
const text = res.dl.dd._t
if (text) {
const list = text.split('#')
let downloadUrl = ''
for (const i of list) {
const url = encodeURI(i.split('$')[1])
downloadUrl += (url + '\n')
}
clipboard.writeText(downloadUrl)
this.$message.success('『MP4』格式的链接已复制, 快去下载吧!')
} else {
this.$message.warning('没有查询到下载链接.')
}
} else {
var m3u8List = {}
zy.detail(e.key, e.ids).then(res => {
const dd = res.dl.dd
const type = Object.prototype.toString.call(dd)
if (type === '[object Array]') {
for (const i of dd) {
if (i._flag.indexOf('m3u8') >= 0) {
m3u8List = i._t.split('#')
}
}
} else {
m3u8List = dd._t.split('#')
}
const list = [...m3u8List]
let downloadUrl = ''
for (const i of list) {
const url = encodeURI(i.split('$')[1])
downloadUrl += (url + '\n')
}
clipboard.writeText(downloadUrl)
this.$message.success('『M3U8』格式的链接已复制, 快去下载吧!')
})
}
})
},
getRecommendations () {
recommendation.all().then(res => {
this.recommendations = res.sort(function (a, b) {
return b.id - a.id
})
this.getFilterData()
})
},
getFilterData () {
this.types = [...new Set(this.recommendations.map(ele => ele.detail.type))].filter(x => x)
this.areas = [...new Set(this.recommendations.map(ele => ele.detail.area))].filter(x => x)
},
getViewMode () {
setting.find().then(res => {
this.viewMode = res.recommendationViewMode
})
},
updateViewMode () {
setting.find().then(res => {
res.recommendationViewMode = this.viewMode
setting.update(res)
})
}
},
created () {
this.getRecommendations()
this.getViewMode()
},
mounted () {
window.addEventListener('resize', () => {
if (this.$refs.recommendataionsWaterfall && this.view === 'Recommendation') {
this.$refs.recommendataionsWaterfall.resize()
this.$refs.recommendataionsWaterfall.refresh()
setTimeout(() => {
this.$refs.recommendataionsWaterfall.refresh()
}, 500)
}
}, false)
}
}
</script>

View File

@@ -56,23 +56,17 @@
/右方向键:<input style="width:50px" type="number" v-model = "d.forwardTimeInSec" @change="updateSettingEvent">
</div>
</div>
<div class='search'>
<div class="title">搜索</div>
<div class="zy-input" @click="toggleSearchAllSites">
<input type="checkbox" v-model = "d.searchAllSites" @change="updateSettingEvent"> 搜索所有资源
</div>
</div>
<div class='site'>
<div class="title">第三方播放</div>
<div class="site-box">
<div class="zy-select">
<div class="vs-placeholder vs-noAfter" @click="selectLocalPlayer">选择本地播放器</div>
</div>
<div class="zy-select" @click = "editPlayerPath = true">
<div class="vs-placeholder vs-noAfter" v-show = "editPlayerPath == false">
<div class="zy-select" @click = "show.editPlayerPath = true">
<div class="vs-placeholder vs-noAfter" v-show = "show.editPlayerPath == false">
<label>编辑</label>
</div>
<input class="zy-input" v-show = "editPlayerPath == true" v-model = "d.externalPlayer"
<input class="zy-input" v-show = "show.editPlayerPath == true" v-model = "d.externalPlayer"
@blur= "updateSettingEvent"
@keyup.enter = "updateSettingEvent">
</div>
@@ -87,9 +81,21 @@
<div class="zy-input" @click="toggleExcludeRootClasses">
<input type="checkbox" v-model = "d.excludeRootClasses" @change="updateSettingEvent"> 屏蔽主分类
</div>
<div class="zy-input" @click="toggleExcludeR18Films">
<input type="checkbox" v-model = "d.excludeR18Films" @change="updateSettingEvent"> 屏蔽福利片
</div>
</div>
</div>
<div class="site">
<div class="title">网络</div>
<div class="site-box">
<div class="zy-select" @mouseleave="show.proxy = false">
<div class="vs-placeholder" @click="show.proxy = true">代理设置</div>
<div class="vs-options" v-if="show.proxy">
<ul class="zy-scroll">
<li :class="d.proxy.type === 'none' ? 'active' : ''" @click="changeProxyType('none')">不使用代理</li>
<!-- <li :class="d.proxy.type === 'system' ? 'active' : ''" @click="changeProxyType('system')">使用系统代理</li> -->
<li :class="d.proxy.type === 'manual' ? 'active' : ''" @click="changeProxyType('manual')">手动指定代理</li>
</ul>
</div>
</div>
</div>
</div>
<div class="theme">
@@ -130,12 +136,66 @@
</div>
<div class="clearDB">
<span @click="clearDBEvent" class="clearBtn">软件重置</span>
<span class="clearTips">如果新安装用户, 无法显示资源, 请点击软件重置. 如非必要, 切勿点击. 会清空用户数据, 恢复默认设置. 点击即软件重置, 并关闭软件.</span>
<span @click="changePasswordEvent" class="clearBtn">设置密码</span>
<div class="clearTips">如果新安装用户, 无法显示资源, 请点击软件重置. 如非必要, 切勿点击. 会清空用户数据, 恢复默认设置. 点击即软件重置, 并关闭软件.</div>
</div>
<div class="Tips">
<span>所有资源来自网上, 该软件不参与任何制作, 上传, 储存等内容, 禁止传播违法资源. 该软件仅供学习参考, 请于安装后24小时内删除.</span>
</div>
</div>
<div> <!-- 输入密码页面 -->
<el-dialog :visible.sync="show.checkPasswordDialog" v-if='show.checkPasswordDialog' :append-to-body="true" @close="closeDialog" width="300px">
<el-form label-width="75px" label-position="left">
<el-form-item label="当前密码" prop='name'>
<el-input v-model="inputPassword" placeholder="请输入您的当前密码" />
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="closeDialog">取消</el-button>
<el-button type="primary" @click="checkPasswordEvent">确定</el-button>
</span>
</el-dialog>
</div>
<div> <!-- 修改密码页面 -->
<el-dialog :visible.sync="show.changePasswordDialog" v-if='show.changePasswordDialog' :append-to-body="true" @close="closeDialog" width="300px">
<el-form label-width="75px" label-position="left">
<el-form-item label="新密码" prop='name'>
<el-input v-model="inputPassword" placeholder="请输入您的新密码" />
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="closeDialog">取消</el-button>
<el-button type="primary" @click="confirmedChangePasswordEvent">确定</el-button>
</span>
</el-dialog>
</div>
<div> <!-- 代理设置界面 -->
<el-dialog :visible.sync="show.proxyDialog" :append-to-body="true" @close="closeDialog" width="400px">
<el-form label-width="50px" label-position="left" size="small">
<el-form-item label="协议: " prop='scheme'>
<el-col :span="15">
<el-select v-model="proxy.scheme" placeholder="请选择协议类型">
<el-option label="http" value="http"></el-option>
<el-option label="socks5" value="socks5"></el-option>
</el-select>
</el-col>
</el-form-item>
<el-form-item label="地址: " prop='url'>
<el-col :span="15">
<el-input v-model="proxy.url" placeholder="地址" />
</el-col>
<el-col class="line" :span="2" style="text-align: center;">:</el-col>
<el-col :span="7">
<el-input v-model="proxy.port" placeholder="端口" width="80px" />
</el-col>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="closeDialog">取消</el-button>
<el-button type="primary" @click="proxyConfirm">确定</el-button>
</span>
</el-dialog>
</div>
</div>
</template>
<script>
@@ -145,35 +205,32 @@ import { setting, sites, shortcut } from '../lib/dexie'
import { sites as defaultSites } from '../lib/dexie/initData'
import { shell, clipboard, remote, ipcRenderer } from 'electron'
import db from '../lib/dexie/dexie'
import zy from '../lib/site/tools'
export default {
name: 'setting',
data () {
return {
pkg: pkg,
sitesList: [],
shortcutList: [],
show: {
site: false,
shortcut: false,
view: false
},
externalPlayer: '',
editPlayerPath: false,
excludeR18Films: true,
latestVersion: pkg.version,
forwardTimeInSec: 5,
d: {
id: 0,
site: '',
theme: '',
shortcut: true,
searchAllSites: true,
view: 'picture',
externalPlayer: '',
view: false,
editPlayerPath: false,
excludeRootClasses: true,
excludeR18Films: true,
forwardTimeInSec: 5
checkPasswordDialog: false,
changePasswordDialog: false,
proxy: false,
proxyDialog: false
},
d: { },
latestVersion: pkg.version,
inputPassword: '',
action: '',
proxy: {
type: '',
scheme: '',
url: '',
port: ''
}
}
},
@@ -193,34 +250,16 @@ export default {
set (val) {
this.SET_SETTING(val)
}
},
editSites: {
get () {
return this.$store.getters.getEditSites
},
set (val) {
this.SET_EDITSITES(val)
}
}
},
methods: {
...mapMutations(['SET_SETTING', 'SET_VIEW', 'SET_EDITSITES']),
...mapMutations(['SET_SETTING', 'SET_VIEW']),
linkOpen (e) {
shell.openExternal(e)
},
getSetting () {
setting.find().then(res => {
this.d = {
id: res.id,
theme: res.theme,
shortcut: res.shortcut,
view: res.view,
externalPlayer: res.externalPlayer,
searchAllSites: res.searchAllSites,
excludeRootClasses: res.excludeRootClasses,
excludeR18Films: res.excludeR18Films,
forwardTimeInSec: res.forwardTimeInSec
}
this.d = res
this.setting = this.d
})
},
@@ -229,11 +268,6 @@ export default {
if (res.length <= 0) {
this.$message.warning('检测到视频源未能正常加载, 即将重置源.')
sites.clear().then(sites.bulkAdd(defaultSites).then(this.getSites()))
} else {
this.sitesList = res
this.editSites = {
sites: res
}
}
})
},
@@ -256,14 +290,10 @@ export default {
this.$message.success(`清除缓存成功, 共清理 ${mb} MB`)
},
updateSettingEvent () {
this.editPlayerPath = false
this.show.editPlayerPath = false
this.setting = this.d
setting.update(this.d)
},
toggleSearchAllSites () {
this.d.searchAllSites = !this.d.searchAllSites
this.updateSettingEvent()
},
toggleExcludeR18Films () {
this.d.excludeR18Films = !this.d.excludeR18Films
this.updateSettingEvent()
@@ -300,11 +330,55 @@ export default {
},
updatePlayerPath () {
this.$message.success('设定第三方播放器路径为:' + this.d.externalPlayer)
this.editPlayerPath = false
this.show.editPlayerPath = false
this.updateSettingEvent()
},
editSitesEvent () {
this.view = 'EditSites'
if (this.d.password) {
this.action = 'EditSites'
this.show.checkPasswordDialog = true
} else {
this.view = 'EditSites'
}
},
async closeDialog () {
this.show.checkPasswordDialog = false
this.show.changePasswordDialog = false
if (this.show.proxyDialog) {
this.show.proxyDialog = false
this.setting.proxy.type = 'none'
await this.updateSettingEvent()
this.$message.info('取消使用代理')
zy.proxy()
}
this.inputPassword = ''
},
checkPasswordEvent () {
if (this.inputPassword === this.d.password) {
this.closeDialog()
if (this.action === 'EditSites') {
this.view = 'EditSites'
} else if (this.action === 'ChangePassword') {
this.show.changePasswordDialog = true
} else if (this.action === 'CleanDB') {
this.clearDB()
}
} else {
this.$message.error('您输入的密码错误,请重试')
}
},
changePasswordEvent () {
if (this.d.password) {
this.action = 'ChangePassword'
this.show.checkPasswordDialog = true
} else {
this.show.changePasswordDialog = true
}
},
confirmedChangePasswordEvent () {
this.d.password = this.inputPassword
this.updateSettingEvent()
this.closeDialog()
},
changeTheme (e) {
this.d.theme = e
@@ -332,7 +406,36 @@ export default {
})
})
},
async changeProxyType (e) {
this.d.proxy.type = e
if (e === 'manual') {
this.show.proxyDialog = true
this.proxy.scheme = this.setting.proxy.scheme
this.proxy.url = this.setting.proxy.url
this.proxy.port = this.setting.proxy.port
}
await this.updateSettingEvent()
this.show.proxy = false
zy.proxy()
},
async proxyConfirm () {
this.d.proxy.scheme = this.proxy.scheme
this.d.proxy.url = this.proxy.url
this.d.proxy.port = this.proxy.port
await this.updateSettingEvent()
this.show.proxyDialog = false
zy.proxy()
this.$message.info('开始使用代理')
},
clearDBEvent () {
if (this.d.password) {
this.action = 'CleanDB'
this.show.checkPasswordDialog = true
} else {
this.clearDB()
}
},
clearDB () {
db.delete().then(res => {
this.$message.success('重置成功')
const win = remote.getCurrentWindow()
@@ -430,11 +533,6 @@ export default {
}
}
}
.search{
width: 100%;
padding: 20px;
margin-top: 20px;
}
.site{
width: 100%;
padding: 20px;
@@ -519,9 +617,9 @@ export default {
line-height: 32px;
}
.clearTips{
margin: 10px 0 0 20px;
font-size: 12px;
color: #ff000088;
margin-left: 10px;
}
}
.Tips{

View File

@@ -1,5 +1,5 @@
<template>
<div class="share" id="share" @click="shareClickEvent">
<div class="share" id="share" @click="shareClickEvent" v-on-clickaway="shareClickEvent">
<div class="left">
<img :src="pic" alt="" @load="picLoadEvent">
</div>
@@ -22,6 +22,7 @@ import { mapMutations } from 'vuex'
import QrcodeVue from 'qrcode.vue'
import html2canvas from 'html2canvas'
import zy from '../lib/site/tools'
import { directive as onClickaway } from 'vue-clickaway'
const { clipboard, nativeImage } = require('electron')
export default {
name: 'share',
@@ -56,6 +57,9 @@ export default {
deep: true
}
},
directives: {
onClickaway: onClickaway
},
methods: {
...mapMutations(['SET_SHARE']),
shareClickEvent () {

View File

@@ -1,13 +1,14 @@
<template>
<div class="listpage" id="star">
<div class="listpage-content">
<div class="listpage-header">
<div class="listpage-header" id="star-header">
<el-switch v-model="viewMode" active-text="海报" active-value="picture" inactive-text="列表" inactive-value="list" @change="updateViewMode"></el-switch>
<el-button @click.stop="exportFavoritesEvent" icon="el-icon-upload2">导出</el-button>
<el-button @click.stop="importFavoritesEvent" icon="el-icon-download">导入</el-button>
<el-button @click.stop="clearFavoritesEvent" icon="el-icon-delete-solid">清空</el-button>
<el-button @click.stop="updateAllEvent" icon="el-icon-refresh">同步所有收藏</el-button>
</div>
<div class="listpage-body" id="star-table">
</div>
<div class="listpage-body" id="star-body">
<div class="show-table" id="star-table" v-show="viewMode === 'list'">
<el-table size="mini" fit height="100%" row-key="id"
ref="starTable"
:data="list"
@@ -16,42 +17,45 @@
@sort-change="handleSortChange">
<el-table-column
sortable
:sort-method="sortByName"
:sort-method="(a , b) => sortByLocaleCompare(a.name, b.name)"
prop="name"
label="片名">
</el-table-column>
<el-table-column
:sort-by="['type', 'name']"
prop="site.name"
width="120"
label="源站">
<template slot-scope="scope">
<span>{{ getSiteName(scope.row) }}</span>
</template>
</el-table-column>
<el-table-column
sortable
:sort-method="sortByType"
prop="type"
:sort-method="(a , b) => sortByLocaleCompare(a.detail.type, b.detail.type)"
prop="detail.type"
label="类型"
width="100">
</el-table-column>
<el-table-column
sortable
:sort-by="['year', 'name']"
prop="year"
:sort-by="['detail.year', 'name']"
prop="detail.year"
label="上映"
width="100"
align="center">
width="100">
</el-table-column>
<el-table-column
:sort-by="['site', 'name']"
sortable
:sort-method="sortBySite"
prop="site"
width="120"
label="片源">
<template slot-scope="scope">
<span>{{ getSiteName(scope.row.key) }}</span>
</template>
</el-table-column>
<el-table-column v-if="list.some(e => e.note)"
prop="note"
<el-table-column v-if="list.some(e => e.detail.note)"
prop="detail.note"
width="120"
label="备注">
</el-table-column>
<el-table-column v-if="list.some(e => e.rate && e.rate !== '暂无评分')"
sortable
sort-by="rate"
prop="rate"
width="120"
align="center"
label="豆瓣评分">
</el-table-column>
<el-table-column v-if="list.some(e => e.index >= 0)"
prop="index"
width="120"
@@ -62,8 +66,9 @@
</el-table-column>
<el-table-column
label="操作"
header-align="right"
align="right">
header-align="center"
align="right"
width="200">
<template slot-scope="scope">
<el-button @click.stop="playEvent(scope.row)" type="text">播放</el-button>
<el-button @click.stop="shareEvent(scope.row)" type="text">分享</el-button>
@@ -73,25 +78,81 @@
</el-table-column>
</el-table>
</div>
<div class="show-picture" id="star-picture" v-show="viewMode === 'picture'">
<Waterfall ref="starWaterfall" :list="list" :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">
<div class="rate" v-if="props.data.rate && props.data.rate !== '暂无评分'">
<span>{{props.data.rate}}分</span>
</div>
<div class="update" v-if="props.data.hasUpdate">
<span>有更新</span>
</div>
<div class="progress" v-if="props.data.index && props.data.detail && props.data.detail.m3u8List !== undefined && props.data.detail.m3u8List.length > 1">
<span>
看至第{{ props.data.index + 1 }}集
</span>
</div>
<img style="width: 100%" :src="props.data.detail.pic" alt="" @load="$refs.starWaterfall.refresh()" @click="detailEvent(props.data)">
<div class="operate">
<div class="operate-wrap">
<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>
<div class="name" @click="detailEvent(props.data)">{{props.data.name}}</div>
<div class="info">
<span>{{props.data.detail.area}}</span>
<span>{{props.data.detail.year}}</span>
<span>{{props.data.detail.note}}</span>
<span>{{props.data.detail.type}}</span>
</div>
</div>
</template>
</Waterfall>
</div>
</div>
</div>
</template>
<script>
import { mapMutations } from 'vuex'
import { star, history, sites } from '../lib/dexie'
import { star, sites, setting } from '../lib/dexie'
import zy from '../lib/site/tools'
import { remote } from 'electron'
import fs from 'fs'
import Sortable from 'sortablejs'
import Waterfall from 'vue-waterfall-plugin'
const { clipboard } = require('electron')
export default {
name: 'star',
data () {
return {
list: [],
sites: []
sites: [],
viewMode: 'picture',
numNoUpdate: 0
}
},
components: {
Waterfall
},
computed: {
view: {
get () {
@@ -128,8 +189,20 @@ export default {
},
watch: {
view () {
this.getAllsites()
this.getFavorites()
if (this.view === 'Star') {
this.getAllsites()
this.getFavorites()
if (this.$refs.starWaterfall) {
this.$refs.starWaterfall.refresh()
}
}
},
numNoUpdate () {
// 如果所有收藏都没有更新的话
if (this.numNoUpdate === this.list.length) {
this.numNoUpdate = 0
this.$message.warning('未查询到任何更新')
}
}
},
methods: {
@@ -137,19 +210,8 @@ export default {
handleSortChange (column, prop, order) {
this.updateDatabase()
},
sortByName (a, b) {
return a.name.localeCompare(b.name, 'zh')
},
sortByType (a, b) {
return a.type.localeCompare(b.type)
},
sortBySite (a, b) {
const siteA = this.getSiteName(a.key)
if (!siteA) {
return -1
} else {
return siteA.localeCompare(this.getSiteName(b.key))
}
sortByLocaleCompare (a, b) {
return a.localeCompare(b, 'zh')
},
detailEvent (e) {
this.detail = {
@@ -165,11 +227,10 @@ export default {
}
},
async playEvent (e) {
const db = await history.find({ site: e.key, ids: e.ids })
if (db) {
this.video = { key: e.key, info: { id: db.ids, name: db.name, index: db.index } }
if (e.index) {
this.video = { key: e.key, info: { id: e.ids, name: e.name, index: e.index }, detail: e.detail }
} else {
this.video = { key: e.key, info: { id: e.ids, name: e.name, index: 0 } }
this.video = { key: e.key, info: { id: e.ids, name: e.name, index: 0 }, detail: e.detail }
}
if (e.hasUpdate) {
this.clearHasUpdateFlag(e)
@@ -207,30 +268,23 @@ export default {
}
},
updateEvent (e) {
zy.detail(e.key, e.ids).then(res => {
zy.detail(e.key, e.ids).then(detailRes => {
var doc = {
id: e.id,
key: e.key,
ids: res.id,
site: res.site,
name: res.name,
type: res.type,
year: res.year,
note: res.note,
index: res.index,
last: res.last,
hasUpdate: res.hasUpdate
ids: e.ids,
site: e.site,
name: e.name,
detail: detailRes,
index: e.index
}
star.get(e.id).then(resStar => {
doc.hasUpdate = resStar.hasUpdate
var msg = ''
if (e.last === res.last) {
msg = `同步"${e.name}"成功, 未查询到更新。`
this.$message.info(msg)
} else {
if (!e.hasUpdate && e.detail.last !== detailRes.last) {
doc.hasUpdate = true
msg = `同步"${e.name}"成功, 检查到更新。`
var msg = `同步"${e.name}"成功, 检查到更新。`
this.$message.success(msg)
} else {
this.numNoUpdate += 1
}
star.update(e.id, doc)
this.getFavorites()
@@ -241,6 +295,7 @@ export default {
})
},
updateAllEvent () {
this.numNoUpdate = 0
this.list.forEach(e => {
this.updateEvent(e)
})
@@ -287,10 +342,14 @@ export default {
}
})
},
getSiteName (key) {
var site = this.sites.find(e => e.key === key)
if (site) {
return site.name
getSiteName (row) {
if (row.site) {
return row.site.name
} else {
var site = this.sites.find(e => e.key === row.key)
if (site) {
return site.name
}
}
},
getHistoryNote (index) {
@@ -302,7 +361,9 @@ export default {
},
getFavorites () {
star.all().then(res => {
this.list = res.reverse()
this.list = res.sort(function (a, b) {
return b.id - a.id
})
})
},
getAllsites () {
@@ -323,7 +384,7 @@ export default {
remote.dialog.showSaveDialog(options).then(result => {
if (!result.canceled) {
fs.writeFileSync(result.filePath, str)
this.$message.success('已保存成功')
this.$message.success('导出收藏成功')
}
}).catch(err => {
this.$message.error(err)
@@ -340,25 +401,35 @@ export default {
}
remote.dialog.showOpenDialog(options).then(result => {
if (!result.canceled) {
var starList = this.list
var starList = Array.from(this.list)
var id = this.list.length + 1
result.filePaths.forEach(file => {
var str = fs.readFileSync(file)
const json = JSON.parse(str)
json.forEach(ele => {
const starExists = starList.includes(x => x.key === ele.key && x.ids === ele.ids)
json.reverse().forEach(ele => {
const starExists = starList.some(x => x.key === ele.key && x.ids === ele.ids)
if (!starExists) {
var doc = {
id: id,
key: ele.key,
ids: ele.ids,
site: ele.site === undefined ? ele.site = this.sites.find(x => x.key === ele.key) : ele.site,
name: ele.name,
type: ele.type,
year: ele.year,
note: ele.note,
hasUpdate: ele.hasUpdate,
index: ele.index,
last: ele.last,
hasUpdate: ele.hasUpdate
rate: ele.rate,
detail: ele.detail === undefined ? {
director: ele.director,
actor: ele.actor,
type: ele.type,
area: ele.area,
lang: ele.lang,
year: ele.year,
last: ele.last,
note: ele.note
} : ele.detail
}
id += 1
starList.push(doc)
}
})
@@ -403,13 +474,34 @@ export default {
_this.updateDatabase()
}
})
},
getViewMode () {
setting.find().then(res => {
this.viewMode = res.starViewMode
})
},
updateViewMode () {
setting.find().then(res => {
res.starViewMode = this.viewMode
setting.update(res)
})
}
},
mounted () {
this.rowDrop()
},
created () {
this.getFavorites()
this.getViewMode()
},
mounted () {
this.rowDrop()
window.addEventListener('resize', () => {
if (this.$refs.starWaterfall && this.view === 'Star') {
this.$refs.starWaterfall.resize()
this.$refs.starWaterfall.refresh()
setTimeout(() => {
this.$refs.starWaterfall.refresh()
}, 500)
}
}, false)
}
}
</script>

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'
export default {
registerComponents () {
Vue.component('Aside', Aside)
@@ -24,5 +24,6 @@ export default {
Vue.component('History', History)
Vue.component('EditSites', EditSites)
Vue.component('IPTV', IPTV)
Vue.component('Recommendation', Recommendation)
}
}

View File

@@ -1,18 +1,19 @@
import Dexie from 'dexie'
import { setting, sites, localKey, iptv } from './initData'
import { setting, sites, localKey, iptv, recommendations } from './initData'
const db = new Dexie('zy')
db.version(4).stores({
search: '++id, keywords',
iptvSearch: '++id, keywords',
setting: 'id, theme, site, shortcut, view, externalPlayer, searchAllSites, excludeRootClasses, excludeR18Films, forwardTimeInSec',
setting: 'id, theme, site, shortcut, view, externalPlayer, searchGroup, excludeRootClasses, excludeR18Films, forwardTimeInSec, starViewMode, recommandationViewMode, password, proxy',
shortcut: 'name, key, desc',
star: '++id, [key+ids], site, name, type, year, note, index, last, hasUpdate',
star: '++id, [key+ids], site, name, detail, index, rate, hasUpdate',
recommendation: '++id, [key+ids], site, name, detail, index, rate, hasUpdate',
sites: '++id, key, name, api, download, isActive, group',
history: '++id, [site+ids], name, type, year, index, time',
mini: 'id, site, ids, name, index, time',
iptv: '++id, name, url, group'
history: '++id, [site+ids], name, type, year, index, time, duration, detail',
mini: 'id, mode, site, ids, name, index, time, url',
iptv: '++id, name, url, group, isActive'
})
db.on('populate', () => {
@@ -20,6 +21,7 @@ db.on('populate', () => {
db.sites.bulkAdd(sites)
db.shortcut.bulkAdd(localKey)
db.iptv.bulkAdd(iptv)
db.recommendation.bulkAdd(recommendations)
})
db.open()

View File

@@ -7,6 +7,7 @@ import sites from './sites'
import search from './search'
import iptvSearch from './iptvSearch'
import iptv from './iptv'
import recommendation from './recommendation'
export {
history,
@@ -17,5 +18,6 @@ export {
sites,
iptv,
search,
iptvSearch
iptvSearch,
recommendation
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

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

View File

@@ -5,238 +5,20 @@ const setting = [
shortcut: true,
view: 'picture',
externalPlayer: '',
searchAllSites: true,
searchGroup: '全站',
excludeRootClasses: true,
excludeR18Films: true,
forwardTimeInSec: 5
}
]
const sites = [
{
id: 1,
key: 'okzy',
name: 'OK 资源网',
api: 'http://cj.okzy.tv/inc/api.php',
download: 'http://cj.okzy.tv/inc/apidown.php',
isActive: 1,
group: '默认'
},
{
id: 2,
key: 'zuidazy',
name: '最大资源网',
api: 'http://www.zdziyuan.com/inc/api.php',
download: 'http://www.zdziyuan.com/inc/apidown.php',
isActive: 1,
group: '默认'
},
{
id: 3,
key: 'doubanzy',
name: '豆瓣电影资源',
api: 'http://v.1988cj.com/inc/api.php',
download: 'http://v.1988cj.com/inc/apidown.php',
isActive: 1,
group: '默认'
},
{
id: 4,
key: '135zy',
name: '135 资源网',
api: 'http://cj.zycjw1.com/inc/api.php',
download: 'http://cj.zycjw1.com/inc/apidown.php',
isActive: 1,
group: '默认'
},
{
id: 5,
key: 'kuyunzy',
name: '酷云资源',
api: 'http://caiji.kuyun98.com/inc/ldg_api.php',
download: 'http://caiji.kuyun98.com/inc/apidown.php',
isActive: 1,
group: '默认'
},
{
id: 6,
key: 'mgtvzy',
name: '芒果 TV 资源网',
api: 'https://api.shijiapi.com/api.php/provide/vod/at/xml/',
download: '',
isActive: 1,
group: '默认'
},
{
id: 7,
key: 'subo988',
name: '速播资源站',
api: 'https://www.subo988.com/inc/api.php',
download: '',
isActive: 1,
group: '默认'
},
{
id: 8,
key: '209zy',
name: '209 资源',
api: 'http://cj.1156zy.com/inc/api.php',
download: '',
isActive: 1,
group: '默认'
},
{
id: 9,
key: 'zuixinzy',
name: '最新资源',
api: 'http://api.zuixinapi.com/inc/api.php',
download: '',
isActive: 1,
group: '默认'
},
{
id: 10,
key: 'kubozy',
name: '酷播资源',
api: 'http://api.kbzyapi.com/inc/api.php',
download: '',
isActive: 1,
group: '默认'
},
{
id: 11,
key: 'yongjiuzy',
name: '永久资源',
api: 'http://cj.yongjiuzyw.com/inc/api.php',
download: '',
isActive: 1,
group: '默认'
},
{
id: 12,
key: '123ku',
name: '123 资源',
api: 'http://cj.123ku2.com:12315/inc/api.php',
download: '',
isActive: 1,
group: '默认'
},
{
id: 13,
key: '88zyw',
name: '88 影视资源站',
api: 'http://www.88zyw.net/inc/api.php',
download: '',
isActive: 1,
group: '默认'
},
{
id: 14,
key: 'wolongzy',
name: '卧龙资源',
api: 'http://cj.wlzy.tv/inc/api_mac.php',
download: '',
isActive: 1,
group: '默认'
},
{
id: 15,
key: 'mahuazy',
name: '麻花资源',
api: 'https://www.mhapi123.com/inc/api.php',
download: '',
isActive: 1,
group: '默认'
},
{
id: 16,
key: 'kkzy',
name: '快快资源',
api: 'https://api.kkzy.tv/inc/api.php',
download: '',
isActive: 1,
group: '默认'
},
{
id: 17,
key: '158zy',
name: '壹伍捌资源网',
api: 'http://cj.158zyz.net:158/inc/api.php',
download: '',
isActive: 1,
group: '默认'
},
{
id: 18,
key: 'rrzy',
name: '人人资源',
api: 'https://www.rrzyw.cc/api.php/provide/vod/from/rrm3u8/at/xml/',
download: '',
isActive: 1,
group: '默认'
},
{
id: 19,
key: 'mokazy',
name: '魔卡资源网',
api: 'https://cj.heiyap.com/api.php/provide/vod/at/xml/',
download: '',
isActive: 1,
group: '默认'
},
{
id: 20,
key: 'kyzy',
name: '快影资源站',
api: 'https://www.kyzy.tv/api.php/kyyun/vod/at/xml/',
download: '',
isActive: 1,
group: '默认'
},
{
id: 21,
key: 'solezy',
name: '搜乐资源网',
api: 'https://www.caijizy.vip/api.php/provide/vod/at/xml/',
download: '',
isActive: 1,
group: '默认'
},
{
id: 22,
key: 'bbkdj',
name: '步步高顶尖资源网',
api: 'http://api.bbkdj.com/api',
download: '',
isActive: 1,
group: '默认'
},
{
id: 23,
key: '1886zy',
name: '1886 资源',
api: 'http://cj.1886zy.co/inc/api.php',
download: '',
isActive: 1,
group: '默认'
},
{
id: 24,
key: 'mbo',
name: '秒播资源',
api: 'http://caiji.mb77.vip/inc/api.php',
download: '',
isActive: 1,
group: '默认'
},
{
id: 25,
key: '605zy',
name: '605资源',
api: 'http://www.605zy.net/inc/seacmsapi.php',
download: '',
isActive: 1,
group: '默认'
forwardTimeInSec: 5,
starViewMode: 'picture',
recommendationViewMode: 'picture',
historyViewMode: 'picture',
password: '',
proxy: {
type: 'none',
scheme: '',
url: '',
port: ''
}
}
]
@@ -341,12 +123,14 @@ const getSite = (key) => {
}
}
const sites = require('./iniData/Sites.json')
const iptv = require('./iniData/Iptv.json')
const recommendations = require('./iniData/Recommendations.json')
export {
setting,
sites,
iptv,
recommendations,
localKey,
getSite
}

View File

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

View File

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

View File

@@ -1,6 +1,64 @@
import { sites } from '../dexie'
import { sites, setting } from '../dexie'
import axios from 'axios'
import parser from 'fast-xml-parser'
import cheerio from 'cheerio'
import { Parser as M3u8Parser } from 'm3u8-parser'
// axios使用系统代理 https://evandontje.com/2020/04/02/automatic-system-proxy-configuration-for-electron-applications/
// xgplayer使用chromium代理设置浏览器又默认使用系统代理 https://www.chromium.org/developers/design-documents/network-settings
// 要在设置中添加代理设置可参考https://stackoverflow.com/questions/37393248/how-connect-to-proxy-in-electron-webview
var http = require('http')
var https = require('http')
const { remote } = require('electron')
var win = remote.getCurrentWindow()
var session = win.webContents.session
var ElectronProxyAgent = require('electron-proxy-agent')
// 请求超时时限
axios.defaults.timeout = 10000 // 可能使用代理,增长超时
// 重试次数共请求3次
axios.defaults.retry = 2
// 请求的间隙
axios.defaults.retryDelay = 1000
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做些事
if (response.status && response.status === 200 && response.request.responseURL.includes('api.php') && !response.data.startsWith('<?xml')) {
}
return response
}, function (err) { // 请求错误时做些事
// 请求超时的之后,抛出 err.code = ECONNABORTED的错误..错误信息是 timeout of xxx ms exceeded
if (err.code === 'ECONNABORTED' && err.message.indexOf('timeout') !== -1) {
var config = err.config
config.__retryCount = config.__retryCount || 0
if (config.__retryCount >= config.retry) {
err.message = '多次请求均超时'
return Promise.reject(err)
}
config.__retryCount += 1
var backoff = new Promise(function (resolve) {
setTimeout(function () {
resolve()
}, config.retryDelay || 1)
})
return backoff.then(function () {
return axios(config)
})
} else {
if (err && !err.response) {
err.message = '连接服务器失败!'
}
return Promise.reject(err)
}
})
const zy = {
xmlConfig: { // XML 转 JSON 配置
trimValues: true,
@@ -159,6 +217,20 @@ const zy = {
const data = res.data
const json = parser.parse(data, this.xmlConfig)
const videoList = json.rss.list.video
// Parse m3u8List
var m3u8List = []
const dd = videoList.dl.dd
const type = Object.prototype.toString.call(dd)
if (type === '[object Array]') {
for (const i of dd) {
if (i._flag.indexOf('m3u8') >= 0) {
m3u8List = i._t.split('#')
}
}
} else {
m3u8List = dd._t.split('#')
}
videoList.m3u8List = m3u8List
resolve(videoList)
}).catch(err => {
reject(err)
@@ -178,8 +250,8 @@ const zy = {
return new Promise((resolve, reject) => {
this.getSite(key).then(res => {
const site = res
const url = `${site.download}?ac=videolist&ids=${id}&ct=1`
if (url) {
if (site.download) {
const url = `${site.download}?ac=videolist&ids=${id}&ct=1`
axios.post(url).then(res => {
const data = res.data
const json = parser.parse(data, this.xmlConfig)
@@ -210,7 +282,117 @@ const zy = {
} catch (e) {
return false
}
},
/**
* 检查直播源
* @param {*} channel 直播频道 url
* @returns boolean
*/
async checkChannel (channel) {
return new Promise((resolve, reject) => {
axios.get(channel).then(res => {
const manifest = res.data
var parser = new M3u8Parser()
parser.push(manifest)
parser.end()
var parsedManifest = parser.manifest
if (parsedManifest.segments.length) {
resolve(true)
} else {
resolve(false)
}
}).catch(e => {
resolve(false)
})
})
},
/**
* 获取豆瓣页面链接
* @param {*} name 视频名称
* @returns 豆瓣页面链接,如果没有搜到该视频,返回搜索页面链接
*/
doubanLink (name) {
return new Promise((resolve, reject) => {
// 豆瓣搜索链接
var nameToSearch = name.replace(/\s/g, '')
var doubanSearchLink = 'https://www.douban.com/search?q=' + nameToSearch
axios.get(doubanSearchLink).then(res => {
const $ = cheerio.load(res.data)
// 比较第一和第二给豆瓣搜索结果, 看名字是否相符
var link = ''
var linkInDouban = $($('div.result')[0]).find('div>div>h3>a').first()
var nameInDouban = linkInDouban.text().replace(/\s/g, '')
if (nameToSearch === nameInDouban) {
link = linkInDouban.attr('href')
} else {
linkInDouban = $($('div.result')[1]).find('div>div>h3>a').first()
nameInDouban = linkInDouban.text().replace(/\s/g, '')
if (nameToSearch === nameInDouban) {
link = linkInDouban.attr('href')
}
}
if (link) {
resolve(link)
} else {
// 如果没找到符合的链接,返回搜索页面
resolve(doubanSearchLink)
}
}).catch(err => {
reject(err)
})
})
},
/**
* 获取豆瓣评分
* @param {*} name 视频名称
* @returns 豆瓣评分
*/
doubanRate (name) {
return new Promise((resolve, reject) => {
var nameToSearch = name.replace(/\s/g, '')
this.doubanLink(nameToSearch).then(link => {
if (link.includes('https://www.douban.com/search')) {
resolve('暂无评分')
} else {
axios.get(link).then(response => {
const parsedHtml = cheerio.load(response.data)
var rating = parsedHtml('body').find('#interest_sectl').first().find('strong').first()
if (rating.text()) {
resolve(rating.text().replace(/\s/g, ''))
} else {
resolve('暂无评分')
}
}).catch(err => {
reject(err)
})
}
}).catch(err => {
reject(err)
})
})
},
async proxy () {
return new Promise((resolve, reject) => {
setting.find().then(db => {
if (db.proxy) {
if (db.proxy.type === 'none') {
session.setProxy({ proxyRules: 'direct://' })
http.globalAgent = https.globalAgent = new ElectronProxyAgent(session)
} else if (db.proxy.type === 'manual') {
if (db.proxy.scheme && db.proxy.url && db.proxy.port) {
const proxyURL = db.proxy.scheme + '://' + db.proxy.url.trim() + ':' + db.proxy.port.trim()
session.setProxy({ proxyRules: proxyURL })
http.globalAgent = https.globalAgent = new ElectronProxyAgent(session)
}
}
}
// 不要删了,留着测试用
// axios.get('https://api.my-ip.io/ip').then(res => console.log(res))
})
})
}
}
zy.proxy()
export default zy

View File

@@ -1,6 +1,6 @@
<template>
<div class="mini">
<div class="top">
<div class="header">
<div class="left">
<span class="title">
<span v-if="m3u8Arr.length > 1"> {{(video.index + 1)}} </span>{{name}}
@@ -22,7 +22,7 @@
<span class="progress" v-show="progress > 0">播放进度: {{progress}}%</span>
</div>
<div class="right">
<span class="top" @click="frameClickEvent('top')" title="置顶">
<span class="topping" @click="frameClickEvent('top')" title="置顶">
<svg t="1595919317571" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1188" style="width:10px;height:14px"><path d="M43.072 974.72l380.864-301.952 151.936 161.6c0 0 63.424 17.28 67.328-30.72l-3.904-163.584 225.088-259.648 98.048-5.696c0 0 76.928-15.488 21.184-82.752l-275.072-276.928c0 0-74.944-9.6-69.248 59.584l0 75.008L383.552 367.104 225.856 376.64c0 0-57.728 19.2-36.608 69.248l148.16 146.176L43.072 974.72 43.072 974.72z" p-id="1189" :fill="isAlwaysOnTop ? '#555555' : '#ffffff'"></path></svg>
</span>
<span class="min" @click="frameClickEvent('min')" title="最小化">
@@ -31,12 +31,12 @@
<span class="max" @click="frameClickEvent('max')" title="最大化">
<svg t="1595917343956" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1540" style="width:8px;height:14px"><path d="M416 416 64.064 416C28.448 416 0 444.64 0 479.936L0 544.064C0 579.264 28.672 608 64.064 608L416 608 416 959.936C416 995.552 444.64 1024 479.936 1024L544.064 1024C579.264 1024 608 995.328 608 959.936L608 608 959.936 608C995.552 608 1024 579.36 1024 544.064L1024 479.936C1024 444.736 995.328 416 959.936 416L608 416 608 64.064C608 28.448 579.36 0 544.064 0L479.936 0C444.736 0 416 28.672 416 64.064L416 416Z" p-id="1541" fill="#ffffff"></path></svg>
</span>
<span class="close" @click="frameClickEvent('close')" title="关闭">
<span class="close" @click="frameClickEvent('close')" title="退出精简模式">
<svg t="1595917372551" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1685" style="width:8px;height:14px"><path d="M511.968 376.224 796.096 92.096C833.536 54.624 894.4 54.624 931.84 92.096 969.312 129.568 969.312 190.4 931.84 227.872L647.744 512 931.84 796.096C969.312 833.568 969.312 894.4 931.84 931.872 894.4 969.344 833.536 969.344 796.096 931.872L511.968 647.744 227.84 931.872C190.4 969.344 129.536 969.344 92.096 931.872 54.624 894.4 54.624 833.568 92.096 796.096L376.224 512 92.096 227.872C54.624 190.4 54.624 129.568 92.096 92.096 129.536 54.624 190.4 54.624 227.84 92.096L511.968 376.224Z" p-id="1686" fill="#ffffff"></path></svg>
</span>
</div>
</div>
<div class="bottom">
<div class="footer">
<div id="xg"></div>
</div>
</div>
@@ -107,6 +107,11 @@ export default {
},
getUrls () {
mini.find().then(res => {
if (res.mode === 'iptv') {
this.xg.src = res.url
this.xg.play()
return
}
this.video = res
this.fetchM3u8List(res).then(m3u8Arr => {
this.m3u8Arr = m3u8Arr
@@ -198,6 +203,9 @@ export default {
const currentTime = this.xg.currentTime
const progress = (currentTime / endTime) * 100
this.progress = progress.toFixed(2)
const percent = parseFloat((currentTime / endTime).toFixed(2))
const win = remote.getCurrentWindow()
win.setProgressBar(percent)
const db = await history.find({ site: this.video.site, ids: this.video.ids })
if (db) {
const v = db
@@ -419,9 +427,10 @@ html,body{
justify-content: center;
align-items: flex-start;
flex-direction: column;
.top{
.header{
width: 100%;
height: 30px;
min-height: 30px;
display: flex;
justify-content: space-between;
align-items: center;
@@ -455,22 +464,27 @@ html,body{
}
}
.right{
width: 80px;
width: 100px;
height: 100%;
display: flex;
justify-content: flex-end;
align-items: center;
span{
-webkit-app-region: no-drag;
display: inline-block;
width: 14px;
height: 14px;
display: flex;
align-items: center;
justify-content: center;
width: 15px;
height: 15px;
text-align: center;
line-height: 14px;
line-height: 15px;
border-radius: 50%;
margin-right: 10px;
cursor: pointer;
opacity: 0.4;
&.topping{
background-color: #f3bab7;
}
&.min{
background-color: #32dc36;
}
@@ -480,9 +494,6 @@ html,body{
&.close{
background-color: #ff5f56;
}
&.top{
background-color: #f3bab7;
}
&:hover{
animation: heartbeat 3s ease-in-out infinite both;
}
@@ -513,7 +524,7 @@ html,body{
}
}
}
.bottom{
.footer{
width: 100%;
flex: 1;
.xgplayer-start{

375
yarn.lock
View File

@@ -803,6 +803,13 @@
core-js-pure "^3.0.0"
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.5.5":
version "7.12.5"
resolved "https://registry.npm.taobao.org/@babel/runtime/download/@babel/runtime-7.12.5.tgz?cache=0&sync_timestamp=1604441208794&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fruntime%2Fdownload%2F%40babel%2Fruntime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e"
integrity sha1-QQ5+SHRB4bNgwpvnFdhw2bmFiC4=
dependencies:
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.8.4", "@babel/runtime@^7.9.6":
version "7.10.4"
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.4.tgz#a6724f1a6b8d2f6ea5236dbfe58c7d7ea9c5eb99"
@@ -963,6 +970,11 @@
dependencies:
defer-to-connect "^1.0.1"
"@tootallnate/once@1":
version "1.1.2"
resolved "https://registry.npm.taobao.org/@tootallnate/once/download/@tootallnate/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
integrity sha1-zLkURTYBeaBOf+av94wA/8Hur4I=
"@types/color-name@^1.1.1":
version "1.1.1"
resolved "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
@@ -1040,6 +1052,15 @@
dependencies:
"@types/yargs-parser" "*"
"@videojs/vhs-utils@^2.2.1":
version "2.2.1"
resolved "https://registry.npm.taobao.org/@videojs/vhs-utils/download/@videojs/vhs-utils-2.2.1.tgz#78ecea26652268646d5003b1b1a705c9b544f8a2"
integrity sha1-eOzqJmUiaGRtUAOxsacFybVE+KI=
dependencies:
"@babel/runtime" "^7.5.5"
global "^4.3.2"
url-toolkit "^2.1.6"
"@vue/babel-helper-vue-jsx-merge-props@^1.0.0":
version "1.0.0"
resolved "https://registry.npmjs.org/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.0.0.tgz#048fe579958da408fb7a8b2a3ec050b50a661040"
@@ -1466,6 +1487,21 @@ address@^1.1.2:
resolved "https://registry.npmjs.org/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6"
integrity sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==
agent-base@2:
version "2.1.1"
resolved "https://registry.npm.taobao.org/agent-base/download/agent-base-2.1.1.tgz?cache=0&sync_timestamp=1603480011934&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fagent-base%2Fdownload%2Fagent-base-2.1.1.tgz#d6de10d5af6132d5bd692427d46fc538539094c7"
integrity sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=
dependencies:
extend "~3.0.0"
semver "~5.0.1"
agent-base@6:
version "6.0.2"
resolved "https://registry.npm.taobao.org/agent-base/download/agent-base-6.0.2.tgz?cache=0&sync_timestamp=1603480011934&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fagent-base%2Fdownload%2Fagent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
integrity sha1-Sf/1hXfP7j83F2/qtMIuAPhtf3c=
dependencies:
debug "4"
aggregate-error@^3.0.0:
version "3.0.1"
resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz#db2fe7246e536f40d9b5442a39e117d7dd6a24e0"
@@ -1814,10 +1850,10 @@ aws4@^1.8.0:
resolved "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz#a17b3a8ea811060e74d47d306122400ad4497ae2"
integrity sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==
axios@^0.20.0:
version "0.20.0"
resolved "https://registry.npm.taobao.org/axios/download/axios-0.20.0.tgz#057ba30f04884694993a8cd07fa394cff11c50bd"
integrity sha1-BXujDwSIRpSZOozQf6OUz/EcUL0=
axios@^0.21.0:
version "0.21.0"
resolved "https://registry.npm.taobao.org/axios/download/axios-0.21.0.tgz?cache=0&sync_timestamp=1603468783865&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Faxios%2Fdownload%2Faxios-0.21.0.tgz#26df088803a2350dff2c27f96fef99fe49442aca"
integrity sha1-Jt8IiAOiNQ3/LCf5b++Z/klEKso=
dependencies:
follow-redirects "^1.10.0"
@@ -2447,11 +2483,6 @@ cheerio@^1.0.0-rc.3:
lodash "^4.15.0"
parse5 "^3.0.1"
child_process@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/child_process/-/child_process-1.0.2.tgz#b1f7e7fc73d25e7fd1d455adc94e143830182b5a"
integrity sha1-sffn/HPSXn/R1FWtyU4UODAYK1o=
"chokidar@>=2.0.0 <4.0.0", chokidar@^3.0.2, chokidar@^3.4.0:
version "3.4.0"
resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.4.0.tgz#b30611423ce376357c765b9b8f904b9fba3c0be8"
@@ -2791,6 +2822,11 @@ connect-history-api-fallback@^1.6.0:
resolved "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc"
integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==
connection-parse@0.0.x:
version "0.0.7"
resolved "https://registry.npm.taobao.org/connection-parse/download/connection-parse-0.0.7.tgz#18e7318aab06a699267372b10c5226d25a1c9a69"
integrity sha1-GOcxiqsGppkmc3KxDFIm0locmmk=
console-browserify@^1.1.0:
version "1.2.0"
resolved "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336"
@@ -2900,6 +2936,11 @@ core-js@^3.6.5:
resolved "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a"
integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==
core-js@^3.7.0:
version "3.7.0"
resolved "https://registry.npm.taobao.org/core-js/download/core-js-3.7.0.tgz?cache=0&sync_timestamp=1604675690423&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcore-js%2Fdownload%2Fcore-js-3.7.0.tgz#b0a761a02488577afbf97179e4681bf49568520f"
integrity sha1-sKdhoCSIV3r7+XF55Ggb9JVoUg8=
core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@@ -3202,18 +3243,30 @@ dashdash@^1.12.0:
dependencies:
assert-plus "^1.0.0"
data-uri-to-buffer@0:
version "0.0.4"
resolved "https://registry.npm.taobao.org/data-uri-to-buffer/download/data-uri-to-buffer-0.0.4.tgz?cache=0&sync_timestamp=1590800007667&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdata-uri-to-buffer%2Fdownload%2Fdata-uri-to-buffer-0.0.4.tgz#46e13ab9da8e309745c8d01ce547213ebdb2fe3f"
integrity sha1-RuE6udqOMJdFyNAc5UchPr2y/j8=
de-indent@^1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
integrity sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=
debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
debug@2, debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
version "2.6.9"
resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
resolved "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1600502824188&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=
dependencies:
ms "2.0.0"
debug@4, debug@^4.2.0:
version "4.2.0"
resolved "https://registry.npm.taobao.org/debug/download/debug-4.2.0.tgz?cache=0&sync_timestamp=1600502824188&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1"
integrity sha1-fxUPk5IOlMWPVXTC/QGjEQ7/5/E=
dependencies:
ms "2.1.2"
debug@^3.1.1, debug@^3.2.5:
version "3.2.6"
resolved "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
@@ -3228,13 +3281,6 @@ debug@^4.0.1, debug@^4.1.0, debug@^4.1.1:
dependencies:
ms "^2.1.1"
debug@^4.2.0:
version "4.2.0"
resolved "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1"
integrity sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==
dependencies:
ms "2.1.2"
decamelize@^1.2.0:
version "1.2.0"
resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
@@ -3393,6 +3439,11 @@ dexie@^3.0.2:
resolved "https://registry.npm.taobao.org/dexie/download/dexie-3.0.2.tgz#4b979904d739e0530b68352005f175a82633a075"
integrity sha1-S5eZBNc54FMLaDUgBfF1qCYzoHU=
diff@^4.0.1:
version "4.0.2"
resolved "https://registry.npm.taobao.org/diff/download/diff-4.0.2.tgz?cache=0&sync_timestamp=1604803633979&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdiff%2Fdownload%2Fdiff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
integrity sha1-YPOuy4nV+uUgwRqhnvwruYKq3n0=
diffie-hellman@^5.0.0:
version "5.0.3"
resolved "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
@@ -3479,6 +3530,11 @@ dom-serializer@~0.1.1:
domelementtype "^1.3.0"
entities "^1.1.1"
dom-walk@^0.1.0:
version "0.1.2"
resolved "https://registry.npm.taobao.org/dom-walk/download/dom-walk-0.1.2.tgz?cache=0&sync_timestamp=1585908356502&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdom-walk%2Fdownload%2Fdom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84"
integrity sha1-DFSL7wSPTR8qlySQAiNgYNqj/YQ=
domain-browser@^1.1.1:
version "1.2.0"
resolved "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
@@ -3651,6 +3707,19 @@ electron-localshortcut@^3.2.1:
keyboardevent-from-electron-accelerator "^2.0.0"
keyboardevents-areequal "^0.2.1"
electron-proxy-agent@^1.2.0:
version "1.2.0"
resolved "https://registry.npm.taobao.org/electron-proxy-agent/download/electron-proxy-agent-1.2.0.tgz#35bdbaf80d466cb7f71f20ddf0c11ad7b0aefdb9"
integrity sha1-Nb26+A1GbLf3HyDd8MEa17Cu/bk=
dependencies:
agent-base "2"
debug "2"
extend "3"
get-uri "1"
http-proxy-agent "^4.0.1"
https-proxy-agent "^5.0.0"
socks-proxy-agent "2"
electron-publish@22.7.0:
version "22.7.0"
resolved "https://registry.npmjs.org/electron-publish/-/electron-publish-22.7.0.tgz#d92ba7c4007c9ac1dd070593e48028184fb2dc19"
@@ -3683,19 +3752,19 @@ electron-updater@^4.3.5:
lodash.isequal "^4.5.0"
semver "^7.3.2"
electron@^10.1.4:
version "10.1.4"
resolved "https://registry.npm.taobao.org/electron/download/electron-10.1.4.tgz?cache=0&sync_timestamp=1603157068707&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Felectron%2Fdownload%2Felectron-10.1.4.tgz#5462c5fac5b4728691042d0f62133ea2c133e6fd"
integrity sha1-VGLF+sW0coaRBC0PYhM+osEz5v0=
electron@^10.1.5:
version "10.1.5"
resolved "https://registry.npm.taobao.org/electron/download/electron-10.1.5.tgz#f2b161310f627063e73fbac44efcb35dece83a90"
integrity sha1-8rFhMQ9icGPnP7rETvyzXezoOpA=
dependencies:
"@electron/get" "^1.0.1"
"@types/node" "^12.0.12"
extract-zip "^1.0.3"
element-ui@^2.13.2:
version "2.13.2"
resolved "https://registry.npmjs.org/element-ui/-/element-ui-2.13.2.tgz#582bf47aaaaaafe23ea1958fae217a687ad06447"
integrity sha512-r761DRPssMPKDiJZWFlG+4e4vr0cRG/atKr3Eqr8Xi0tQMNbtmYU1QXvFnKiFPFFGkgJ6zS6ASkG+sellcoHlQ==
element-ui@^2.14.0:
version "2.14.0"
resolved "https://registry.npm.taobao.org/element-ui/download/element-ui-2.14.0.tgz#dcff2718fb485542ea5b5a1f5c0daf1113477b24"
integrity sha1-3P8nGPtIVULqW1ofXA2vERNHeyQ=
dependencies:
async-validator "~1.8.1"
babel-helper-vue-jsx-merge-props "^2.0.0"
@@ -3890,7 +3959,7 @@ eslint-config-standard@^14.1.0:
resolved "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-14.1.1.tgz#830a8e44e7aef7de67464979ad06b406026c56ea"
integrity sha512-Z9B+VR+JIXRxz21udPTL9HpFMyoMUEeX1G251EQ6e05WD9aPVtVBn09XUmZ259wCMlCDmYDSZG62Hhm+ZTJcUg==
eslint-import-resolver-node@^0.3.3:
eslint-import-resolver-node@^0.3.3, eslint-import-resolver-node@^0.3.4:
version "0.3.4"
resolved "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717"
integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==
@@ -3941,17 +4010,17 @@ eslint-plugin-es@^3.0.0:
eslint-utils "^2.0.0"
regexpp "^3.0.0"
eslint-plugin-import@^2.20.2:
version "2.22.0"
resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz#92f7736fe1fde3e2de77623c838dd992ff5ffb7e"
integrity sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg==
eslint-plugin-import@^2.22.1:
version "2.22.1"
resolved "https://registry.npm.taobao.org/eslint-plugin-import/download/eslint-plugin-import-2.22.1.tgz#0896c7e6a0cf44109a2d97b95903c2bb689d7702"
integrity sha1-CJbH5qDPRBCaLZe5WQPCu2iddwI=
dependencies:
array-includes "^3.1.1"
array.prototype.flat "^1.2.3"
contains-path "^0.1.0"
debug "^2.6.9"
doctrine "1.5.0"
eslint-import-resolver-node "^0.3.3"
eslint-import-resolver-node "^0.3.4"
eslint-module-utils "^2.6.0"
has "^1.0.3"
minimatch "^3.0.4"
@@ -3977,10 +4046,10 @@ eslint-plugin-promise@^4.2.1:
resolved "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz#845fd8b2260ad8f82564c1222fce44ad71d9418a"
integrity sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==
eslint-plugin-standard@^4.0.0:
version "4.0.1"
resolved "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz#ff0519f7ffaff114f76d1bd7c3996eef0f6e20b4"
integrity sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ==
eslint-plugin-standard@^4.0.2:
version "4.1.0"
resolved "https://registry.npm.taobao.org/eslint-plugin-standard/download/eslint-plugin-standard-4.1.0.tgz#0c3bf3a67e853f8bbbc580fb4945fbf16f41b7c5"
integrity sha1-DDvzpn6FP4u7xYD7SUX78W9Bt8U=
eslint-plugin-vue@^6.2.2:
version "6.2.2"
@@ -4293,10 +4362,10 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2:
assign-symbols "^1.0.0"
is-extendable "^1.0.1"
extend@~3.0.2:
extend@3, extend@~3.0.0, extend@~3.0.2:
version "3.0.2"
resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
resolved "https://registry.npm.taobao.org/extend/download/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo=
external-editor@^3.0.3:
version "3.1.0"
@@ -4341,6 +4410,11 @@ extsprintf@^1.2.0:
resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
eyes@~0.1.6:
version "0.1.8"
resolved "https://registry.npm.taobao.org/eyes/download/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0"
integrity sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=
fast-deep-equal@^3.1.1:
version "3.1.3"
resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
@@ -4421,6 +4495,11 @@ file-loader@^4.2.0:
loader-utils "^1.2.3"
schema-utils "^2.5.0"
file-uri-to-path@0:
version "0.0.2"
resolved "https://registry.npm.taobao.org/file-uri-to-path/download/file-uri-to-path-0.0.2.tgz#37cdd1b5b905404b3f05e1b23645be694ff70f82"
integrity sha1-N83RtbkFQEs/BeGyNkW+aU/3D4I=
file-uri-to-path@1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
@@ -4687,6 +4766,14 @@ fsevents@~2.1.2:
resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e"
integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==
ftp@~0.3.5:
version "0.3.10"
resolved "https://registry.npm.taobao.org/ftp/download/ftp-0.3.10.tgz#9197d861ad8142f3e63d5a83bfe4c59f7330885d"
integrity sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=
dependencies:
readable-stream "1.1.x"
xregexp "2.0.0"
function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
@@ -4731,6 +4818,18 @@ get-stream@^5.0.0, get-stream@^5.1.0:
dependencies:
pump "^3.0.0"
get-uri@1:
version "1.1.0"
resolved "https://registry.npm.taobao.org/get-uri/download/get-uri-1.1.0.tgz#7375d04daf7fcb584b3632679cbdf339b51bb149"
integrity sha1-c3XQTa9/y1hLNjJnnL3zObUbsUk=
dependencies:
data-uri-to-buffer "0"
debug "2"
extend "3"
file-uri-to-path "0"
ftp "~0.3.5"
readable-stream "2"
get-value@^2.0.3, get-value@^2.0.6:
version "2.0.6"
resolved "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
@@ -4805,6 +4904,14 @@ global-tunnel-ng@^2.7.1:
npm-conf "^1.1.3"
tunnel "^0.0.6"
global@^4.3.2:
version "4.4.0"
resolved "https://registry.npm.taobao.org/global/download/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406"
integrity sha1-PnsQUXkAajI+1xqvyj6cV6XMZAY=
dependencies:
min-document "^2.19.0"
process "^0.11.10"
globals@^11.1.0:
version "11.12.0"
resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
@@ -5001,6 +5108,14 @@ hash.js@^1.0.0, hash.js@^1.0.3:
inherits "^2.0.3"
minimalistic-assert "^1.0.1"
hashring@3.2.x:
version "3.2.0"
resolved "https://registry.npm.taobao.org/hashring/download/hashring-3.2.0.tgz#fda4efde8aa22cdb97fb1d2a65e88401e1c144ce"
integrity sha1-/aTv3oqiLNuX+x0qZeiEAeHBRM4=
dependencies:
connection-parse "0.0.x"
simple-lru-cache "0.0.x"
he@1.2.x, he@^1.1.0:
version "1.2.0"
resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
@@ -5169,6 +5284,15 @@ http-parser-js@>=0.5.1:
resolved "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.2.tgz#da2e31d237b393aae72ace43882dd7e270a8ff77"
integrity sha512-opCO9ASqg5Wy2FNo7A0sxy71yGbbkJJXLdgMK04Tcypw9jr2MgWbyubb0+WdmDmGnFflO7fRbqbaihh/ENDlRQ==
http-proxy-agent@^4.0.1:
version "4.0.1"
resolved "https://registry.npm.taobao.org/http-proxy-agent/download/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a"
integrity sha1-ioyO9/WTLM+VPClsqCkblap0qjo=
dependencies:
"@tootallnate/once" "1"
agent-base "6"
debug "4"
http-proxy-middleware@0.19.1:
version "0.19.1"
resolved "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a"
@@ -5202,6 +5326,14 @@ https-browserify@^1.0.0:
resolved "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
https-proxy-agent@^5.0.0:
version "5.0.0"
resolved "https://registry.npm.taobao.org/https-proxy-agent/download/https-proxy-agent-5.0.0.tgz?cache=0&sync_timestamp=1600349079392&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttps-proxy-agent%2Fdownload%2Fhttps-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2"
integrity sha1-4qkFQqu2inYuCghQ9sntrf2FBrI=
dependencies:
agent-base "6"
debug "4"
human-signals@^1.1.1:
version "1.1.1"
resolved "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
@@ -5398,9 +5530,9 @@ ip-regex@^2.1.0:
resolved "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=
ip@^1.1.0, ip@^1.1.5:
ip@^1.1.0, ip@^1.1.4, ip@^1.1.5:
version "1.1.5"
resolved "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
resolved "https://registry.npm.taobao.org/ip/download/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=
ipaddr.js@1.9.1, ipaddr.js@^1.9.0:
@@ -5724,6 +5856,11 @@ is-yarn-global@^0.3.0:
resolved "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232"
integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==
isarray@0.0.1:
version "0.0.1"
resolved "https://registry.npm.taobao.org/isarray/download/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
@@ -5756,6 +5893,13 @@ isstream@~0.1.2:
resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
jackpot@>=0.0.6:
version "0.0.6"
resolved "https://registry.npm.taobao.org/jackpot/download/jackpot-0.0.6.tgz#3cff064285cbf66f4eab2593c90bce816a821849"
integrity sha1-PP8GQoXL9m9OqyWTyQvOgWqCGEk=
dependencies:
retry "0.6.0"
jake@^10.6.1:
version "10.8.2"
resolved "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz#ebc9de8558160a66d82d0eadc6a2e58fbc500a7b"
@@ -6149,10 +6293,10 @@ loglevel@^1.6.8:
resolved "https://registry.npmjs.org/loglevel/-/loglevel-1.6.8.tgz#8a25fb75d092230ecd4457270d80b54e28011171"
integrity sha512-bsU7+gc9AJ2SqpzxwU3+1fedl8zAntbtC5XYlt3s2j1hJcn2PsXSmgN8TaLG/J1/2mod4+cE/3vNL70/c1RNCA==
loose-envify@^1.0.0:
loose-envify@^1.0.0, loose-envify@^1.2.0:
version "1.4.0"
resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
resolved "https://registry.npm.taobao.org/loose-envify/download/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha1-ce5R+nvkyuwaY4OffmgtgTLTDK8=
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
@@ -6186,6 +6330,15 @@ lru-cache@^5.1.1:
dependencies:
yallist "^3.0.2"
m3u8-parser@^4.5.0:
version "4.5.0"
resolved "https://registry.npm.taobao.org/m3u8-parser/download/m3u8-parser-4.5.0.tgz#9c30b32c9b69cc3f81b5e6789717fa84b9fdb9aa"
integrity sha1-nDCzLJtpzD+BteZ4lxf6hLn9uao=
dependencies:
"@babel/runtime" "^7.5.5"
"@videojs/vhs-utils" "^2.2.1"
global "^4.3.2"
m3u@0.0.2:
version "0.0.2"
resolved "https://mirrors.huaweicloud.com/repository/npm/m3u/-/m3u-0.0.2.tgz#cb971743b434efd8c77b3cc3a47fc0411a903df7"
@@ -6251,6 +6404,14 @@ media-typer@0.3.0:
resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
memcached@^2.2.2:
version "2.2.2"
resolved "https://registry.npm.taobao.org/memcached/download/memcached-2.2.2.tgz#68f86ccfd84bcf93cc25ed46d6d7fc0c7521c9d5"
integrity sha1-aPhsz9hLz5PMJe1G1tf8DHUhydU=
dependencies:
hashring "3.2.x"
jackpot ">=0.0.6"
memory-fs@^0.2.0:
version "0.2.0"
resolved "https://registry.npmjs.org/memory-fs/-/memory-fs-0.2.0.tgz#f2bb25368bc121e391c2520de92969caee0a0290"
@@ -6363,6 +6524,13 @@ mimic-response@^1.0.0, mimic-response@^1.0.1:
resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
min-document@^2.19.0:
version "2.19.0"
resolved "https://registry.npm.taobao.org/min-document/download/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685"
integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=
dependencies:
dom-walk "^0.1.0"
mini-css-extract-plugin@^0.9.0:
version "0.9.0"
resolved "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz#47f2cf07aa165ab35733b1fc97d4c46c0564339e"
@@ -7893,10 +8061,10 @@ read-pkg@^5.1.1:
parse-json "^5.0.0"
type-fest "^0.6.0"
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
"readable-stream@1 || 2", readable-stream@2, readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
version "2.3.7"
resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
resolved "https://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
integrity sha1-Hsoc9xGu+BTAT2IlKjamL2yyO1c=
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.3"
@@ -7906,6 +8074,16 @@ read-pkg@^5.1.1:
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
readable-stream@1.1.x:
version "1.1.14"
resolved "https://registry.npm.taobao.org/readable-stream/download/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk=
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.1"
isarray "0.0.1"
string_decoder "~0.10.x"
readable-stream@^3.0.0, readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.6.0:
version "3.6.0"
resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
@@ -8163,6 +8341,11 @@ ret@~0.1.10:
resolved "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
retry@0.6.0:
version "0.6.0"
resolved "https://registry.npm.taobao.org/retry/download/retry-0.6.0.tgz#1c010713279a6fd1e8def28af0c3ff1871caa537"
integrity sha1-HAEHEyeab9Ho3vKK8MP/GHHKpTc=
retry@^0.12.0:
version "0.12.0"
resolved "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
@@ -8278,10 +8461,10 @@ sass-loader@^8.0.2:
schema-utils "^2.6.1"
semver "^6.3.0"
sass@^1.26.5:
version "1.26.10"
resolved "https://registry.npmjs.org/sass/-/sass-1.26.10.tgz#851d126021cdc93decbf201d1eca2a20ee434760"
integrity sha512-bzN0uvmzfsTvjz0qwccN1sPm2HxxpNI/Xa+7PlUEMS+nQvbyuEK7Y0qFqxlPHhiNHb1Ze8WQJtU31olMObkAMw==
sass@^1.29.0:
version "1.29.0"
resolved "https://registry.npm.taobao.org/sass/download/sass-1.29.0.tgz?cache=0&sync_timestamp=1604536692062&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsass%2Fdownload%2Fsass-1.29.0.tgz#ec4e1842c146d8ea9258c28c141b8c2b7c6ab7f1"
integrity sha1-7E4YQsFG2OqSWMKMFBuMK3xqt/E=
dependencies:
chokidar ">=2.0.0 <4.0.0"
@@ -8352,6 +8535,11 @@ semver@^7.2.1, semver@^7.3.2:
resolved "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
semver@~5.0.1:
version "5.0.3"
resolved "https://registry.npm.taobao.org/semver/download/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a"
integrity sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=
send@0.17.1:
version "0.17.1"
resolved "https://registry.npmjs.org/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
@@ -8420,6 +8608,13 @@ serve-static@1.14.1:
parseurl "~1.3.3"
send "0.17.1"
session@^0.1.0:
version "0.1.0"
resolved "https://registry.npm.taobao.org/session/download/session-0.1.0.tgz#6ae9aa6f26093be31ed2005bcd426ae80aa3a085"
integrity sha1-aumqbyYJO+Me0gBbzUJq6AqjoIU=
dependencies:
vows "*"
set-blocking@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
@@ -8509,6 +8704,11 @@ signal-exit@^3.0.0, signal-exit@^3.0.2:
resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
simple-lru-cache@0.0.x:
version "0.0.2"
resolved "https://registry.npm.taobao.org/simple-lru-cache/download/simple-lru-cache-0.0.2.tgz#d59cc3a193c1a5d0320f84ee732f6e4713e511dd"
integrity sha1-1ZzDoZPBpdAyD4Tucy9uRxPlEd0=
simple-swizzle@^0.2.2:
version "0.2.2"
resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
@@ -8535,6 +8735,11 @@ slice-ansi@^2.1.0:
astral-regex "^1.0.0"
is-fullwidth-code-point "^2.0.0"
smart-buffer@^1.0.13:
version "1.1.15"
resolved "https://registry.npm.taobao.org/smart-buffer/download/smart-buffer-1.1.15.tgz#7f114b5b65fab3e2a35aa775bb12f0d1c649bf16"
integrity sha1-fxFLW2X6s+KjWqd1uxLw0cZJvxY=
snapdragon-node@^2.0.1:
version "2.1.1"
resolved "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
@@ -8586,6 +8791,23 @@ sockjs@0.3.20:
uuid "^3.4.0"
websocket-driver "0.6.5"
socks-proxy-agent@2:
version "2.1.1"
resolved "https://registry.npm.taobao.org/socks-proxy-agent/download/socks-proxy-agent-2.1.1.tgz?cache=0&sync_timestamp=1580846156853&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsocks-proxy-agent%2Fdownload%2Fsocks-proxy-agent-2.1.1.tgz#86ebb07193258637870e13b7bd99f26c663df3d3"
integrity sha1-huuwcZMlhjeHDhO3vZnybGY989M=
dependencies:
agent-base "2"
extend "3"
socks "~1.1.5"
socks@~1.1.5:
version "1.1.10"
resolved "https://registry.npm.taobao.org/socks/download/socks-1.1.10.tgz?cache=0&sync_timestamp=1603684981912&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsocks%2Fdownload%2Fsocks-1.1.10.tgz#5b8b7fc7c8f341c53ed056e929b7bf4de8ba7b5a"
integrity sha1-W4t/x8jzQcU+0FbpKbe/Tei6e1o=
dependencies:
ip "^1.1.4"
smart-buffer "^1.0.13"
sort-keys@^1.0.0:
version "1.1.2"
resolved "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad"
@@ -8593,10 +8815,10 @@ sort-keys@^1.0.0:
dependencies:
is-plain-obj "^1.0.0"
sortablejs@^1.10.1:
version "1.12.0"
resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.12.0.tgz#ee6d7ece3598c2af0feb1559d98595e5ea37cbd6"
integrity sha512-bPn57rCjBRlt2sC24RBsu40wZsmLkSo2XeqG8k6DC1zru5eObQUIPPZAQG7W2SJ8FZQYq+BEJmvuw1Zxb3chqg==
sortablejs@1.10.2:
version "1.10.2"
resolved "https://registry.npm.taobao.org/sortablejs/download/sortablejs-1.10.2.tgz#6e40364d913f98b85a14f6678f92b5c1221f5290"
integrity sha1-bkA2TZE/mLhaFPZnj5K1wSIfUpA=
source-list-map@^2.0.0:
version "2.0.1"
@@ -8861,6 +9083,11 @@ string_decoder@^1.0.0, string_decoder@^1.1.1:
dependencies:
safe-buffer "~5.2.0"
string_decoder@~0.10.x:
version "0.10.31"
resolved "https://registry.npm.taobao.org/string_decoder/download/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=
string_decoder@~1.1.1:
version "1.1.1"
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
@@ -9541,6 +9768,11 @@ url-parse@^1.4.3:
querystringify "^2.1.1"
requires-port "^1.0.0"
url-toolkit@^2.1.6:
version "2.2.1"
resolved "https://registry.npm.taobao.org/url-toolkit/download/url-toolkit-2.2.1.tgz#89009ed3d62a3574de079532a7266c14d2cc1c4f"
integrity sha1-iQCe09YqNXTeB5UypyZsFNLMHE8=
url@^0.11.0:
version "0.11.0"
resolved "https://registry.npmjs.org/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
@@ -9653,6 +9885,15 @@ vm-browserify@^1.0.1:
resolved "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
vows@*:
version "0.8.3"
resolved "https://registry.npm.taobao.org/vows/download/vows-0.8.3.tgz#36e353c2bca3a93902fc32eb8c5baab2e3a93f10"
integrity sha1-NuNTwryjqTkC/DLrjFuqsuOpPxA=
dependencies:
diff "^4.0.1"
eyes "~0.1.6"
glob "^7.1.2"
vue-cli-plugin-electron-builder@2.0.0-rc.4:
version "2.0.0-rc.4"
resolved "https://registry.npmjs.org/vue-cli-plugin-electron-builder/-/vue-cli-plugin-electron-builder-2.0.0-rc.4.tgz#c819279e00fe6771912f5f0468ee26f279750a5b"
@@ -9678,6 +9919,13 @@ vue-cli-plugin-electron-builder@2.0.0-rc.4:
webpack-merge "^4.2.2"
yargs "^15.3.1"
vue-clickaway@^2.2.2:
version "2.2.2"
resolved "https://registry.npm.taobao.org/vue-clickaway/download/vue-clickaway-2.2.2.tgz#cecf6839575e8b2afc5d3edb3efb616d293dbb44"
integrity sha1-zs9oOVdeiyr8XT7bPvthbSk9u0Q=
dependencies:
loose-envify "^1.2.0"
vue-eslint-parser@^7.0.0:
version "7.1.0"
resolved "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.1.0.tgz#9cdbcc823e656b087507a1911732b867ac101e83"
@@ -9742,12 +9990,12 @@ vue@^2.6.12:
resolved "https://registry.npm.taobao.org/vue/download/vue-2.6.12.tgz?cache=0&sync_timestamp=1602778254831&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue%2Fdownload%2Fvue-2.6.12.tgz#f5ebd4fa6bd2869403e29a896aed4904456c9123"
integrity sha1-9evU+mvShpQD4pqJau1JBEVskSM=
vuedraggable@^2.24.2:
version "2.24.2"
resolved "https://registry.npm.taobao.org/vuedraggable/download/vuedraggable-2.24.2.tgz#cd98faec99905238469e9b4d235fba5a59fb7da2"
integrity sha1-zZj67JmQUjhGnptNI1+6Wln7faI=
vuedraggable@^2.24.3:
version "2.24.3"
resolved "https://registry.npm.taobao.org/vuedraggable/download/vuedraggable-2.24.3.tgz?cache=0&sync_timestamp=1603590834453&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvuedraggable%2Fdownload%2Fvuedraggable-2.24.3.tgz#43c93849b746a24ce503e123d5b259c701ba0d19"
integrity sha1-Q8k4SbdGokzlA+Ej1bJZxwG6DRk=
dependencies:
sortablejs "^1.10.1"
sortablejs "1.10.2"
vuex@^3.5.1:
version "3.5.1"
@@ -10052,6 +10300,11 @@ xgplayer@^2.13.0:
pasition "^1.0.1"
request-frame "^1.5.3"
xregexp@2.0.0:
version "2.0.0"
resolved "https://registry.npm.taobao.org/xregexp/download/xregexp-2.0.0.tgz?cache=0&sync_timestamp=1604008197739&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fxregexp%2Fdownload%2Fxregexp-2.0.0.tgz#52a63e56ca0b84a7f3a5f3d61872f126ad7a5943"
integrity sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=
xregexp@^4.2.4:
version "4.3.0"
resolved "https://registry.npmjs.org/xregexp/-/xregexp-4.3.0.tgz#7e92e73d9174a99a59743f67a4ce879a04b5ae50"