mirror of
https://github.com/cuiocean/ZY-Player.git
synced 2026-02-14 16:06:48 +08:00
Compare commits
790 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f846b996b | ||
|
|
2bd5e31a28 | ||
|
|
9d8dc9ecb1 | ||
|
|
2a073e4092 | ||
|
|
b1daa73afe | ||
|
|
18940ff9f7 | ||
|
|
76d4d68401 | ||
|
|
f91200e609 | ||
|
|
b64f500710 | ||
|
|
cf1cfe9f77 | ||
|
|
da4fe162f6 | ||
|
|
d949c52020 | ||
|
|
1ce9e0525b | ||
|
|
4ebf82eae0 | ||
|
|
e0b1a5332d | ||
|
|
3ecb4302ba | ||
|
|
5c39db8ca6 | ||
|
|
4f45045d18 | ||
|
|
b7733179f2 | ||
|
|
e1f7044ae0 | ||
|
|
93e76db444 | ||
|
|
6eaa281e4a | ||
|
|
490d34e1fb | ||
|
|
0d0d6bd90f | ||
|
|
ecdc96d2f3 | ||
|
|
234f6dd069 | ||
|
|
f80fe7ecf1 | ||
|
|
6876721567 | ||
|
|
bedd1339df | ||
|
|
0a3a7a4d57 | ||
|
|
786e23f5a2 | ||
|
|
418f14bcc1 | ||
|
|
a9e4a34e4f | ||
|
|
fede7e4ef2 | ||
|
|
956ebbf8b8 | ||
|
|
014dac0b64 | ||
|
|
5fc1020e79 | ||
|
|
aca487f796 | ||
|
|
429eb4aac0 | ||
|
|
e032f86d3d | ||
|
|
f92af48a4e | ||
|
|
eff69db063 | ||
|
|
a5c8d20635 | ||
|
|
da22abd25d | ||
|
|
2dd91f78c9 | ||
|
|
a8b0e7e6a8 | ||
|
|
39edb9ce35 | ||
|
|
3323a56671 | ||
|
|
4dc88469e8 | ||
|
|
b04201f803 | ||
|
|
f34da7ff85 | ||
|
|
b8f010c4f5 | ||
|
|
f876b863e7 | ||
|
|
384ae10475 | ||
|
|
647c540f0b | ||
|
|
87d01da241 | ||
|
|
641bdf00d3 | ||
|
|
31510624c1 | ||
|
|
d5c4e296c3 | ||
|
|
f55065472d | ||
|
|
525da05c5f | ||
|
|
de8c51918f | ||
|
|
17229eb6b4 | ||
|
|
d4530eef89 | ||
|
|
cb68da5a22 | ||
|
|
c21f6538f3 | ||
|
|
729dab765c | ||
|
|
8521de2844 | ||
|
|
6ec7dffd59 | ||
|
|
51fccb699a | ||
|
|
525d6af888 | ||
|
|
5a17d1b991 | ||
|
|
edef20d171 | ||
|
|
e912804fcc | ||
|
|
3165345839 | ||
|
|
7133c8982a | ||
|
|
26c1ba1e62 | ||
|
|
4e83e365a6 | ||
|
|
03775b091d | ||
|
|
9147a8e1fb | ||
|
|
0d84e20326 | ||
|
|
d421a5cfe4 | ||
|
|
46fc5a0942 | ||
|
|
60aac3944e | ||
|
|
4683223a68 | ||
|
|
86856397f6 | ||
|
|
09e6af6f18 | ||
|
|
18db5a1eb0 | ||
|
|
d116f08550 | ||
|
|
7441341658 | ||
|
|
9b71355803 | ||
|
|
aba07ea20b | ||
|
|
790ea92180 | ||
|
|
1dc683e332 | ||
|
|
82df96e4d0 | ||
|
|
bb1e31a270 | ||
|
|
1d8d9ae72f | ||
|
|
6dfe3bea95 | ||
|
|
6fcb6ad16c | ||
|
|
c692ed2100 | ||
|
|
26bcdd4101 | ||
|
|
5104f9a85d | ||
|
|
d61ee76e58 | ||
|
|
b1a683a8db | ||
|
|
5d0dc1bed7 | ||
|
|
3481a5346e | ||
|
|
c957fe33e2 | ||
|
|
51aa21e551 | ||
|
|
a887968458 | ||
|
|
380d31c0d3 | ||
|
|
46b5f82348 | ||
|
|
675622e9ee | ||
|
|
9a67821984 | ||
|
|
e457574755 | ||
|
|
50f5154628 | ||
|
|
9da7ffc451 | ||
|
|
35adae51cc | ||
|
|
fe75edd738 | ||
|
|
362dccb167 | ||
|
|
08e95611ea | ||
|
|
739b3fe30f | ||
|
|
3ba2dc9993 | ||
|
|
6543d8baf0 | ||
|
|
a1c9c657e3 | ||
|
|
9306adb60e | ||
|
|
682c706618 | ||
|
|
02c04c3d46 | ||
|
|
17c78522bb | ||
|
|
7af6c73084 | ||
|
|
d31e0daca9 | ||
|
|
9a7534ba57 | ||
|
|
a73e679b72 | ||
|
|
4f6c248345 | ||
|
|
68a0226759 | ||
|
|
e72af95c75 | ||
|
|
559e85785f | ||
|
|
2bf69fb0b9 | ||
|
|
c082986e09 | ||
|
|
05d71a62aa | ||
|
|
bb537d789d | ||
|
|
11baacc778 | ||
|
|
9dbc0e00dc | ||
|
|
23e5c569b1 | ||
|
|
59a89e280b | ||
|
|
b72886fbe6 | ||
|
|
75bac6582c | ||
|
|
7cc7e4e0e6 | ||
|
|
b1707f88d6 | ||
|
|
9ca946eb66 | ||
|
|
76ed091c78 | ||
|
|
5965c55773 | ||
|
|
6631b8f568 | ||
|
|
b7bb5f85a3 | ||
|
|
c8795e2aa9 | ||
|
|
2d7f012180 | ||
|
|
95ae729df8 | ||
|
|
40218521ac | ||
|
|
f4396cb69f | ||
|
|
2dfbc8a8a2 | ||
|
|
f94e8f0bec | ||
|
|
a9011abdf0 | ||
|
|
843a8dd1fc | ||
|
|
9b5aae095e | ||
|
|
24e890d1ab | ||
|
|
959f515f55 | ||
|
|
f97d63cf68 | ||
|
|
c2f3a60198 | ||
|
|
9128f407ce | ||
|
|
c5c6e5e34f | ||
|
|
b12cdf25d5 | ||
|
|
7c08627e6f | ||
|
|
68c3687da3 | ||
|
|
00d6f2d218 | ||
|
|
a918713bf7 | ||
|
|
ae7aaec623 | ||
|
|
81476e0f20 | ||
|
|
4136b0f3ce | ||
|
|
c3a4cf5cc5 | ||
|
|
d2263f3f76 | ||
|
|
71df73fbd3 | ||
|
|
ba6f3df9b1 | ||
|
|
35c205fd86 | ||
|
|
30796af5f8 | ||
|
|
fde5dbb89d | ||
|
|
df3b43d8ac | ||
|
|
8f94a5604d | ||
|
|
c6a39591d5 | ||
|
|
051d6b7701 | ||
|
|
51ba1d87ad | ||
|
|
9af55df310 | ||
|
|
d82251fb02 | ||
|
|
4d192a4c3a | ||
|
|
1f25219cdc | ||
|
|
25d65866ae | ||
|
|
11559ca164 | ||
|
|
6c82178604 | ||
|
|
029d1d9b49 | ||
|
|
c10f7b98d9 | ||
|
|
48d4b369a8 | ||
|
|
42d2b5c20f | ||
|
|
ccbafaae39 | ||
|
|
fb3b908fe8 | ||
|
|
4c4cc6d81b | ||
|
|
9ccfefaafb | ||
|
|
15a38f1b9c | ||
|
|
967657e0ac | ||
|
|
cd08e9e14b | ||
|
|
7e5bd534ef | ||
|
|
dce2e36ef0 | ||
|
|
8a72b30f79 | ||
|
|
bbe0d157f4 | ||
|
|
f44f8ea6cf | ||
|
|
cd6f9f1f53 | ||
|
|
74d084cb7b | ||
|
|
e60962a0f5 | ||
|
|
459a54382f | ||
|
|
e08a90d87a | ||
|
|
c676159cc7 | ||
|
|
0fc8e54d26 | ||
|
|
fe858a0cd9 | ||
|
|
2238ddd109 | ||
|
|
cc1c100075 | ||
|
|
81ba6de6cb | ||
|
|
28baca56c4 | ||
|
|
3493831729 | ||
|
|
42fce7d137 | ||
|
|
c7a4b389e1 | ||
|
|
5f47789a1a | ||
|
|
7591c30b59 | ||
|
|
dd43c18491 | ||
|
|
6949eb16d6 | ||
|
|
4a369a755e | ||
|
|
e1b1742424 | ||
|
|
de31c4c0bb | ||
|
|
c85910edd0 | ||
|
|
b8d78bab10 | ||
|
|
9eed5ce0b7 | ||
|
|
4b11cab4bf | ||
|
|
6ffbc2a63c | ||
|
|
c6f4917cdc | ||
|
|
fe37b32a0f | ||
|
|
7fb295d34c | ||
|
|
e8c5c0ec72 | ||
|
|
64dc9c98d2 | ||
|
|
ca36841f5d | ||
|
|
59d33d201c | ||
|
|
bf3b6d4088 | ||
|
|
bf2567bfde | ||
|
|
3499fb5937 | ||
|
|
dec12c77d0 | ||
|
|
17be5d45f1 | ||
|
|
f493fcd24e | ||
|
|
d040bc01fc | ||
|
|
6644c97811 | ||
|
|
68960ab5bb | ||
|
|
46de044214 | ||
|
|
0cbf9ca7fb | ||
|
|
6fa40af9bd | ||
|
|
7343f1824a | ||
|
|
3df0665950 | ||
|
|
022b1b28ad | ||
|
|
55d1740354 | ||
|
|
9d71991103 | ||
|
|
361e24ecad | ||
|
|
53f80d2cce | ||
|
|
880dd9ff35 | ||
|
|
42c89120da | ||
|
|
d990aa92b0 | ||
|
|
e117564ecb | ||
|
|
99592e3fcb | ||
|
|
adc8fd4329 | ||
|
|
579caddaeb | ||
|
|
1d5344f292 | ||
|
|
22dc74ea3a | ||
|
|
72d7c91540 | ||
|
|
ef874d1831 | ||
|
|
bb9a8ca65d | ||
|
|
747abf3b26 | ||
|
|
1078cf3c63 | ||
|
|
22b877b0fb | ||
|
|
34e6b8bd08 | ||
|
|
4d039e9a63 | ||
|
|
16f3954959 | ||
|
|
17845e6ab4 | ||
|
|
292f932130 | ||
|
|
127ef9ad43 | ||
|
|
11f0ae27fd | ||
|
|
2599343943 | ||
|
|
0fb5903416 | ||
|
|
ce89720c55 | ||
|
|
8ff7fa588a | ||
|
|
8d5bbedfd8 | ||
|
|
713e0affae | ||
|
|
0f55f3b2ea | ||
|
|
c98e41201d | ||
|
|
2cfd31806d | ||
|
|
d54dab4e90 | ||
|
|
2af85fbfd1 | ||
|
|
15c542db82 | ||
|
|
1a3ccaa3ba | ||
|
|
3d01fd045f | ||
|
|
f6636a7864 | ||
|
|
dd108d3b09 | ||
|
|
0b24ded61f | ||
|
|
d21494cf86 | ||
|
|
76add8f87a | ||
|
|
5a115700e3 | ||
|
|
16e8ef2c4a | ||
|
|
483449aad8 | ||
|
|
2b7a425f6f | ||
|
|
a06c9e9d32 | ||
|
|
32a21952a2 | ||
|
|
ff01abe88c | ||
|
|
962f6b46c3 | ||
|
|
b16604add6 | ||
|
|
3028939ed9 | ||
|
|
1ffcb38b4b | ||
|
|
2ec05b6ab5 | ||
|
|
9cbd37d143 | ||
|
|
b9ab1b11f4 | ||
|
|
428f49a2e8 | ||
|
|
2e8941c6cc | ||
|
|
91e2fc56b7 | ||
|
|
e2b124e4ac | ||
|
|
6b37e3ebd5 | ||
|
|
5dcdb6a410 | ||
|
|
5d41f783bc | ||
|
|
28ad8f3313 | ||
|
|
c475fbdf46 | ||
|
|
ee622f88da | ||
|
|
1b2461c423 | ||
|
|
3044bfcbc4 | ||
|
|
4038e5e6be | ||
|
|
bea1ef4c73 | ||
|
|
7af9a6d76d | ||
|
|
2140d90a87 | ||
|
|
e86eef1b05 | ||
|
|
42dd8fe5e4 | ||
|
|
9fd8c60dd5 | ||
|
|
49c480061b | ||
|
|
022b1f4090 | ||
|
|
9c08a64524 | ||
|
|
90ec848c11 | ||
|
|
82270a702f | ||
|
|
61dcb1ec49 | ||
|
|
40b853361e | ||
|
|
57ff3325f0 | ||
|
|
c4283e2da0 | ||
|
|
7052bd7e05 | ||
|
|
64a12a06c4 | ||
|
|
3df3b385ce | ||
|
|
e77db4711e | ||
|
|
fb3fd26870 | ||
|
|
72790f5f3e | ||
|
|
ea2815969d | ||
|
|
e330cff7d4 | ||
|
|
da5b91535e | ||
|
|
00c8f0c1e2 | ||
|
|
924fd439d9 | ||
|
|
ed039894c8 | ||
|
|
005bdf7ea6 | ||
|
|
19071faf70 | ||
|
|
176d9f6b5a | ||
|
|
31a8dd0f32 | ||
|
|
336ea08c69 | ||
|
|
8e4a0870a1 | ||
|
|
86130e6c53 | ||
|
|
e984d0a349 | ||
|
|
506991f3b1 | ||
|
|
04c35ba7a9 | ||
|
|
275b6757bf | ||
|
|
612930cc8b | ||
|
|
80e36fa99c | ||
|
|
f069044f28 | ||
|
|
c77ac7ea7f | ||
|
|
803181b4f7 | ||
|
|
ac2474903d | ||
|
|
04b7e139da | ||
|
|
b49e1b82bf | ||
|
|
dc00c690e7 | ||
|
|
44ba552435 | ||
|
|
8d84d1bf22 | ||
|
|
c78368dac9 | ||
|
|
11af5a7ecd | ||
|
|
ecfeecf45f | ||
|
|
455f5dae84 | ||
|
|
ffbffde74f | ||
|
|
0be0433355 | ||
|
|
cc2dc19e39 | ||
|
|
aa4583898a | ||
|
|
2e96812a1f | ||
|
|
6f52d73d52 | ||
|
|
a3ebba641f | ||
|
|
8ceffab2fe | ||
|
|
454d192141 | ||
|
|
a1423993c8 | ||
|
|
1c9a84dbc6 | ||
|
|
304b0d10b4 | ||
|
|
aff97f6d46 | ||
|
|
650c882f58 | ||
|
|
32fa465cf2 | ||
|
|
1fdfada14f | ||
|
|
5ed8b6e49a | ||
|
|
c2e2f1c490 | ||
|
|
7ad40ba375 | ||
|
|
c708292051 | ||
|
|
79932a74bc | ||
|
|
3f79f31550 | ||
|
|
1d33db0143 | ||
|
|
1dc7b38160 | ||
|
|
db7cdab787 | ||
|
|
d1e6ac1ae6 | ||
|
|
d63710afe6 | ||
|
|
8abe4b7ef8 | ||
|
|
98b4f5bc1d | ||
|
|
248c0994c9 | ||
|
|
2eba0523bc | ||
|
|
49589102d9 | ||
|
|
79b02df628 | ||
|
|
0f456fe7a8 | ||
|
|
850c8d5423 | ||
|
|
63cf367f52 | ||
|
|
bd43f06e7d | ||
|
|
2ed47e64c3 | ||
|
|
8817d39d49 | ||
|
|
b68525213a | ||
|
|
0efbc38137 | ||
|
|
cd2cb684a5 | ||
|
|
500dbfa1ee | ||
|
|
e970074266 | ||
|
|
9dc7ab4d1e | ||
|
|
ffe821d107 | ||
|
|
0f015b26e2 | ||
|
|
f031f9e7fd | ||
|
|
b38de7f393 | ||
|
|
8b5e8fd072 | ||
|
|
58e556554e | ||
|
|
cceed30d35 | ||
|
|
980b0a6e50 | ||
|
|
c98236222d | ||
|
|
6a7c2afb2d | ||
|
|
af482a450a | ||
|
|
42b81b98cf | ||
|
|
da7dfed5ba | ||
|
|
7d6c5482af | ||
|
|
11e7ffc554 | ||
|
|
4974d57fbf | ||
|
|
037bb1a2ff | ||
|
|
b19870d228 | ||
|
|
de0161c560 | ||
|
|
623a10bd13 | ||
|
|
c69eadbe3e | ||
|
|
5f48f46cbc | ||
|
|
694986d6c5 | ||
|
|
d4ad68e030 | ||
|
|
72089bf53f | ||
|
|
0401ce6d7e | ||
|
|
09e27d4f40 | ||
|
|
45de6650bf | ||
|
|
4e0fa4d980 | ||
|
|
7a0f8f9644 | ||
|
|
e43ef98ce7 | ||
|
|
2abbf41ed1 | ||
|
|
02139d3d24 | ||
|
|
d86a10d753 | ||
|
|
dc8bdb29dc | ||
|
|
98b019be5f | ||
|
|
e6d1698d62 | ||
|
|
6c1e6c511f | ||
|
|
1a1393615c | ||
|
|
5930690144 | ||
|
|
091493fa77 | ||
|
|
cd1c4eaffe | ||
|
|
1bb217d84f | ||
|
|
92eac6d2dd | ||
|
|
b067cfa143 | ||
|
|
99d21fd7fe | ||
|
|
b167f711d0 | ||
|
|
7d4ffeed87 | ||
|
|
7e94ef8025 | ||
|
|
1a36bc85b9 | ||
|
|
f7ed0e1c29 | ||
|
|
970a359aba | ||
|
|
be0441d042 | ||
|
|
3fc350e6d6 | ||
|
|
b26a4d4f27 | ||
|
|
454ea48891 | ||
|
|
d564d0928b | ||
|
|
2562119bad | ||
|
|
1a7aaa8dff | ||
|
|
583a768068 | ||
|
|
6216ad96d6 | ||
|
|
766b1d458f | ||
|
|
6a0699ec20 | ||
|
|
a6fd748e09 | ||
|
|
064ff38650 | ||
|
|
1c74174a3a | ||
|
|
0625c4945f | ||
|
|
e1d0643c68 | ||
|
|
bce10b906c | ||
|
|
d485a5733e | ||
|
|
5ab5cee6dc | ||
|
|
235e894f66 | ||
|
|
ee62ae0c8f | ||
|
|
f8b95fe430 | ||
|
|
a3fc5dba79 | ||
|
|
e1cee12222 | ||
|
|
6d2b1720b7 | ||
|
|
1c7024a68a | ||
|
|
8729184ba9 | ||
|
|
618fdf03d9 | ||
|
|
ac573b0de4 | ||
|
|
6b225d5076 | ||
|
|
cb2ce525ae | ||
|
|
8b78aafda4 | ||
|
|
3a02a5d1cf | ||
|
|
4212cc681a | ||
|
|
015595eb0a | ||
|
|
4ea00a9d8f | ||
|
|
6e19a08186 | ||
|
|
940dbe3d17 | ||
|
|
222e89c24d | ||
|
|
24af7c3084 | ||
|
|
34d981c6a6 | ||
|
|
2e5f5a8d6d | ||
|
|
1565d39ba7 | ||
|
|
24b84e4b12 | ||
|
|
c138f1beb5 | ||
|
|
4589856721 | ||
|
|
f2fbf96a04 | ||
|
|
8a0bb9a3f1 | ||
|
|
8cf2a92673 | ||
|
|
40c32a9085 | ||
|
|
7ef5283562 | ||
|
|
454287ede5 | ||
|
|
77792f0ca4 | ||
|
|
d793605367 | ||
|
|
0a13bac9e6 | ||
|
|
5b54279e9a | ||
|
|
e1e115643e | ||
|
|
826375c233 | ||
|
|
ae33d47186 | ||
|
|
a7d07ed964 | ||
|
|
95db790529 | ||
|
|
2d406c0c24 | ||
|
|
7b39be271f | ||
|
|
d8367414a2 | ||
|
|
d647d2ecec | ||
|
|
7f9f847d73 | ||
|
|
36e0b140cd | ||
|
|
99948770ff | ||
|
|
5300d777ce | ||
|
|
64da42524d | ||
|
|
1ebdfee7bc | ||
|
|
17ba319157 | ||
|
|
27bdc3559d | ||
|
|
ca53a22598 | ||
|
|
6632318cf6 | ||
|
|
cb7a4af7ae | ||
|
|
25340b79aa | ||
|
|
381b0a8735 | ||
|
|
c7b99244bb | ||
|
|
5b5826e9a6 | ||
|
|
03e2f2673b | ||
|
|
503a90d8da | ||
|
|
afb92d59ff | ||
|
|
d26f1cbdf7 | ||
|
|
7f821b05ad | ||
|
|
746c93c9d2 | ||
|
|
9fb51ed8fc | ||
|
|
6a1c045e0b | ||
|
|
756b8ecc33 | ||
|
|
b4946a6c99 | ||
|
|
cbde4180ab | ||
|
|
00dab782e8 | ||
|
|
89d6183841 | ||
|
|
efd2095261 | ||
|
|
cbedb859c3 | ||
|
|
65aedc84cf | ||
|
|
95c58095ee | ||
|
|
b5da3c7f81 | ||
|
|
5b0211b2ed | ||
|
|
0bb6409687 | ||
|
|
7078e05668 | ||
|
|
0172a204b1 | ||
|
|
c6b0781a02 | ||
|
|
b3e67bcc7d | ||
|
|
cbca6db97e | ||
|
|
814ecaf25b | ||
|
|
4a07520336 | ||
|
|
2e121a901c | ||
|
|
3a2a16a168 | ||
|
|
881ab6cfa5 | ||
|
|
3151b33a23 | ||
|
|
f154f44772 | ||
|
|
a1458cf8bf | ||
|
|
595136c799 | ||
|
|
b7e497e2d9 | ||
|
|
dce8ad2ef2 | ||
|
|
79ba45b63a | ||
|
|
b6fcbcb934 | ||
|
|
54c4409311 | ||
|
|
5e9c273048 | ||
|
|
197df4e830 | ||
|
|
5271dfa490 | ||
|
|
7efde45aed | ||
|
|
4c92918dc3 | ||
|
|
6c0bd5125b | ||
|
|
785f9b20e7 | ||
|
|
8d052d2904 | ||
|
|
69a397e24e | ||
|
|
c216352268 | ||
|
|
89448d390f | ||
|
|
a853b02aa0 | ||
|
|
0443ce248f | ||
|
|
8009c3197e | ||
|
|
978d4e7181 | ||
|
|
138b70263a | ||
|
|
7f48c91f97 | ||
|
|
7a494a54c0 | ||
|
|
97812af0fd | ||
|
|
490d7c963e | ||
|
|
ed1afa2026 | ||
|
|
7ef114d0e3 | ||
|
|
7f9b7fc2c8 | ||
|
|
511820f873 | ||
|
|
af6dcb11bf | ||
|
|
7ecad1ad8e | ||
|
|
4d169f9d51 | ||
|
|
f3862e8385 | ||
|
|
490d4839b7 | ||
|
|
033bcb3df7 | ||
|
|
df22efa980 | ||
|
|
5428891297 | ||
|
|
bb3502774b | ||
|
|
fa67ad03d2 | ||
|
|
8a196ae52a | ||
|
|
ebfb681205 | ||
|
|
ba9f3246d2 | ||
|
|
51cb181acd | ||
|
|
33537638b0 | ||
|
|
fa9f85a177 | ||
|
|
3e1ecaac74 | ||
|
|
5cc9849e8a | ||
|
|
e353b629c5 | ||
|
|
4d20d5bc68 | ||
|
|
a921ce7adf | ||
|
|
1dd8d0dd24 | ||
|
|
b90c359670 | ||
|
|
27eb8c06ff | ||
|
|
add2bedb61 | ||
|
|
3dc970e198 | ||
|
|
3f2def4455 | ||
|
|
5b8d883af4 | ||
|
|
7113567475 | ||
|
|
e30da35e72 | ||
|
|
55b7396a2e | ||
|
|
83568fa499 | ||
|
|
838d3a64cd | ||
|
|
506be03e3e | ||
|
|
cfdb561473 | ||
|
|
ab2f45189f | ||
|
|
f4b9a73b18 | ||
|
|
6f99d789f4 | ||
|
|
e71090dad2 | ||
|
|
afe3351837 | ||
|
|
5dc0613aeb | ||
|
|
1c6385ae6c | ||
|
|
88a95a8bfb | ||
|
|
951e6ffa37 | ||
|
|
b83aed0a97 | ||
|
|
67ce537039 | ||
|
|
975562a66b | ||
|
|
8e7015c9d6 | ||
|
|
b841552dc7 | ||
|
|
0a9b939dc3 | ||
|
|
14ff252cce | ||
|
|
afd016be93 | ||
|
|
9cd7f7d267 | ||
|
|
8a76ec4e87 | ||
|
|
a00d965ce9 | ||
|
|
c9eb0c3e22 | ||
|
|
c80c0bd948 | ||
|
|
65dcfa04ae | ||
|
|
4e4ab82ea2 | ||
|
|
dd2adf4f99 | ||
|
|
777fbde528 | ||
|
|
472898f978 | ||
|
|
7f41d415f1 | ||
|
|
5d37a36c21 | ||
|
|
3a499766af | ||
|
|
cea797b6d0 | ||
|
|
37b41b0e20 | ||
|
|
1105c46f08 | ||
|
|
1df7b41edd | ||
|
|
f76c71c950 | ||
|
|
cd77384bd9 | ||
|
|
64adc9d6c1 | ||
|
|
e9095e50a6 | ||
|
|
acfa742b4f | ||
|
|
a79c48cba0 | ||
|
|
904ef5ccea | ||
|
|
3db281c87f | ||
|
|
076e6e99e4 | ||
|
|
32f6ac0310 | ||
|
|
b8706ea432 | ||
|
|
509d6c7900 | ||
|
|
51454d828c | ||
|
|
59449886f5 | ||
|
|
601e9895cc | ||
|
|
1ba8b46990 | ||
|
|
7ed34caa56 | ||
|
|
fc40521420 | ||
|
|
cfdd836e01 | ||
|
|
083e00ddbf | ||
|
|
c41c7c4857 | ||
|
|
4bde51dc38 | ||
|
|
38c7540145 | ||
|
|
a44579d4a1 | ||
|
|
7f2d6f12c0 | ||
|
|
daf1c4ddb6 | ||
|
|
c1372c5589 | ||
|
|
c623533271 | ||
|
|
069e7e16d6 | ||
|
|
cabe4240f4 | ||
|
|
5448e86109 | ||
|
|
536f6dad7d | ||
|
|
bf2796779f | ||
|
|
3a29147fd6 | ||
|
|
e987ecc446 | ||
|
|
9aee6d8527 | ||
|
|
4d438fcdd3 | ||
|
|
36e40f4778 | ||
|
|
422def0702 | ||
|
|
fc52d79d88 | ||
|
|
cc09d0aca0 | ||
|
|
b514f1c04e | ||
|
|
189e67eb22 | ||
|
|
e5c3adf1c5 | ||
|
|
299367f0b8 | ||
|
|
0d67474459 | ||
|
|
15a188aa85 | ||
|
|
0555badcfa | ||
|
|
6f8f700dfc | ||
|
|
001772d75c | ||
|
|
a2d2215646 | ||
|
|
053853f036 | ||
|
|
d4ea77b961 | ||
|
|
1cd91aada2 | ||
|
|
f3aa8c1f51 | ||
|
|
ce73a9a095 | ||
|
|
504fc7fc47 | ||
|
|
ac56980317 | ||
|
|
c1043d9197 | ||
|
|
8902282fe2 | ||
|
|
e0ae32027a | ||
|
|
f5ffca0c52 | ||
|
|
a95f915328 | ||
|
|
1badcea9f3 | ||
|
|
a448825ed2 | ||
|
|
708b6bbd3a | ||
|
|
7ded9a8485 | ||
|
|
57d60e9400 | ||
|
|
e01254c1c4 | ||
|
|
a007e62e38 | ||
|
|
117c805e3c | ||
|
|
529558b754 | ||
|
|
3b86ccd0d8 | ||
|
|
508a3af4b3 | ||
|
|
a010d8f11e | ||
|
|
d1a3c404fa | ||
|
|
1dbd07faae | ||
|
|
4dec62aa9c | ||
|
|
1f781ae92d | ||
|
|
4717299ae6 | ||
|
|
8d40cbd5fc | ||
|
|
4c8fa08166 | ||
|
|
ac513fbce6 | ||
|
|
9321d3a5d9 | ||
|
|
0f2776fb1c | ||
|
|
b577ce12c1 | ||
|
|
fa4c4e22fd | ||
|
|
a93d4042ba | ||
|
|
09bd9d8401 | ||
|
|
588e52c330 | ||
|
|
6c4e110bb8 | ||
|
|
54857b8501 | ||
|
|
a8a6fa2185 | ||
|
|
0e571efd6f | ||
|
|
79adbd1f81 |
28
.github/ISSUE_TEMPLATE/bug.md
vendored
Normal file
28
.github/ISSUE_TEMPLATE/bug.md
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
name: 报告Bug(请先查看常见问题及搜索issue列表中有无你要提的问题)
|
||||
about: 创建报告以帮助我们改进
|
||||
title: '(未回答的问题请删除)'
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
||||
**描述错误**
|
||||
清楚简洁地说明错误是什么。
|
||||
|
||||
**重现**
|
||||
重现行为的步骤
|
||||
|
||||
**预期行为**
|
||||
对您期望发生的事情的简洁明了的描述。
|
||||
|
||||
**截图**
|
||||
如果适用,请添加屏幕截图以帮助解释您的问题(直接把图片拖到编辑框即可添加图片)。
|
||||
|
||||
**环境:**
|
||||
-操作系统及版本:[例如:Windows 10 64位 18362.156]
|
||||
-软件安装包及版本:[例如:Windows 64位绿色版 1.0.0]
|
||||
|
||||
**其他内容**
|
||||
在此处添加有关该问题的任何其他上下文。
|
||||
17
.github/ISSUE_TEMPLATE/feature.md
vendored
Normal file
17
.github/ISSUE_TEMPLATE/feature.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: 功能请求(请先查看常见问题及搜索issue列表中有无你要提的问题)
|
||||
about: 为这个项目提出一个想法
|
||||
title: 例如:添加xxx功能、优化xxx功能(未回答的问题请删除)
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**描述您想要的解决方案**
|
||||
简洁明了地描述您要发生的事情。
|
||||
|
||||
**描述您考虑过的替代方案**
|
||||
对您考虑过的所有替代解决方案或功能的简洁明了的描述。
|
||||
|
||||
**其他内容**
|
||||
在此处添加有关功能请求的任何其他上下文或屏幕截图(直接把图片拖到编辑框即可添加图片)。
|
||||
19
.github/ISSUE_TEMPLATE/help.md
vendored
Normal file
19
.github/ISSUE_TEMPLATE/help.md
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
name: 需要帮助
|
||||
about: "其它问题"
|
||||
labels: help wanted
|
||||
|
||||
---
|
||||
|
||||
### 版本、安装方式、系统
|
||||
|
||||
1. 你在使用什么版本的
|
||||
|
||||
2. 你通过什么方式安装
|
||||
|
||||
3. 你所使用的操作系统
|
||||
|
||||
|
||||
### 描述问题:
|
||||
|
||||
<!-- 在下方描述问题 -->
|
||||
35
.github/workflows/x86.yml
vendored
Normal file
35
.github/workflows/x86.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
name: release-build
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- x86-v*
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12
|
||||
|
||||
- run: |
|
||||
yarn
|
||||
yarn dist
|
||||
shell: pwsh
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: dist_electron
|
||||
path: dist_electron/*.exe
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -10,6 +10,7 @@ node_modules
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
|
||||
101
README.md
101
README.md
@@ -22,61 +22,66 @@
|
||||
<p>
|
||||
|
||||
|
||||
## ZY Player 资源播放器
|
||||
<h1 align="center">ZY Player 资源播放器</h1>
|
||||
|
||||
1. 全平台支持. Windows, Mac, Linux
|
||||
2. 12个视频源. 未来更新更多的视频源
|
||||
3. 新增历史播放记录, 并记录播放进度
|
||||
4. 新增分享功能. 一键分享海报图片
|
||||
5. 新增精简模式. 支持修改透明度
|
||||
6. 收藏夹同步更新视频追剧
|
||||
7. 支持演员名称搜索
|
||||
8. 更详细的视频分类
|
||||
9. 后台自动更新
|
||||
10. 全新布局配色
|
||||
11. 新增多语言
|
||||
12. 全局快捷键
|
||||
13. 下载功能
|
||||
14. ...
|
||||
|
||||
觉得软件不错的, 点击右上角 star 收藏关注一波呀~
|
||||
|
||||
> Tips: 资源加载不出来时, 点击列表下方链接, 浏览器打开一下网站. 原理是需要通过网站的人机检测.
|
||||
### ✨特性
|
||||
|
||||
#### 全局快捷键:
|
||||
- 🍕 全平台支持. Windows, Mac, Linux
|
||||
- 🍥 支持 IPTV, 卫视直播
|
||||
- 🍔 视频源支持自定义, 支持导入, 导出
|
||||
- 🍟 支持海报模式和列表模式浏览资源
|
||||
- 🌭 播放历史, 自动跳转历史进度
|
||||
- 🍿 收藏夹支持导入,导出, 支持同步追剧
|
||||
- 🥙 支持精简模式, 摸鱼划水
|
||||
- 🥪 一键搜索所有资源, 支持历史搜索记录
|
||||
- 🌮 导出资源下载链接
|
||||
- 🍣 支持第三方播放器播放
|
||||
- 🍤 显示豆瓣评分
|
||||
|
||||
| 快捷键 | 说明 | 主界面 | 小窗口 |
|
||||
| :----------------------: | ---------- | :----: | :----: |
|
||||
| `⌘ + →` 或 `Ctrl + →` | 下一集 | √ | √ |
|
||||
| `⌘ + ←` 或 `Ctrl + ←` | 上一集 | √ | √ |
|
||||
| `⌘ + ↑` 或 `Ctrl + ↑` | 减少透明度 | | √ |
|
||||
| `⌘ + ↓` 或 `Ctrl + ↓` | 增加透明度 | | √ |
|
||||
| `Shift + ↑` | 增加倍速 + 0.25 | √ | √ |
|
||||
| `Shift + ↓` | 减少倍速 - 0.25 | √ | √ |
|
||||
### 🌴 下载
|
||||
|
||||
#### 下载:
|
||||
- 🍓 [Github -- 官方下载](https://github.com/Hunlongyu/ZY-Player/releases)
|
||||
- 🍉 [蓝奏云 -- 快速下载](https://www.lanzoux.com/b04s6a3re) 密码:95px
|
||||
- 🍒 适用于32位操作系统的x86软件,在蓝奏云网盘里, 后缀名: ZY Player * 32位.exe
|
||||
|
||||
1. [Github -- 官方下载](https://github.com/Hunlongyu/ZY-Player/releases)
|
||||
### 🚀 快捷键
|
||||
|
||||
2. [蓝奏云 -- 快速下载](https://www.lanzous.com/b04s6a3re) 密码:95px
|
||||
播放窗口 和 Mini窗口
|
||||
|
||||
#### 截图:
|
||||
1. 浏览 ⇣ ↓
|
||||

|
||||
2. 搜索 ⇣ ↓
|
||||

|
||||
3. 详情 ⇣ ↓
|
||||

|
||||
4. 播放 ⇣ ↓
|
||||

|
||||
5. 收藏 ⇣ ↓
|
||||

|
||||
6. 白色主题皮肤 ⇣ ↓
|
||||

|
||||
7. 绿色主题皮肤 ⇣ ↓
|
||||

|
||||
8. 粉色色主题皮肤 ⇣ ↓
|
||||

|
||||
| 快捷键 | 说明 | 快捷键 | 说明 |
|
||||
| :-----------: | ---------------------------- | :-------: | ----------------- |
|
||||
| `Alt + Space` | 聚焦或取消聚焦(全局快捷键) | | |
|
||||
| `→` | 快进 5 秒 | `←` | 快退 5 秒 |
|
||||
| `↑` | 音量调高 | `↓` | 音量调低 |
|
||||
| `m` | 静音 | `t` | 置顶或退出置顶 |
|
||||
| `f` | 进入或退出全屏 | `esc` | 退出全屏 |
|
||||
| `Alt + →` | 下一集 | `Alt + ←` | 上一集 |
|
||||
| `Alt + ↑` | 透明度调高 | `Alt + ↓` | 透明度调低 |
|
||||
| `home` | 跳到视频开始位置 | `end` | 跳到视频结束位置 |
|
||||
| `pgUp` | 播放倍速加快 0.25 | `pgDown` | 播放倍速减慢 0.25 |
|
||||
| `Alt + m` | 进入或退出 Mini 模式 | `space` | 播放或暂停 |
|
||||
|
||||
### 重要:
|
||||
所有资源来自网上, 该软件不参与任何制作, 上传, 储存, 下载等内容. 该软件仅供学习参考, 请于安装后24小时内删除.
|
||||
### 🎨 截图
|
||||
|
||||
| 🥼 浏览 (海报模式) | 🧥 浏览 (列表模式) |
|
||||
| :----------------------------------------------------------: | :----------------------------------------------------------: |
|
||||
|  |  |
|
||||
| 👔 搜索 | 👕 详情 |
|
||||
|  |  |
|
||||
| 👖 播放 (普通模式) | 🩳 播放 (精简模式) |
|
||||
|  |  |
|
||||
| 🧣 历史记录 | 🧤 收藏夹 |
|
||||
|  |  |
|
||||
| 👗 白色主题 | 🥻 黑色主题 |
|
||||
|  |  |
|
||||
| 👘 绿色主题 | 👚 粉色主题 |
|
||||
|  |  |
|
||||
|
||||
### 🍭 开发者
|
||||
|
||||
| [Hunlongyu](https://github.com/Hunlongyu) | [cuiocean](https://github.com/cuiocean) |
|
||||
| :----------------------------------------------------------: | :----------------------------------------------------------: |
|
||||
| <img width="120" src="https://avatars2.githubusercontent.com/u/15273630?s=460&u=48cf3299e2a842c0252233d8be42ef4c5d792138&v=4"/> | <img width="120" src="https://avatars0.githubusercontent.com/u/5760235?s=460&u=9d969dd8d83f069ce7ebd60516770c93ac07a330&v=4" /> |
|
||||
| 💻 🎨 🐛 | 💻 🐛 |
|
||||
|
||||
19
docs/doc/404.html
Normal file
19
docs/doc/404.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>ZY PLAYER</title>
|
||||
<meta name="generator" content="VuePress 1.5.2">
|
||||
|
||||
<meta name="description" content="ZY PLAYER 文档">
|
||||
<link rel="preload" href="/doc/assets/css/0.styles.7cdd3ee2.css" as="style"><link rel="preload" href="/doc/assets/js/app.441507e8.js" as="script"><link rel="preload" href="/doc/assets/js/4.023f7c55.js" as="script"><link rel="prefetch" href="/doc/assets/js/2.b7bb5685.js"><link rel="prefetch" href="/doc/assets/js/3.0958b336.js"><link rel="prefetch" href="/doc/assets/js/5.445cad31.js"><link rel="prefetch" href="/doc/assets/js/6.32cb0422.js"><link rel="prefetch" href="/doc/assets/js/7.e50f21bc.js"><link rel="prefetch" href="/doc/assets/js/8.d2479dad.js">
|
||||
<link rel="stylesheet" href="/doc/assets/css/0.styles.7cdd3ee2.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app" data-server-rendered="true"><div class="theme-container"><div class="theme-default-content"><h1>404</h1> <blockquote>Looks like we've got some broken links.</blockquote> <a href="/doc/" class="router-link-active">
|
||||
Take me home.
|
||||
</a></div></div><div class="global-ui"></div></div>
|
||||
<script src="/doc/assets/js/app.441507e8.js" defer></script><script src="/doc/assets/js/4.023f7c55.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
1
docs/doc/assets/css/0.styles.7cdd3ee2.css
Normal file
1
docs/doc/assets/css/0.styles.7cdd3ee2.css
Normal file
File diff suppressed because one or more lines are too long
1
docs/doc/assets/css/0.styles.a0babdbb.css
Normal file
1
docs/doc/assets/css/0.styles.a0babdbb.css
Normal file
File diff suppressed because one or more lines are too long
1
docs/doc/assets/img/search.83621669.svg
Normal file
1
docs/doc/assets/img/search.83621669.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="12" height="13"><g stroke-width="2" stroke="#aaa" fill="none"><path d="M11.29 11.71l-4-4"/><circle cx="5" cy="5" r="4"/></g></svg>
|
||||
|
After Width: | Height: | Size: 216 B |
1
docs/doc/assets/js/2.b7bb5685.js
Normal file
1
docs/doc/assets/js/2.b7bb5685.js
Normal file
File diff suppressed because one or more lines are too long
1
docs/doc/assets/js/3.0958b336.js
Normal file
1
docs/doc/assets/js/3.0958b336.js
Normal file
@@ -0,0 +1 @@
|
||||
(window.webpackJsonp=window.webpackJsonp||[]).push([[3],{317:function(t,e,n){},348:function(t,e,n){"use strict";var i=n(317);n.n(i).a},355:function(t,e,n){"use strict";n.r(e);var i={functional:!0,props:{type:{type:String,default:"tip"},text:String,vertical:{type:String,default:"top"}},render:function(t,e){var n=e.props,i=e.slots;return t("span",{class:["badge",n.type],style:{verticalAlign:n.vertical}},n.text||i().default)}},r=(n(348),n(42)),a=Object(r.a)(i,void 0,void 0,!1,null,"50e657c5",null);e.default=a.exports}}]);
|
||||
1
docs/doc/assets/js/3.4e0fa3d9.js
Normal file
1
docs/doc/assets/js/3.4e0fa3d9.js
Normal file
@@ -0,0 +1 @@
|
||||
(window.webpackJsonp=window.webpackJsonp||[]).push([[3],{317:function(t,e,n){},348:function(t,e,n){"use strict";var i=n(317);n.n(i).a},356:function(t,e,n){"use strict";n.r(e);var i={functional:!0,props:{type:{type:String,default:"tip"},text:String,vertical:{type:String,default:"top"}},render:function(t,e){var n=e.props,i=e.slots;return t("span",{class:["badge",n.type],style:{verticalAlign:n.vertical}},n.text||i().default)}},r=(n(348),n(42)),a=Object(r.a)(i,void 0,void 0,!1,null,"50e657c5",null);e.default=a.exports}}]);
|
||||
1
docs/doc/assets/js/4.023f7c55.js
Normal file
1
docs/doc/assets/js/4.023f7c55.js
Normal file
@@ -0,0 +1 @@
|
||||
(window.webpackJsonp=window.webpackJsonp||[]).push([[4],{350:function(t,e,s){"use strict";s.r(e);var n=["There's nothing here.","How did we get here?","That's a Four-Oh-Four.","Looks like we've got some broken links."],o={methods:{getMsg:function(){return n[Math.floor(Math.random()*n.length)]}}},i=s(42),h=Object(i.a)(o,(function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"theme-container"},[e("div",{staticClass:"theme-default-content"},[e("h1",[this._v("404")]),this._v(" "),e("blockquote",[this._v(this._s(this.getMsg()))]),this._v(" "),e("RouterLink",{attrs:{to:"/"}},[this._v("\n Take me home.\n ")])],1)])}),[],!1,null,null,null);e.default=h.exports}}]);
|
||||
1
docs/doc/assets/js/5.445cad31.js
Normal file
1
docs/doc/assets/js/5.445cad31.js
Normal file
@@ -0,0 +1 @@
|
||||
(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{351:function(t,e,n){"use strict";n.r(e);var s=n(42),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]);
|
||||
1
docs/doc/assets/js/5.d90b4340.js
Normal file
1
docs/doc/assets/js/5.d90b4340.js
Normal file
@@ -0,0 +1 @@
|
||||
(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{354:function(t,e,n){"use strict";n.r(e);var s=n(42),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]);
|
||||
1
docs/doc/assets/js/6.32cb0422.js
Normal file
1
docs/doc/assets/js/6.32cb0422.js
Normal file
@@ -0,0 +1 @@
|
||||
(window.webpackJsonp=window.webpackJsonp||[]).push([[6],{352:function(t,s,e){"use strict";e.r(s);var n=e(42),r=Object(n.a)({},(function(){var t=this.$createElement,s=this._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[s("h2",{attrs:{id:"常见问题"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#常见问题"}},[this._v("#")]),this._v(" 常见问题")]),this._v(" "),s("ol",[s("li")])])}),[],!1,null,null,null);s.default=r.exports}}]);
|
||||
1
docs/doc/assets/js/6.f276a306.js
Normal file
1
docs/doc/assets/js/6.f276a306.js
Normal file
@@ -0,0 +1 @@
|
||||
(window.webpackJsonp=window.webpackJsonp||[]).push([[6],{351:function(t,e,n){"use strict";n.r(e);var s=n(42),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]);
|
||||
1
docs/doc/assets/js/7.d3eb66c2.js
Normal file
1
docs/doc/assets/js/7.d3eb66c2.js
Normal file
@@ -0,0 +1 @@
|
||||
(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{353:function(t,s,e){"use strict";e.r(s);var n=e(42),r=Object(n.a)({},(function(){var t=this.$createElement,s=this._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[s("h2",{attrs:{id:"常见问题"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#常见问题"}},[this._v("#")]),this._v(" 常见问题")]),this._v(" "),s("ol",[s("li")])])}),[],!1,null,null,null);s.default=r.exports}}]);
|
||||
1
docs/doc/assets/js/7.e50f21bc.js
Normal file
1
docs/doc/assets/js/7.e50f21bc.js
Normal file
File diff suppressed because one or more lines are too long
1
docs/doc/assets/js/8.d2479dad.js
Normal file
1
docs/doc/assets/js/8.d2479dad.js
Normal file
File diff suppressed because one or more lines are too long
1
docs/doc/assets/js/8.e8a88c5e.js
Normal file
1
docs/doc/assets/js/8.e8a88c5e.js
Normal file
File diff suppressed because one or more lines are too long
1
docs/doc/assets/js/9.10e938e4.js
Normal file
1
docs/doc/assets/js/9.10e938e4.js
Normal file
File diff suppressed because one or more lines are too long
13
docs/doc/assets/js/app.441507e8.js
Normal file
13
docs/doc/assets/js/app.441507e8.js
Normal file
File diff suppressed because one or more lines are too long
13
docs/doc/assets/js/app.bfbedbef.js
Normal file
13
docs/doc/assets/js/app.bfbedbef.js
Normal file
File diff suppressed because one or more lines are too long
41
docs/doc/index.html
Normal file
41
docs/doc/index.html
Normal file
@@ -0,0 +1,41 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>ZY PLAYER</title>
|
||||
<meta name="generator" content="VuePress 1.5.2">
|
||||
|
||||
<meta name="description" content="ZY PLAYER 文档">
|
||||
<link rel="preload" href="/doc/assets/css/0.styles.7cdd3ee2.css" as="style"><link rel="preload" href="/doc/assets/js/app.441507e8.js" as="script"><link rel="preload" href="/doc/assets/js/2.b7bb5685.js" as="script"><link rel="preload" href="/doc/assets/js/5.445cad31.js" as="script"><link rel="prefetch" href="/doc/assets/js/3.0958b336.js"><link rel="prefetch" href="/doc/assets/js/4.023f7c55.js"><link rel="prefetch" href="/doc/assets/js/6.32cb0422.js"><link rel="prefetch" href="/doc/assets/js/7.e50f21bc.js"><link rel="prefetch" href="/doc/assets/js/8.d2479dad.js">
|
||||
<link rel="stylesheet" href="/doc/assets/css/0.styles.7cdd3ee2.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app" data-server-rendered="true"><div class="theme-container no-sidebar"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/doc/" aria-current="page" class="home-link router-link-exact-active router-link-active"><!----> <span class="site-name">ZY PLAYER</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/doc/" aria-current="page" class="nav-link router-link-exact-active router-link-active">
|
||||
主页
|
||||
</a></div><div class="nav-item"><a href="/doc/sites/" class="nav-link">
|
||||
管理源
|
||||
</a></div><div class="nav-item"><a href="/doc/shortcut/" class="nav-link">
|
||||
快捷键
|
||||
</a></div><div class="nav-item"><a href="/doc/question/" class="nav-link">
|
||||
常见问题
|
||||
</a></div> <!----></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/doc/" aria-current="page" class="nav-link router-link-exact-active router-link-active">
|
||||
主页
|
||||
</a></div><div class="nav-item"><a href="/doc/sites/" class="nav-link">
|
||||
管理源
|
||||
</a></div><div class="nav-item"><a href="/doc/shortcut/" class="nav-link">
|
||||
快捷键
|
||||
</a></div><div class="nav-item"><a href="/doc/question/" class="nav-link">
|
||||
常见问题
|
||||
</a></div> <!----></nav> <ul class="sidebar-links"><li><section class="sidebar-group depth-0"><p class="sidebar-heading open"><span>Home</span> <!----></p> <!----></section></li></ul> </aside> <main aria-labelledby="main-title" class="home"><header class="hero"><!----> <h1 id="main-title">
|
||||
ZY PLAYER
|
||||
</h1> <p class="description">
|
||||
ZY PLAYER 文档
|
||||
</p> <p class="action"><a href="/doc/sites/" class="nav-link action-button">
|
||||
开始阅读
|
||||
</a></p></header> <div class="features"><div class="feature"><h2>管理源</h2> <p>导入, 导出, 编辑源</p></div><div class="feature"><h2>快捷键</h2> <p>导入, 导出, 编辑快捷键</p></div><div class="feature"><h2>常见问题问答</h2> <p>一些常见问题问答</p></div></div> <div class="theme-default-content custom content__default"></div> <div class="footer">
|
||||
MIT Licensed | Copyright © 2020 Hunlongyu
|
||||
</div></main></div><div class="global-ui"></div></div>
|
||||
<script src="/doc/assets/js/app.441507e8.js" defer></script><script src="/doc/assets/js/2.b7bb5685.js" defer></script><script src="/doc/assets/js/5.445cad31.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
33
docs/doc/question/index.html
Normal file
33
docs/doc/question/index.html
Normal file
@@ -0,0 +1,33 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>常见问题 | ZY PLAYER</title>
|
||||
<meta name="generator" content="VuePress 1.5.2">
|
||||
|
||||
<meta name="description" content="ZY PLAYER 文档">
|
||||
<link rel="preload" href="/doc/assets/css/0.styles.7cdd3ee2.css" as="style"><link rel="preload" href="/doc/assets/js/app.441507e8.js" as="script"><link rel="preload" href="/doc/assets/js/2.b7bb5685.js" as="script"><link rel="preload" href="/doc/assets/js/6.32cb0422.js" as="script"><link rel="prefetch" href="/doc/assets/js/3.0958b336.js"><link rel="prefetch" href="/doc/assets/js/4.023f7c55.js"><link rel="prefetch" href="/doc/assets/js/5.445cad31.js"><link rel="prefetch" href="/doc/assets/js/7.e50f21bc.js"><link rel="prefetch" href="/doc/assets/js/8.d2479dad.js">
|
||||
<link rel="stylesheet" href="/doc/assets/css/0.styles.7cdd3ee2.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/doc/" class="home-link router-link-active"><!----> <span class="site-name">ZY PLAYER</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/doc/" class="nav-link">
|
||||
主页
|
||||
</a></div><div class="nav-item"><a href="/doc/sites/" class="nav-link">
|
||||
管理源
|
||||
</a></div><div class="nav-item"><a href="/doc/shortcut/" class="nav-link">
|
||||
快捷键
|
||||
</a></div><div class="nav-item"><a href="/doc/question/" aria-current="page" class="nav-link router-link-exact-active router-link-active">
|
||||
常见问题
|
||||
</a></div> <!----></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/doc/" class="nav-link">
|
||||
主页
|
||||
</a></div><div class="nav-item"><a href="/doc/sites/" class="nav-link">
|
||||
管理源
|
||||
</a></div><div class="nav-item"><a href="/doc/shortcut/" class="nav-link">
|
||||
快捷键
|
||||
</a></div><div class="nav-item"><a href="/doc/question/" aria-current="page" class="nav-link router-link-exact-active router-link-active">
|
||||
常见问题
|
||||
</a></div> <!----></nav> <ul class="sidebar-links"><li><section class="sidebar-group depth-0"><p class="sidebar-heading open"><span>常见问题</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/doc/question/#常见问题" class="sidebar-link">常见问题</a><ul class="sidebar-sub-headers"></ul></li></ul></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h2 id="常见问题"><a href="#常见问题" class="header-anchor">#</a> 常见问题</h2> <ol><li></li></ol></div> <footer class="page-edit"><!----> <!----></footer> <!----> </main></div><div class="global-ui"></div></div>
|
||||
<script src="/doc/assets/js/app.441507e8.js" defer></script><script src="/doc/assets/js/2.b7bb5685.js" defer></script><script src="/doc/assets/js/6.32cb0422.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
34
docs/doc/shortcut/index.html
Normal file
34
docs/doc/shortcut/index.html
Normal file
File diff suppressed because one or more lines are too long
34
docs/doc/sites/index.html
Normal file
34
docs/doc/sites/index.html
Normal file
File diff suppressed because one or more lines are too long
@@ -50,6 +50,7 @@
|
||||
<nav class="nav-menu d-none d-lg-block">
|
||||
<ul>
|
||||
<li class="active"><a href="#header">Home</a></li>
|
||||
<li><a href="http://zyplayer.fun/doc/">文档</a></li>
|
||||
<li><a href="#features">特色</a></li>
|
||||
<li><a href="#gallery">截图</a></li>
|
||||
<li><a href="#faq">常见问题</a></li>
|
||||
@@ -234,6 +235,7 @@
|
||||
<ul>
|
||||
<li><i class="bx bx-chevron-right"></i> <a target="_blank" href="#">Home</a></li>
|
||||
<li><i class="bx bx-chevron-right"></i> <a target="_blank" href="https://www.ghpym.com/zyplayer.html">果核剥壳</a></li>
|
||||
<li><i class="bx bx-chevron-right"></i> <a target="_blank" href="https://www.iplaysoft.com/zy-player.html">异次元软件世界</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -278,4 +280,4 @@
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
85
package.json
85
package.json
@@ -1,59 +1,74 @@
|
||||
{
|
||||
"name": "zy",
|
||||
"version": "1.0.13",
|
||||
"version": "2.6.7",
|
||||
"private": true,
|
||||
"author": {
|
||||
"name": "Hunlongyu",
|
||||
"email": "hunlongyu@gmail.com"
|
||||
},
|
||||
"description": "ZY Player 资源播放器",
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint",
|
||||
"electron:build": "vue-cli-service electron:build",
|
||||
"dev": "vue-cli-service electron:serve",
|
||||
"electron:build": "vue-cli-service electron:build",
|
||||
"electron:serve": "vue-cli-service electron:serve",
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"postuninstall": "electron-builder install-app-deps",
|
||||
"electron:generate-icons": "electron-icon-builder --input=./public/icon.png --output=build --flatten",
|
||||
"release": "vue-cli-service electron:build -p always"
|
||||
"release": "vue-cli-service electron:build -p always",
|
||||
"dist": "vue-cli-service electron:build --win --ia32"
|
||||
},
|
||||
"main": "background.js",
|
||||
"dependencies": {
|
||||
"axios": "^0.19.2",
|
||||
"core-js": "^3.6.5",
|
||||
"dexie": "^2.0.4",
|
||||
"electron-updater": "^4.3.1",
|
||||
"element-ui": "^2.13.2",
|
||||
"html2canvas": "^1.0.0-rc.5",
|
||||
"leancloud-storage": "^4.5.3",
|
||||
"macaddress": "^0.5.1",
|
||||
"modern-normalize": "^0.6.0",
|
||||
"axios": "^0.21.0",
|
||||
"cheerio": "^1.0.0-rc.3",
|
||||
"core-js": "^3.7.0",
|
||||
"cors": "^2.8.5",
|
||||
"dexie": "^3.0.3",
|
||||
"electron-localshortcut": "^3.2.1",
|
||||
"electron-proxy-agent": "^1.2.0",
|
||||
"electron-updater": "^4.3.5",
|
||||
"element-ui": "^2.14.1",
|
||||
"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",
|
||||
"pinyin-match": "^1.1.1",
|
||||
"qrcode.vue": "^1.7.0",
|
||||
"vue": "^2.6.11",
|
||||
"vue-i18n": "^8.17.7",
|
||||
"vuex": "^3.4.0",
|
||||
"xgplayer": "^2.7.1",
|
||||
"xgplayer-hls.js": "^2.2.2"
|
||||
"randomstring": "^1.1.5",
|
||||
"session": "^0.1.0",
|
||||
"sortablejs": "^1.12.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.3",
|
||||
"vuex": "^3.5.1",
|
||||
"xgplayer": "^2.13.1",
|
||||
"xgplayer-hls.js": "^2.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~4.3.0",
|
||||
"@vue/cli-plugin-eslint": "~4.3.0",
|
||||
"@vue/cli-plugin-vuex": "~4.3.0",
|
||||
"@vue/cli-service": "~4.3.0",
|
||||
"@vue/cli-plugin-babel": "~4.5.9",
|
||||
"@vue/cli-plugin-eslint": "~4.5.9",
|
||||
"@vue/cli-plugin-vuex": "~4.5.9",
|
||||
"@vue/cli-service": "~4.5.9",
|
||||
"@vue/eslint-config-standard": "^5.1.2",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-plugin-component": "^1.1.1",
|
||||
"electron": "^9.0.0",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-import": "^2.20.2",
|
||||
"electron": "^11.0.2",
|
||||
"electron-devtools-installer": "^3.1.1",
|
||||
"eslint": "^7.14.0",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"sass": "^1.26.3",
|
||||
"sass-loader": "^8.0.2",
|
||||
"vue-cli-plugin-electron-builder": "2.0.0-beta.6",
|
||||
"vue-template-compiler": "^2.6.11"
|
||||
"eslint-plugin-standard": "^4.1.0",
|
||||
"eslint-plugin-vue": "^7.1.0",
|
||||
"sass": "^1.29.0",
|
||||
"sass-loader": "^10.1.0",
|
||||
"vue-cli-plugin-electron-builder": "2.0.0-rc.5",
|
||||
"vue-template-compiler": "^2.6.12"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,17 +4,8 @@
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>icon.png">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?62aeb2505bfa26a2461d2a7a3b485096";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
|
||||
28
src/App.vue
28
src/App.vue
@@ -6,7 +6,11 @@
|
||||
<Film v-show="view === 'Film'" />
|
||||
<Play v-show="view === 'Play'" />
|
||||
<Star v-show="view === 'Star'" />
|
||||
<History v-show="view === 'History'" />
|
||||
<Setting v-show="view === 'Setting'" />
|
||||
<IPTV v-show="view === 'IPTV'" />
|
||||
<EditSites v-if="view === 'EditSites'"/>
|
||||
<Recommendation v-show="view === 'Recommendation'" />
|
||||
</div>
|
||||
<transition name="slide">
|
||||
<Detail v-if="detail.show"/>
|
||||
@@ -16,6 +20,7 @@
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'App',
|
||||
@@ -34,18 +39,27 @@ export default {
|
||||
share () {
|
||||
return this.$store.getters.getShare
|
||||
},
|
||||
theme () {
|
||||
return this.$store.getters.getTheme
|
||||
setting () {
|
||||
return this.$store.getters.getSetting
|
||||
},
|
||||
editSites () {
|
||||
return this.$store.getters.getEditSites
|
||||
},
|
||||
recommendation () {
|
||||
return this.$store.getters.recommendation
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
theme () {
|
||||
this.changeTheme()
|
||||
setting: {
|
||||
handler () {
|
||||
this.changeSetting()
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeTheme () {
|
||||
this.appTheme = `theme-${this.theme}`
|
||||
changeSetting () {
|
||||
this.appTheme = `theme-${this.setting.theme}`
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,7 +69,7 @@ export default {
|
||||
@import './assets/scss/theme.scss';
|
||||
html, body, #app{
|
||||
height: 100%;
|
||||
border-radius: 6px;
|
||||
border-radius: 0px;
|
||||
}
|
||||
#app {
|
||||
font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', SimSun, sans-serif;
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 38 KiB |
BIN
src/assets/image/wepay-hunlongyu.png
Normal file
BIN
src/assets/image/wepay-hunlongyu.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 169 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 232 KiB |
BIN
src/assets/image/wepay_cuiocean.jpg
Normal file
BIN
src/assets/image/wepay_cuiocean.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 85 KiB |
@@ -42,6 +42,22 @@
|
||||
border-left: .3em solid transparent;
|
||||
}
|
||||
}
|
||||
.vs-input{
|
||||
height: 30px;
|
||||
input{
|
||||
border: none;
|
||||
width: 200px;
|
||||
height: 30px;
|
||||
text-indent: 22px;
|
||||
background-color: #ffffff00;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
.vs-noAfter{
|
||||
&::after{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.vs-options{
|
||||
z-index: 2;
|
||||
width: 100%;
|
||||
@@ -62,105 +78,27 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// table
|
||||
.zy-table{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
font-size: 15px;
|
||||
.tHead{
|
||||
height: 50px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid;
|
||||
padding: 0 5px 0 0;
|
||||
font-weight: 600;
|
||||
span{
|
||||
display: flex;
|
||||
width: 180px;
|
||||
font-size: 16px;
|
||||
&.name{
|
||||
flex: 1;
|
||||
padding-left: 15px;
|
||||
}
|
||||
&.type{
|
||||
width: 120px;
|
||||
}
|
||||
&.from{
|
||||
width: 120px;
|
||||
}
|
||||
&.operate{
|
||||
width: 170px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.tBody{
|
||||
flex: 1;
|
||||
overflow-y: scroll;
|
||||
border-bottom: 1px solid;
|
||||
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;
|
||||
width: 180px;
|
||||
font-size: 13px;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
&.name{
|
||||
flex: 1;
|
||||
padding-left: 15px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
&.type{
|
||||
width: 120px;
|
||||
}
|
||||
&.from{
|
||||
width: 120px;
|
||||
}
|
||||
&.operate{
|
||||
width: 170px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.tFooter{
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
padding-right: 10px;
|
||||
.tFooter-span{
|
||||
padding-left: 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.btn{
|
||||
cursor: pointer;
|
||||
}
|
||||
.zy-input{
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
width: 200px;
|
||||
height: 30px;
|
||||
cursor: pointer;
|
||||
input{
|
||||
vertical-align: bottom;
|
||||
position: relative;
|
||||
border: none;
|
||||
width: 20px;
|
||||
height: 15px;
|
||||
background-color: #ffffff00;
|
||||
text-indent: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
// scroll
|
||||
.zy-scroll{
|
||||
&::-webkit-scrollbar{
|
||||
width: 5px;
|
||||
width: 10px;
|
||||
height: 1px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
@@ -173,6 +111,259 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Page of list using el-table
|
||||
.listpage{
|
||||
position: absolute;
|
||||
left: 80px;
|
||||
right: 20px;
|
||||
top: 40px;
|
||||
bottom: 20px;
|
||||
width: calc(100% - 100px);
|
||||
height: calc(100% - 60px);
|
||||
border-radius: 5px;
|
||||
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%;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.el-button{
|
||||
font-size: 1rem;
|
||||
border: none;
|
||||
&:hover{
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.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: hidden;
|
||||
font-size: 1rem;
|
||||
}
|
||||
.el-table__body-wrapper{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
&::-webkit-scrollbar{
|
||||
width: 5px;
|
||||
height: 1px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
border-radius: 10px;
|
||||
position: absolute;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
border-radius: 10px;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
.disableExpand div.el-table__expand-icon{
|
||||
display: none;
|
||||
}
|
||||
.el-input{
|
||||
width: 200px;
|
||||
}
|
||||
.el-table__body td,.el-table__body th{
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
.el-table--enable-row-hover .el-table__body tr:hover>td{
|
||||
transform: scale(1.02);
|
||||
}
|
||||
.el-table .highlight{
|
||||
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);
|
||||
}
|
||||
.site{
|
||||
position: absolute;
|
||||
top: 0%;
|
||||
left: 0%;
|
||||
width: 100%;
|
||||
background-color: #111111aa;
|
||||
color:#2f90b9;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
font-size: 14px;
|
||||
font-weight: bolder;
|
||||
text-align: center;
|
||||
}
|
||||
.progress{
|
||||
position: absolute;
|
||||
bottom: 10%;
|
||||
left: 0%;
|
||||
width: 40%;
|
||||
background-color: #111111aa;
|
||||
color: #f8df70;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
font-size: 14px;
|
||||
font-weight: bolder;
|
||||
text-align: left;
|
||||
}
|
||||
.update{
|
||||
position: absolute;
|
||||
top: 5%;
|
||||
left: -40%;
|
||||
width: 100%;
|
||||
background-color: #68b88e;
|
||||
color: #cdcdcd;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
.operate{
|
||||
display: none;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
background-color: #111111aa;
|
||||
width: 100%;
|
||||
font-size: 13px;
|
||||
.operate-wrap{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.o-play, .o-star, .o-share{
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
width: 80px;
|
||||
height: 36px;
|
||||
text-align: center;
|
||||
line-height: 36px;
|
||||
color: #cdcdcd;
|
||||
&:hover{
|
||||
background-color: #111;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.name{
|
||||
font-size: 16px;
|
||||
padding: 10px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.info{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 12px;
|
||||
padding: 10px;
|
||||
}
|
||||
&:hover{
|
||||
.operate{
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// loading
|
||||
.zy-loading{
|
||||
width: 100%;
|
||||
@@ -217,4 +408,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
:root{
|
||||
// general
|
||||
--highlight-color:#1677b3;
|
||||
// light
|
||||
--l-c-0: #823aa0;
|
||||
--l-c-1: #823aa011;
|
||||
@@ -12,10 +14,10 @@
|
||||
--l-fc-3: #823aa0;
|
||||
--l-bgc-1: #ffffff;
|
||||
--l-bgc-2: #f2f6f9;
|
||||
--l-bsc: 0 3px 1px -2px #8e8da233, 0 2px 2px 0 #8e8da224, 0 1px 5px 0 #8e8da21f;
|
||||
--l-bsc: 0 1px 3px #8e8da233, 0 1px 2px #8e8da244;
|
||||
--l-bsc-hover: 0 14px 28px #8e8da255, 0 10px 10px #8e8da244;
|
||||
--l-bsc-2: 0 -4px 23px 0 #8e8da233;
|
||||
--l-bsc-hover: 0 14px 26px -12px #8e8da26b, 0 4px 23px 0 #8e8da21f, 0 8px 10px -5px #8e8da233;
|
||||
--l-bsc-scroll: inset 0 0 5px #823aa005;
|
||||
--l-bsc-scroll: inset 0 0 5px #823aa000;
|
||||
|
||||
// dark
|
||||
--d-c-0: #38dd77;
|
||||
@@ -30,9 +32,9 @@
|
||||
--d-fc-3: #38dd77;
|
||||
--d-bgc-1: #222222;
|
||||
--d-bgc-2: #2f2f2f;
|
||||
--d-bsc: 0 3px 1px -2px #38dd7733, 0 2px 2px 0 #38dd7722, 0 1px 5px 0 #38dd7711;
|
||||
--d-bsc: 0 1px 3px #38dd7733, 0 1px 2px #38dd7744;
|
||||
--d-bsc-hover: 0 14px 28px #38dd7755, 0 10px 10px #38dd7744;
|
||||
--d-bsc-2: 0 -4px 23px 0 #38dd7733;
|
||||
--d-bsc-hover: 0 14px 26px -12px #38dd7733, 0 4px 23px 0 #38dd7722, 0 8px 10px -5px #38dd7711;
|
||||
--d-bsc-scroll: inset 0 0 5px #38dd7705;
|
||||
|
||||
// green
|
||||
@@ -48,9 +50,9 @@
|
||||
--g-fc-3: #C1D95C;
|
||||
--g-bgc-1: #4baea0;
|
||||
--g-bgc-2: #74b4ac;
|
||||
--g-bsc: 0 3px 1px -2px #e1ebe033, 0 2px 2px 0 #e1ebe022, 0 1px 5px 0 #e1ebe011;
|
||||
--g-bsc: 0 1px 3px #e1ebe033, 0 1px 2px #e1ebe044;
|
||||
--g-bsc-hover: 0 14px 28px #e1ebe055, 0 10px 10px #e1ebe044;
|
||||
--g-bsc-2: 0 -4px 23px 0 #e1ebe033;
|
||||
--g-bsc-hover: 0 14px 26px -12px #e1ebe033, 0 4px 23px 0 #e1ebe022, 0 8px 10px -5px #e1ebe011;
|
||||
--g-bsc-scroll: inset 0 0 5px #e1ebe005;
|
||||
|
||||
// pink
|
||||
@@ -63,12 +65,12 @@
|
||||
--p-c-9: #f4f7f799;
|
||||
--p-fc-1: #ffffff;
|
||||
--p-fc-2: #FFFFF3;
|
||||
--p-fc-3: #f15c5c;
|
||||
--p-fc-3: #177ea7;
|
||||
--p-bgc-1: #ff8499;
|
||||
--p-bgc-2: #fea1b2;
|
||||
--p-bsc: 0 3px 1px -2px #ef528533, 0 2px 2px 0 #ef528522, 0 1px 5px 0 #ef528511;
|
||||
--p-bsc: 0 1px 3px #ef528533, 0 1px 2px #ef528544;
|
||||
--p-bsc-hover: 0 14px 28px #ef528555, 0 10px 10px #ef528544;
|
||||
--p-bsc-2: 0 -4px 23px 0 #ef528533;
|
||||
--p-bsc-hover: 0 14px 26px -12px #ef528533, 0 4px 23px 0 #ef528522, 0 8px 10px -5px #ef528511;
|
||||
--p-bsc-scroll: inset 0 0 5px #ef528505;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,37 +1,10 @@
|
||||
.theme-dark{
|
||||
background-color: var(--d-bgc-1);
|
||||
.el-pagination{
|
||||
background-color: var(--d-bgc-1);
|
||||
color: var(--d-fc-1);
|
||||
.el-pagination__total, .el-pagination__jump, .el-input__inner{
|
||||
color: var(--d-fc-1);
|
||||
background-color: var(--d-bgc-1);
|
||||
}
|
||||
.el-input__inner{
|
||||
border-color: var(--d-c-3);
|
||||
}
|
||||
.el-pager{
|
||||
.number{
|
||||
background-color: var(--d-bgc-1);
|
||||
}
|
||||
.number:hover{
|
||||
color: var(--d-c-8);
|
||||
}
|
||||
.active{
|
||||
color: var(--d-c-9);
|
||||
}
|
||||
}
|
||||
.more, .btn-next, .btn-prev{
|
||||
background-color: var(--d-bgc-1);
|
||||
&:hover{
|
||||
color: var(--d-c-8);
|
||||
}
|
||||
}
|
||||
}
|
||||
.zy-select{
|
||||
color: var(--d-fc-1);
|
||||
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);
|
||||
}
|
||||
@@ -39,6 +12,7 @@
|
||||
background-color: var(--d-bgc-1);
|
||||
box-shadow: var(--d-bsc);
|
||||
ul{
|
||||
overflow-y: scroll;
|
||||
li{
|
||||
&:hover{
|
||||
background-color: var(--d-c-1);
|
||||
@@ -49,49 +23,33 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.zy-table{
|
||||
color: var(--d-fc-2);
|
||||
.tHead{
|
||||
.vs-input{
|
||||
color: var(--d-fc-1);
|
||||
background-color: var(--d-bgc-1);
|
||||
border-bottom-color: var(--d-c-3);
|
||||
}
|
||||
.tBody{
|
||||
border-bottom-color: var(--d-c-3);
|
||||
ul{
|
||||
li{
|
||||
border-bottom-color: var(--d-c-2);
|
||||
&:hover{
|
||||
animation: d-tableHoverAni 0.2s ease both;
|
||||
@keyframes d-tableHoverAni {
|
||||
to{
|
||||
box-shadow: var(--d-bsc-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
span{
|
||||
&.btn:hover{
|
||||
color: var(--d-fc-3)
|
||||
}
|
||||
}
|
||||
input{
|
||||
color: var(--d-fc-1);
|
||||
&::-webkit-input-placeholder{
|
||||
color: var(--d-fc-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
.tFooter{
|
||||
.tFooter-span{
|
||||
color: var(--d-fc-1);
|
||||
}
|
||||
}
|
||||
.zy-input{
|
||||
color: var(--d-fc-1);
|
||||
background-color: var(--d-bgc-1);
|
||||
input{
|
||||
color: var(--d-fc-1);
|
||||
}
|
||||
}
|
||||
.zy-scroll{
|
||||
&:hover{
|
||||
&::-webkit-scrollbar-thumb {
|
||||
box-shadow: var(--d-bsc-scroll);
|
||||
background: var(--d-c-3);
|
||||
background: var(--d-c-5);
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
box-shadow: var(--d-bsc-scroll);
|
||||
background: var(--bgc);
|
||||
background: var(--d-bgc-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,6 +70,7 @@
|
||||
background-color: var(--d-c-2);
|
||||
}
|
||||
&.active{
|
||||
background-color: var(--d-bgc-2);
|
||||
svg{
|
||||
stroke: var(--d-c-0);
|
||||
stroke-width: 2;
|
||||
@@ -123,11 +82,17 @@
|
||||
.frame{
|
||||
span{
|
||||
&.min{
|
||||
background-color: #32dc36;
|
||||
}
|
||||
&.max{
|
||||
background-color: #ffbe2a;
|
||||
}
|
||||
&.close{
|
||||
background-color: #ff5f56;
|
||||
}
|
||||
&.top{
|
||||
background-color: #f3bab7;
|
||||
}
|
||||
}
|
||||
}
|
||||
.detail{
|
||||
@@ -146,10 +111,17 @@
|
||||
}
|
||||
}
|
||||
.detail-body{
|
||||
.info, .desc, .m3u8_urls, .mp4_urls{
|
||||
.info, .desc, .m3u8, .operate{
|
||||
border-color: var(--d-c-2);
|
||||
}
|
||||
.m3u8_urls, .mp4_urls{
|
||||
.operate{
|
||||
span{
|
||||
&:hover{
|
||||
color: var(--d-fc-2);
|
||||
}
|
||||
}
|
||||
}
|
||||
.m3u8{
|
||||
.box{
|
||||
span{
|
||||
border-color: var(--d-c-5);
|
||||
@@ -164,44 +136,23 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.film{
|
||||
.top{
|
||||
.search{
|
||||
background-color: var(--d-bgc-1);
|
||||
box-shadow: var(--d-bsc);
|
||||
&:hover{
|
||||
box-shadow: var(--d-bsc-hover);
|
||||
}
|
||||
svg{
|
||||
stroke: var(--d-c-0);
|
||||
stroke-width: 1;
|
||||
fill: none;
|
||||
}
|
||||
.search-box{
|
||||
background-color: var(--d-bgc-1);
|
||||
}
|
||||
&.active{
|
||||
box-shadow: var(--d-bsc-hover);
|
||||
svg{
|
||||
stroke-width: 1.5;
|
||||
fill: var(--d-c-2);
|
||||
}
|
||||
}
|
||||
input{
|
||||
color: var(--d-fc-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
.middle{
|
||||
background-color: var(--d-bgc-1);
|
||||
box-shadow: var(--d-bsc);
|
||||
}
|
||||
}
|
||||
.play{
|
||||
background-color: var(--d-bgc-1);
|
||||
box-shadow: var(--d-bsc);
|
||||
.el-input{
|
||||
input{
|
||||
background-color: var(--d-bgc-1);
|
||||
border: 1px solid var(--d-bgc-1);
|
||||
color: var(--d-fc-2);
|
||||
}
|
||||
}
|
||||
.title{
|
||||
color: var(--d-fc-1);
|
||||
.right {
|
||||
svg {
|
||||
fill: var(--d-fc-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
.box{
|
||||
.more{
|
||||
@@ -225,6 +176,10 @@
|
||||
fill: var(--d-c-3);
|
||||
}
|
||||
}
|
||||
&.last-tip {
|
||||
color: var(--d-fc-1);
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -254,6 +209,17 @@
|
||||
background-color: var(--d-c-2);
|
||||
color: var(--d-fc-3);
|
||||
}
|
||||
&:hover{
|
||||
background-color: var(--d-c-3);
|
||||
}
|
||||
}
|
||||
}
|
||||
.list-channels{
|
||||
.btn{
|
||||
color: var(--d-fc-1);
|
||||
&:hover{
|
||||
text-decoration:underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
.list-history{
|
||||
@@ -283,14 +249,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.play-mask{
|
||||
background-color: var(--d-bgc-1);
|
||||
color: var(--d-fc-1);
|
||||
}
|
||||
}
|
||||
.star{
|
||||
background-color: var(--d-bgc-1);
|
||||
box-shadow: var(--d-bsc);
|
||||
}
|
||||
.setting{
|
||||
background-color: var(--d-bgc-1);
|
||||
@@ -303,12 +261,18 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.view, .search, .shortcut, .site{
|
||||
.title{
|
||||
color: var(--d-fc-1);
|
||||
}
|
||||
}
|
||||
.theme{
|
||||
.title{
|
||||
color: var(--d-fc-1);
|
||||
}
|
||||
.theme-item{
|
||||
box-shadow: var(--d-bsc);
|
||||
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
|
||||
&:hover{
|
||||
box-shadow: var(--d-bsc-hover);
|
||||
.theme-name{
|
||||
@@ -326,6 +290,10 @@
|
||||
}
|
||||
.qrcode-item{
|
||||
box-shadow: var(--d-bsc);
|
||||
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
|
||||
&:hover{
|
||||
box-shadow: var(--d-bsc-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -343,4 +311,118 @@
|
||||
background-color: var(--d-bgc-1);
|
||||
}
|
||||
}
|
||||
.history{
|
||||
background-color: var(--d-bgc-1);
|
||||
box-shadow: var(--d-bsc);
|
||||
}
|
||||
|
||||
// Page of list using table and picture
|
||||
.listpage{
|
||||
color: var(--d-fc-2);
|
||||
.listpage-header{
|
||||
border-bottom-color: var(--d-c-3);
|
||||
.btn{
|
||||
&:hover{
|
||||
color: var(--d-fc-3)
|
||||
}
|
||||
}
|
||||
.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);
|
||||
}
|
||||
}
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
.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-table__body-wrapper{
|
||||
&: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-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);
|
||||
}
|
||||
.el-button{
|
||||
color: var(--d-fc-1);
|
||||
&:hover{
|
||||
color: var(--d-fc-3)
|
||||
}
|
||||
}
|
||||
}
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +1,10 @@
|
||||
.theme-green{
|
||||
background-color: var(--g-bgc-1);
|
||||
.el-pagination{
|
||||
background-color: var(--g-bgc-1);
|
||||
color: var(--g-fc-1);
|
||||
.el-pagination__total, .el-pagination__jump, .el-input__inner{
|
||||
color: var(--g-fc-1);
|
||||
background-color: var(--g-bgc-1);
|
||||
}
|
||||
.el-input__inner{
|
||||
border-color: var(--g-c-3);
|
||||
}
|
||||
.el-pager{
|
||||
.number{
|
||||
background-color: var(--g-bgc-1);
|
||||
}
|
||||
.number:hover{
|
||||
color: var(--g-c-8);
|
||||
}
|
||||
.active{
|
||||
color: var(--g-c-9);
|
||||
}
|
||||
}
|
||||
.more, .btn-next, .btn-prev{
|
||||
background-color: var(--g-bgc-1);
|
||||
&:hover{
|
||||
color: var(--g-c-8);
|
||||
}
|
||||
}
|
||||
}
|
||||
.zy-select{
|
||||
color: var(--g-fc-1);
|
||||
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);
|
||||
}
|
||||
@@ -39,6 +12,7 @@
|
||||
background-color: var(--g-bgc-1);
|
||||
box-shadow: var(--g-bsc);
|
||||
ul{
|
||||
overflow-y: scroll;
|
||||
li{
|
||||
&:hover{
|
||||
background-color: var(--g-c-1);
|
||||
@@ -49,49 +23,33 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.zy-table{
|
||||
color: var(--g-fc-2);
|
||||
.tHead{
|
||||
.vs-input{
|
||||
color: var(--g-fc-1);
|
||||
background-color: var(--g-bgc-1);
|
||||
border-bottom-color: var(--g-c-3);
|
||||
}
|
||||
.tBody{
|
||||
border-bottom-color: var(--g-c-3);
|
||||
ul{
|
||||
li{
|
||||
border-bottom-color: var(--g-c-2);
|
||||
&:hover{
|
||||
animation: d-tableHoverAni 0.2s ease both;
|
||||
@keyframes d-tableHoverAni {
|
||||
to{
|
||||
box-shadow: var(--g-bsc-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
span{
|
||||
&.btn:hover{
|
||||
color: var(--g-fc-3)
|
||||
}
|
||||
}
|
||||
input{
|
||||
color: var(--g-fc-1);
|
||||
&::-webkit-input-placeholder{
|
||||
color: var(--g-fc-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
.tFooter{
|
||||
.tFooter-span{
|
||||
color: var(--g-fc-1);
|
||||
}
|
||||
}
|
||||
.zy-input{
|
||||
color: var(--g-fc-1);
|
||||
background-color: var(--g-bgc-1);
|
||||
input{
|
||||
color: var(--g-fc-1);
|
||||
}
|
||||
}
|
||||
.zy-scroll{
|
||||
&:hover{
|
||||
&::-webkit-scrollbar-thumb {
|
||||
box-shadow: var(--g-bsc-scroll);
|
||||
background: var(--g-c-3);
|
||||
background: var(--g-c-5);
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
box-shadow: var(--g-bsc-scroll);
|
||||
background: var(--bgc);
|
||||
background: var(--g-bgc-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,6 +70,7 @@
|
||||
background-color: var(--g-c-2);
|
||||
}
|
||||
&.active{
|
||||
background-color: var(--g-bgc-2);
|
||||
svg{
|
||||
stroke: var(--g-c-0);
|
||||
stroke-width: 2;
|
||||
@@ -123,15 +82,21 @@
|
||||
.frame{
|
||||
span{
|
||||
&.min{
|
||||
background-color: #32dc36;
|
||||
}
|
||||
&.max{
|
||||
background-color: #ffbe2a;
|
||||
}
|
||||
&.close{
|
||||
background-color: #ff5f56;
|
||||
}
|
||||
&.top{
|
||||
background-color: #f3bab7;
|
||||
}
|
||||
}
|
||||
}
|
||||
.detail{
|
||||
color: var(--g-fc-1);
|
||||
color: var(--g-fc-1) !important;
|
||||
background-color:var(--g-bgc-1);
|
||||
box-shadow: var(--g-bsc-2);
|
||||
.detail-content{
|
||||
@@ -146,10 +111,17 @@
|
||||
}
|
||||
}
|
||||
.detail-body{
|
||||
.info, .desc, .m3u8_urls, .mp4_urls{
|
||||
.info, .desc, .m3u8, .operate{
|
||||
border-color: var(--g-c-2);
|
||||
}
|
||||
.m3u8_urls, .mp4_urls{
|
||||
.operate{
|
||||
span{
|
||||
&:hover{
|
||||
color: var(--g-fc-2);
|
||||
}
|
||||
}
|
||||
}
|
||||
.m3u8{
|
||||
.box{
|
||||
span{
|
||||
border-color: var(--g-c-5);
|
||||
@@ -164,44 +136,23 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.film{
|
||||
.top{
|
||||
.search{
|
||||
background-color: var(--g-bgc-1);
|
||||
box-shadow: var(--g-bsc);
|
||||
&:hover{
|
||||
box-shadow: var(--g-bsc-hover);
|
||||
}
|
||||
svg{
|
||||
stroke: var(--g-c-0);
|
||||
stroke-width: 1;
|
||||
fill: none;
|
||||
}
|
||||
.search-box{
|
||||
background-color: var(--g-bgc-1);
|
||||
}
|
||||
&.active{
|
||||
box-shadow: var(--g-bsc-hover);
|
||||
svg{
|
||||
stroke-width: 1.5;
|
||||
fill: var(--g-c-2);
|
||||
}
|
||||
}
|
||||
input{
|
||||
color: var(--g-fc-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
.middle{
|
||||
background-color: var(--g-bgc-1);
|
||||
box-shadow: var(--g-bsc);
|
||||
}
|
||||
}
|
||||
.play{
|
||||
background-color: var(--g-bgc-1);
|
||||
box-shadow: var(--g-bsc);
|
||||
.el-input{
|
||||
input{
|
||||
background-color: var(--g-bgc-1);
|
||||
border: 1px solid var(--g-bgc-1);
|
||||
color: var(--g-fc-2);
|
||||
}
|
||||
}
|
||||
.title{
|
||||
color: var(--g-fc-1);
|
||||
.right {
|
||||
svg {
|
||||
fill: var(--g-fc-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
.box{
|
||||
.more{
|
||||
@@ -225,6 +176,10 @@
|
||||
fill: var(--g-c-3);
|
||||
}
|
||||
}
|
||||
&.last-tip {
|
||||
color: var(--g-fc-1);
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -254,6 +209,17 @@
|
||||
background-color: var(--g-c-2);
|
||||
color: var(--g-fc-3);
|
||||
}
|
||||
&:hover{
|
||||
background-color: var(--g-c-3);
|
||||
}
|
||||
}
|
||||
}
|
||||
.list-channels{
|
||||
.btn{
|
||||
color: var(--g-fc-1);
|
||||
&:hover{
|
||||
text-decoration:underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
.list-history{
|
||||
@@ -283,14 +249,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.play-mask{
|
||||
background-color: var(--g-bgc-1);
|
||||
color: var(--g-fc-1);
|
||||
}
|
||||
}
|
||||
.star{
|
||||
background-color: var(--g-bgc-1);
|
||||
box-shadow: var(--g-bsc);
|
||||
}
|
||||
.setting{
|
||||
background-color: var(--g-bgc-1);
|
||||
@@ -303,12 +261,18 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.view, .search, .shortcut, .site{
|
||||
.title{
|
||||
color: var(--g-fc-1);
|
||||
}
|
||||
}
|
||||
.theme{
|
||||
.title{
|
||||
color: var(--g-fc-1);
|
||||
}
|
||||
.theme-item{
|
||||
box-shadow: var(--g-bsc);
|
||||
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
|
||||
&:hover{
|
||||
box-shadow: var(--g-bsc-hover);
|
||||
.theme-name{
|
||||
@@ -326,6 +290,10 @@
|
||||
}
|
||||
.qrcode-item{
|
||||
box-shadow: var(--g-bsc);
|
||||
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
|
||||
&:hover{
|
||||
box-shadow: var(--g-bsc-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -343,4 +311,118 @@
|
||||
background-color: var(--g-bgc-1);
|
||||
}
|
||||
}
|
||||
.history{
|
||||
background-color: var(--g-bgc-1);
|
||||
box-shadow: var(--g-bsc);
|
||||
}
|
||||
|
||||
// Page of list using table and picture
|
||||
.listpage{
|
||||
color: var(--g-fc-2);
|
||||
.listpage-header{
|
||||
border-bottom-color: var(--g-c-3);
|
||||
.btn{
|
||||
&:hover{
|
||||
color: var(--g-fc-3)
|
||||
}
|
||||
}
|
||||
.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);
|
||||
}
|
||||
}
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
.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-table__body-wrapper{
|
||||
&: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-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);
|
||||
}
|
||||
.el-button{
|
||||
color: var(--g-fc-1);
|
||||
&:hover{
|
||||
color: var(--g-fc-3)
|
||||
}
|
||||
}
|
||||
}
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,10 @@
|
||||
.theme-light{
|
||||
background-color: var(--l-bgc-1);
|
||||
.el-pagination{
|
||||
color: var(--l-fc-1);
|
||||
.el-pagination__total, .el-pagination__jump, .el-input__inner{
|
||||
color: var(--l-fc-1);
|
||||
}
|
||||
.el-pager{
|
||||
.number:hover{
|
||||
color: var(--l-c-8);
|
||||
}
|
||||
.active{
|
||||
color: var(--l-c-9);
|
||||
}
|
||||
}
|
||||
.more, .btn-next, .btn-prev{
|
||||
&:hover{
|
||||
color: var(--l-c-8);
|
||||
}
|
||||
}
|
||||
}
|
||||
.zy-select{
|
||||
color: var(--l-fc-1);
|
||||
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);
|
||||
}
|
||||
@@ -30,6 +12,7 @@
|
||||
background-color: var(--l-bgc-1);
|
||||
box-shadow: var(--l-bsc);
|
||||
ul{
|
||||
overflow-y: scroll;
|
||||
li{
|
||||
&:hover{
|
||||
background-color: var(--l-c-1);
|
||||
@@ -40,49 +23,33 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.zy-table{
|
||||
color: var(--l-fc-2);
|
||||
.tHead{
|
||||
.vs-input{
|
||||
color: var(--l-fc-1);
|
||||
background-color: var(--l-bgc-1);
|
||||
border-bottom-color: var(--l-c-3);
|
||||
}
|
||||
.tBody{
|
||||
border-bottom-color: var(--l-c-3);
|
||||
ul{
|
||||
li{
|
||||
border-bottom-color: var(--l-c-2);
|
||||
&:hover{
|
||||
animation: l-tableHoverAni 0.2s ease both;
|
||||
@keyframes l-tableHoverAni {
|
||||
to{
|
||||
box-shadow: var(--l-bsc-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
span{
|
||||
&.btn:hover{
|
||||
color: var(--l-fc-3)
|
||||
}
|
||||
}
|
||||
input{
|
||||
color: var(--l-fc-1);
|
||||
&::-webkit-input-placeholder{
|
||||
color: var(--l-fc-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
.tFooter{
|
||||
.tFooter-span{
|
||||
color: var(--l-fc-1);
|
||||
}
|
||||
}
|
||||
.zy-input{
|
||||
color: var(--l-fc-1);
|
||||
background-color: var(--l-bgc-1);
|
||||
input{
|
||||
color: var(--l-fc-1);
|
||||
}
|
||||
}
|
||||
.zy-scroll{
|
||||
&:hover{
|
||||
&::-webkit-scrollbar-thumb {
|
||||
box-shadow: var(--l-bsc-scroll);
|
||||
background: var(--l-c-3);
|
||||
background: var(--l-c-5);
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
box-shadow: var(--l-bsc-scroll);
|
||||
background: var(--bgc);
|
||||
background: var(--l-bgc-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,6 +70,7 @@
|
||||
background-color: var(--l-c-2);
|
||||
}
|
||||
&.active{
|
||||
background-color: var(--l-bgc-2);
|
||||
svg{
|
||||
stroke: var(--l-c-0);
|
||||
stroke-width: 2;
|
||||
@@ -114,15 +82,21 @@
|
||||
.frame{
|
||||
span{
|
||||
&.min{
|
||||
background-color: #32dc36;
|
||||
}
|
||||
&.max{
|
||||
background-color: #ffbe2a;
|
||||
}
|
||||
&.close{
|
||||
background-color: #ff5f56;
|
||||
}
|
||||
&.top{
|
||||
background-color: #f3bab7;
|
||||
}
|
||||
}
|
||||
}
|
||||
.detail{
|
||||
color: var(--l-fc-1);
|
||||
color: var(--l-fc-1) !important;
|
||||
background-color:var(--l-bgc-1);
|
||||
box-shadow: var(--l-bsc-2);
|
||||
.detail-content{
|
||||
@@ -137,10 +111,17 @@
|
||||
}
|
||||
}
|
||||
.detail-body{
|
||||
.info, .desc, .m3u8_urls, .mp4_urls{
|
||||
.info, .desc, .m3u8, .operate{
|
||||
border-color: var(--l-c-2);
|
||||
}
|
||||
.m3u8_urls, .mp4_urls{
|
||||
.operate{
|
||||
span{
|
||||
&:hover{
|
||||
color: var(--l-fc-2);
|
||||
}
|
||||
}
|
||||
}
|
||||
.m3u8{
|
||||
.box{
|
||||
span{
|
||||
border-color: var(--l-c-5);
|
||||
@@ -155,44 +136,23 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.film{
|
||||
.top{
|
||||
.search{
|
||||
background-color: var(--l-bgc-1);
|
||||
box-shadow: var(--l-bsc);
|
||||
&:hover{
|
||||
box-shadow: var(--l-bsc-hover);
|
||||
}
|
||||
svg{
|
||||
stroke: #823aa099;
|
||||
stroke-width: 1;
|
||||
fill: none;
|
||||
}
|
||||
.search-box{
|
||||
background-color: none;
|
||||
}
|
||||
&.active{
|
||||
box-shadow: var(--l-bsc-hover);
|
||||
svg{
|
||||
stroke-width: 1.5;
|
||||
fill: var(--l-c-2);
|
||||
}
|
||||
}
|
||||
input{
|
||||
color: var(--l-fc-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
.middle{
|
||||
background-color: var(--l-bgc-1);
|
||||
box-shadow: var(--l-bsc);
|
||||
}
|
||||
}
|
||||
.play{
|
||||
background-color: var(--l-bgc-1);
|
||||
box-shadow: var(--l-bsc);
|
||||
.el-input{
|
||||
input{
|
||||
background-color: var(--l-bgc-1);
|
||||
border: 1px solid var(--l-bgc-1);
|
||||
color: var(--l-fc-2);
|
||||
}
|
||||
}
|
||||
.title{
|
||||
color: var(--d-fc-1);
|
||||
color: var(--l-fc-1);
|
||||
.right {
|
||||
svg {
|
||||
fill: var(--l-fc-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
.box{
|
||||
.more{
|
||||
@@ -216,11 +176,12 @@
|
||||
fill: var(--l-c-3);
|
||||
}
|
||||
}
|
||||
&.last-tip {
|
||||
color: var(--l-fc-1);
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.mask{
|
||||
background-color: var(--l-bgc-1);
|
||||
}
|
||||
}
|
||||
.list{
|
||||
border: 1px solid var(--l-c-3);
|
||||
@@ -248,6 +209,17 @@
|
||||
background-color: var(--l-c-2);
|
||||
color: var(--l-fc-3);
|
||||
}
|
||||
&:hover{
|
||||
background-color: var(--l-c-3);
|
||||
}
|
||||
}
|
||||
}
|
||||
.list-channels{
|
||||
.btn{
|
||||
color: var(--l-fc-1);
|
||||
&:hover{
|
||||
text-decoration:underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
.list-history{
|
||||
@@ -277,14 +249,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.play-mask{
|
||||
background-color: var(--l-bgc-1);
|
||||
color: var(--l-fc-1);
|
||||
}
|
||||
}
|
||||
.star{
|
||||
background-color: var(--l-bgc-1);
|
||||
box-shadow: var(--l-bsc);
|
||||
}
|
||||
.setting{
|
||||
background-color: var(--l-bgc-1);
|
||||
@@ -297,12 +261,18 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.view, .search, .shortcut, .site{
|
||||
.title{
|
||||
color: var(--l-fc-1);
|
||||
}
|
||||
}
|
||||
.theme{
|
||||
.title{
|
||||
color: var(--l-fc-1);
|
||||
}
|
||||
.theme-item{
|
||||
box-shadow: var(--l-bsc);
|
||||
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
|
||||
&:hover{
|
||||
box-shadow: var(--l-bsc-hover);
|
||||
.theme-name{
|
||||
@@ -320,6 +290,10 @@
|
||||
}
|
||||
.qrcode-item{
|
||||
box-shadow: var(--l-bsc);
|
||||
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
|
||||
&:hover{
|
||||
box-shadow: var(--l-bsc-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -337,4 +311,118 @@
|
||||
background-color: var(--l-bgc-1);
|
||||
}
|
||||
}
|
||||
.history{
|
||||
background-color: var(--l-bgc-1);
|
||||
box-shadow: var(--l-bsc);
|
||||
}
|
||||
|
||||
// Page of list using table and picture
|
||||
.listpage{
|
||||
color: var(--l-fc-2);
|
||||
.listpage-header{
|
||||
border-bottom-color: var(--l-c-3);
|
||||
.btn{
|
||||
&:hover{
|
||||
color: var(--l-fc-3)
|
||||
}
|
||||
}
|
||||
.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);
|
||||
}
|
||||
}
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
.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-table__body-wrapper{
|
||||
&: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-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);
|
||||
}
|
||||
.el-button{
|
||||
color: var(--l-fc-1);
|
||||
&:hover{
|
||||
color: var(--l-fc-3)
|
||||
}
|
||||
}
|
||||
}
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +1,10 @@
|
||||
.theme-pink{
|
||||
background-color: var(--p-bgc-1);
|
||||
.el-pagination{
|
||||
background-color: var(--p-bgc-1);
|
||||
color: var(--p-fc-1);
|
||||
.el-pagination__total, .el-pagination__jump, .el-input__inner{
|
||||
color: var(--p-fc-1);
|
||||
background-color: var(--p-bgc-1);
|
||||
}
|
||||
.el-input__inner{
|
||||
border-color: var(--p-c-3);
|
||||
}
|
||||
.el-pager{
|
||||
.number{
|
||||
background-color: var(--p-bgc-1);
|
||||
}
|
||||
.number:hover{
|
||||
color: var(--p-c-8);
|
||||
}
|
||||
.active{
|
||||
color: var(--p-c-9);
|
||||
}
|
||||
}
|
||||
.more, .btn-next, .btn-prev{
|
||||
background-color: var(--p-bgc-1);
|
||||
&:hover{
|
||||
color: var(--p-c-8);
|
||||
}
|
||||
}
|
||||
}
|
||||
.zy-select{
|
||||
color: var(--p-fc-1);
|
||||
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);
|
||||
}
|
||||
@@ -39,6 +12,7 @@
|
||||
background-color: var(--p-bgc-1);
|
||||
box-shadow: var(--p-bsc);
|
||||
ul{
|
||||
overflow-y: scroll;
|
||||
li{
|
||||
&:hover{
|
||||
background-color: var(--p-c-1);
|
||||
@@ -49,49 +23,33 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.zy-table{
|
||||
color: var(--p-fc-2);
|
||||
.tHead{
|
||||
.vs-input{
|
||||
color: var(--p-fc-1);
|
||||
background-color: var(--p-bgc-1);
|
||||
border-bottom-color: var(--p-c-3);
|
||||
}
|
||||
.tBody{
|
||||
border-bottom-color: var(--p-c-3);
|
||||
ul{
|
||||
li{
|
||||
border-bottom-color: var(--p-c-2);
|
||||
&:hover{
|
||||
animation: d-tableHoverAni 0.2s ease both;
|
||||
@keyframes d-tableHoverAni {
|
||||
to{
|
||||
box-shadow: var(--p-bsc-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
span{
|
||||
&.btn:hover{
|
||||
color: var(--p-fc-3)
|
||||
}
|
||||
}
|
||||
input{
|
||||
color: var(--p-fc-1);
|
||||
&::-webkit-input-placeholder{
|
||||
color: var(--p-fc-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
.tFooter{
|
||||
.tFooter-span{
|
||||
color: var(--p-fc-1);
|
||||
}
|
||||
}
|
||||
.zy-input{
|
||||
color: var(--p-fc-1);
|
||||
background-color: var(--p-bgc-1);
|
||||
input{
|
||||
color: var(--p-fc-1);
|
||||
}
|
||||
}
|
||||
.zy-scroll{
|
||||
&:hover{
|
||||
&::-webkit-scrollbar-thumb {
|
||||
box-shadow: var(--p-bsc-scroll);
|
||||
background: var(--p-c-3);
|
||||
background: var(--p-c-5);
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
box-shadow: var(--p-bsc-scroll);
|
||||
background: var(--bgc);
|
||||
background: var(--p-bgc-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,6 +70,7 @@
|
||||
background-color: var(--p-c-2);
|
||||
}
|
||||
&.active{
|
||||
background-color: var(--p-bgc-2);
|
||||
svg{
|
||||
stroke: var(--p-c-0);
|
||||
stroke-width: 2;
|
||||
@@ -123,15 +82,21 @@
|
||||
.frame{
|
||||
span{
|
||||
&.min{
|
||||
background-color: #32dc36;
|
||||
}
|
||||
&.max{
|
||||
background-color: #ffbe2a;
|
||||
}
|
||||
&.close{
|
||||
background-color: #ff5f56;
|
||||
}
|
||||
&.top{
|
||||
background-color: #f3bab7;
|
||||
}
|
||||
}
|
||||
}
|
||||
.detail{
|
||||
color: var(--p-fc-1);
|
||||
color: var(--p-fc-1) !important;
|
||||
background-color:var(--p-bgc-1);
|
||||
box-shadow: var(--p-bsc-2);
|
||||
.detail-content{
|
||||
@@ -146,10 +111,17 @@
|
||||
}
|
||||
}
|
||||
.detail-body{
|
||||
.info, .desc, .m3u8_urls, .mp4_urls{
|
||||
.info, .desc, .m3u8, .operate{
|
||||
border-color: var(--p-c-2);
|
||||
}
|
||||
.m3u8_urls, .mp4_urls{
|
||||
.operate{
|
||||
span{
|
||||
&:hover{
|
||||
color: var(--p-fc-2);
|
||||
}
|
||||
}
|
||||
}
|
||||
.m3u8{
|
||||
.box{
|
||||
span{
|
||||
border-color: var(--p-c-5);
|
||||
@@ -164,44 +136,23 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.film{
|
||||
.top{
|
||||
.search{
|
||||
background-color: var(--p-bgc-1);
|
||||
box-shadow: var(--p-bsc);
|
||||
&:hover{
|
||||
box-shadow: var(--p-bsc-hover);
|
||||
}
|
||||
svg{
|
||||
stroke: var(--p-c-0);
|
||||
stroke-width: 1;
|
||||
fill: none;
|
||||
}
|
||||
.search-box{
|
||||
background-color: var(--p-bgc-1);
|
||||
}
|
||||
&.active{
|
||||
box-shadow: var(--p-bsc-hover);
|
||||
svg{
|
||||
stroke-width: 1.5;
|
||||
fill: var(--p-c-2);
|
||||
}
|
||||
}
|
||||
input{
|
||||
color: var(--p-fc-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
.middle{
|
||||
background-color: var(--p-bgc-1);
|
||||
box-shadow: var(--p-bsc);
|
||||
}
|
||||
}
|
||||
.play{
|
||||
background-color: var(--p-bgc-1);
|
||||
box-shadow: var(--p-bsc);
|
||||
.el-input{
|
||||
input{
|
||||
background-color: var(--p-bgc-1);
|
||||
border: 1px solid var(--p-bgc-1);
|
||||
color: var(--p-fc-2);
|
||||
}
|
||||
}
|
||||
.title{
|
||||
color: var(--p-fc-1);
|
||||
.right {
|
||||
svg {
|
||||
fill: var(--p-fc-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
.box{
|
||||
.more{
|
||||
@@ -225,6 +176,10 @@
|
||||
fill: var(--p-c-3);
|
||||
}
|
||||
}
|
||||
&.last-tip {
|
||||
color: var(--p-fc-1);
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -254,6 +209,17 @@
|
||||
background-color: var(--p-c-2);
|
||||
color: var(--p-fc-3);
|
||||
}
|
||||
&:hover{
|
||||
background-color: var(--p-c-3);
|
||||
}
|
||||
}
|
||||
}
|
||||
.list-channels{
|
||||
.btn{
|
||||
color: var(--p-fc-1);
|
||||
&:hover{
|
||||
text-decoration:underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
.list-history{
|
||||
@@ -283,14 +249,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.play-mask{
|
||||
background-color: var(--p-bgc-1);
|
||||
color: var(--p-fc-1);
|
||||
}
|
||||
}
|
||||
.star{
|
||||
background-color: var(--p-bgc-1);
|
||||
box-shadow: var(--p-bsc);
|
||||
}
|
||||
.setting{
|
||||
background-color: var(--p-bgc-1);
|
||||
@@ -303,12 +261,18 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.view, .search, .shortcut, .site{
|
||||
.title{
|
||||
color: var(--p-fc-1);
|
||||
}
|
||||
}
|
||||
.theme{
|
||||
.title{
|
||||
color: var(--p-fc-1);
|
||||
}
|
||||
.theme-item{
|
||||
box-shadow: var(--p-bsc);
|
||||
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
|
||||
&:hover{
|
||||
box-shadow: var(--p-bsc-hover);
|
||||
.theme-name{
|
||||
@@ -326,6 +290,10 @@
|
||||
}
|
||||
.qrcode-item{
|
||||
box-shadow: var(--p-bsc);
|
||||
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
|
||||
&:hover{
|
||||
box-shadow: var(--p-bsc-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -343,4 +311,118 @@
|
||||
background-color: var(--p-bgc-1);
|
||||
}
|
||||
}
|
||||
.history{
|
||||
background-color: var(--p-bgc-1);
|
||||
box-shadow: var(--p-bsc);
|
||||
}
|
||||
|
||||
// Page of list using table and picture
|
||||
.listpage{
|
||||
color: var(--p-fc-2);
|
||||
.listpage-header{
|
||||
border-bottom-color: var(--p-c-3);
|
||||
.btn{
|
||||
&:hover{
|
||||
color: var(--p-fc-3)
|
||||
}
|
||||
}
|
||||
.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);
|
||||
}
|
||||
}
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
.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-table__body-wrapper{
|
||||
&: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-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);
|
||||
}
|
||||
.el-button{
|
||||
color: var(--p-fc-1);
|
||||
&:hover{
|
||||
color: var(--p-fc-3)
|
||||
}
|
||||
}
|
||||
}
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
'use strict'
|
||||
|
||||
import { app, ipcMain, protocol, BrowserWindow } from 'electron'
|
||||
import {
|
||||
createProtocol
|
||||
// installVueDevtools
|
||||
} from 'vue-cli-plugin-electron-builder/lib'
|
||||
import path from 'path'
|
||||
import { autoUpdater } from 'electron-updater'
|
||||
import './lib/site/server'
|
||||
import { app, protocol, BrowserWindow, globalShortcut } from 'electron'
|
||||
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
|
||||
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
|
||||
import { initUpdater } from './lib/update/update'
|
||||
const isDevelopment = process.env.NODE_ENV !== 'production'
|
||||
const globalShortcut = require('electron').globalShortcut
|
||||
|
||||
app.commandLine.appendSwitch('disable-features', 'OutOfBlinkCors') // 允许跨域
|
||||
// app.commandLine.appendSwitch('--ignore-certificate-errors', 'true') // 忽略证书相关错误
|
||||
|
||||
let win
|
||||
let mini
|
||||
|
||||
// Scheme must be registered before the app is ready
|
||||
protocol.registerSchemesAsPrivileged([{ scheme: 'app', privileges: { secure: true, standard: true } }])
|
||||
|
||||
function createWindow () {
|
||||
@@ -22,99 +20,45 @@ function createWindow () {
|
||||
height: 720,
|
||||
frame: false,
|
||||
resizable: true,
|
||||
transparent: true,
|
||||
webPreferences: {
|
||||
webSecurity: false,
|
||||
enableRemoteModule: true,
|
||||
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION
|
||||
},
|
||||
// eslint-disable-next-line
|
||||
icon: path.join(__static, 'icon.png')
|
||||
}
|
||||
})
|
||||
|
||||
if (process.env.WEBPACK_DEV_SERVER_URL) {
|
||||
win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
|
||||
if (!process.env.IS_TEST) win.webContents.openDevTools()
|
||||
} else {
|
||||
createProtocol('app')
|
||||
win.loadURL('app://./index.html')
|
||||
autoUpdater.checkForUpdatesAndNotify()
|
||||
}
|
||||
|
||||
initUpdater(win)
|
||||
|
||||
win.on('closed', () => {
|
||||
win = null
|
||||
})
|
||||
}
|
||||
|
||||
function createMini () {
|
||||
mini = new BrowserWindow({
|
||||
width: 550,
|
||||
minWidth: 260,
|
||||
height: 340,
|
||||
minHeight: 180,
|
||||
frame: false,
|
||||
resizable: true,
|
||||
transparent: true,
|
||||
alwaysOnTop: true,
|
||||
webPreferences: {
|
||||
webSecurity: false,
|
||||
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION
|
||||
},
|
||||
// eslint-disable-next-line
|
||||
icon: path.join(__static, 'icon.png')
|
||||
})
|
||||
|
||||
if (process.env.WEBPACK_DEV_SERVER_URL) {
|
||||
mini.loadURL(process.env.WEBPACK_DEV_SERVER_URL + 'mini')
|
||||
if (!process.env.IS_TEST) mini.webContents.openDevTools()
|
||||
} else {
|
||||
mini.loadURL('app://./mini.html')
|
||||
}
|
||||
|
||||
mini.on('closed', () => {
|
||||
mini = null
|
||||
})
|
||||
if (process.platform === 'darwin') {
|
||||
app.dock.show()
|
||||
}
|
||||
|
||||
app.allowRendererProcessReuse = true
|
||||
app.commandLine.appendSwitch('disable-features', 'OutOfBlinkCors')
|
||||
if (process.platform === 'Linux') {
|
||||
app.disableHardwareAcceleration()
|
||||
app.commandLine.appendSwitch('--no-sandbox') // linux 关闭沙盒模式
|
||||
}
|
||||
app.allowRendererProcessReuse = true
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
app.quit()
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (win === null) {
|
||||
createWindow()
|
||||
}
|
||||
if (mini === null) {
|
||||
createMini()
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('min', () => {
|
||||
win.minimize()
|
||||
})
|
||||
ipcMain.on('close', () => {
|
||||
win.close()
|
||||
})
|
||||
|
||||
ipcMain.on('mini', () => {
|
||||
createMini()
|
||||
win.close()
|
||||
})
|
||||
ipcMain.on('miniMin', () => {
|
||||
mini.minimize()
|
||||
})
|
||||
ipcMain.on('miniClose', () => {
|
||||
mini.close()
|
||||
createWindow()
|
||||
})
|
||||
ipcMain.on('miniOpacity', (e, arg) => {
|
||||
mini.setOpacity(arg)
|
||||
})
|
||||
|
||||
const gotTheLock = app.requestSingleInstanceLock()
|
||||
@@ -122,65 +66,28 @@ if (!gotTheLock) {
|
||||
app.quit()
|
||||
} else {
|
||||
app.on('second-instance', (event, commandLine, workingDirectory) => {
|
||||
// 当运行第二个实例时,将会聚焦到win这个窗口
|
||||
if (win) {
|
||||
if (win.isMinimized()) win.restore()
|
||||
win.focus()
|
||||
}
|
||||
})
|
||||
|
||||
// 创建 win, 加载应用的其余部分, etc...
|
||||
app.on('ready', () => {
|
||||
globalShortcut.register('CommandOrControl+right', function () {
|
||||
if (win) {
|
||||
win.webContents.send('next', 0)
|
||||
app.on('ready', async () => {
|
||||
if (isDevelopment && !process.env.IS_TEST) {
|
||||
try {
|
||||
await installExtension(VUEJS_DEVTOOLS)
|
||||
} catch (e) {
|
||||
console.error('Vue Devtools failed to install:', e.toString())
|
||||
}
|
||||
if (mini) {
|
||||
mini.webContents.send('next', 0)
|
||||
}
|
||||
})
|
||||
globalShortcut.register('CommandOrControl+left', function () {
|
||||
if (win) {
|
||||
win.webContents.send('prev', 0)
|
||||
}
|
||||
if (mini) {
|
||||
mini.webContents.send('prev', 0)
|
||||
}
|
||||
})
|
||||
globalShortcut.register('CommandOrControl+up', function () {
|
||||
if (mini) {
|
||||
mini.webContents.send('up', 0)
|
||||
}
|
||||
})
|
||||
globalShortcut.register('CommandOrControl+down', function () {
|
||||
if (mini) {
|
||||
mini.webContents.send('down', 0)
|
||||
}
|
||||
})
|
||||
globalShortcut.register('shift+up', function () {
|
||||
if (win) {
|
||||
win.webContents.send('playbackRateUp', 0)
|
||||
}
|
||||
if (mini) {
|
||||
mini.webContents.send('playbackRateUp', 0)
|
||||
}
|
||||
})
|
||||
globalShortcut.register('shift+down', function () {
|
||||
if (win) {
|
||||
win.webContents.send('playbackRateDown', 0)
|
||||
}
|
||||
if (mini) {
|
||||
mini.webContents.send('playbackRateDown', 0)
|
||||
}
|
||||
})
|
||||
if (!process.env.WEBPACK_DEV_SERVER_URL) {
|
||||
createProtocol('app')
|
||||
}
|
||||
createWindow()
|
||||
globalShortcut.register('Alt+Space', () => {
|
||||
if (win) {
|
||||
win.isFocused() ? win.blur() : win.focus()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Exit cleanly on request from parent process in development mode.
|
||||
if (isDevelopment) {
|
||||
if (process.platform === 'win32') {
|
||||
process.on('message', data => {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="aside">
|
||||
<span :class="[view === 'Film' ? 'active ': ''] + 'zy-svg'" @click="changeView('Film')">
|
||||
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-labelledby="apertureIconTitle">
|
||||
<title id="apertureIconTitle">{{$t('view')}}</title>
|
||||
<title id="apertureIconTitle">电影</title>
|
||||
<path d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z"></path>
|
||||
<g stroke-linecap="round">
|
||||
<path d="M3 16H14.3164"></path>
|
||||
@@ -14,21 +14,35 @@
|
||||
</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 === 'Play' ? 'active ': ''] + 'zy-svg'" @click="changeView('Play')">
|
||||
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-labelledby="playIconTitle">
|
||||
<title id="playIconTitle">{{$t('play')}}</title>
|
||||
<title id="playIconTitle">播放</title>
|
||||
<path d="M20 12L5 21V3z"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<span :class="[view === 'Star' ? 'active ': ''] + 'zy-svg'" @click="changeView('Star')">
|
||||
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-labelledby="favouriteIconTitle">
|
||||
<title id="favouriteIconTitle">{{$t('star')}}</title>
|
||||
<title id="favouriteIconTitle">收藏</title>
|
||||
<path d="M12,21 L10.55,19.7051771 C5.4,15.1242507 2,12.1029973 2,8.39509537 C2,5.37384196 4.42,3 7.5,3 C9.24,3 10.91,3.79455041 12,5.05013624 C13.09,3.79455041 14.76,3 16.5,3 C19.58,3 22,5.37384196 22,8.39509537 C22,12.1029973 18.6,15.1242507 13.45,19.7149864 L12,21 Z"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<span :class="[view === 'History' ? 'active ': ''] + 'zy-svg'" @click="changeView('History')">
|
||||
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-labelledby="timeIconTitle">
|
||||
<title id="timeIconTitle">历史记录</title>
|
||||
<circle cx="12" cy="12" r="10"></circle>
|
||||
<polyline points="12 5 12 12 16 16"></polyline>
|
||||
</svg>
|
||||
</span>
|
||||
<span :class="[view === 'Setting' ? 'active ': ''] + 'zy-svg'" @click="changeView('Setting')">
|
||||
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-labelledby="settingsIconTitle">
|
||||
<title id="settingsIconTitle">{{$t('setting')}}</title>
|
||||
<title id="settingsIconTitle">设置</title>
|
||||
<path d="M5.03506429,12.7050339 C5.01187484,12.4731696 5,12.2379716 5,12 C5,11.7620284 5.01187484,11.5268304 5.03506429,11.2949661 L3.20577137,9.23205081 L5.20577137,5.76794919 L7.9069713,6.32070904 C8.28729123,6.0461342 8.69629298,5.80882212 9.12862533,5.61412402 L10,3 L14,3 L14.8713747,5.61412402 C15.303707,5.80882212 15.7127088,6.0461342 16.0930287,6.32070904 L18.7942286,5.76794919 L20.7942286,9.23205081 L18.9649357,11.2949661 C18.9881252,11.5268304 19,11.7620284 19,12 C19,12.2379716 18.9881252,12.4731696 18.9649357,12.7050339 L20.7942286,14.7679492 L18.7942286,18.2320508 L16.0930287,17.679291 C15.7127088,17.9538658 15.303707,18.1911779 14.8713747,18.385876 L14,21 L10,21 L9.12862533,18.385876 C8.69629298,18.1911779 8.28729123,17.9538658 7.9069713,17.679291 L5.20577137,18.2320508 L3.20577137,14.7679492 L5.03506429,12.7050339 Z"></path>
|
||||
<circle cx="12" cy="12" r="1"></circle>
|
||||
</svg>
|
||||
@@ -47,12 +61,23 @@ export default {
|
||||
set (val) {
|
||||
this.SET_VIEW(val)
|
||||
}
|
||||
},
|
||||
detail: {
|
||||
get () {
|
||||
return this.$store.getters.getDetail
|
||||
},
|
||||
set (val) {
|
||||
this.SET_DETAIL(val)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SET_VIEW']),
|
||||
...mapMutations(['SET_VIEW', 'SET_DETAIL']),
|
||||
changeView (e) {
|
||||
this.view = e
|
||||
this.detail = {
|
||||
show: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,17 +86,17 @@ export default {
|
||||
.aside{
|
||||
width: 60px;
|
||||
height: 100%;
|
||||
user-select: none;
|
||||
-webkit-app-region: drag;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
user-select: none;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
-webkit-app-region: drag;
|
||||
span{
|
||||
-webkit-app-region: no-drag;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
cursor: pointer;
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,28 +2,60 @@
|
||||
<div class="detail">
|
||||
<div class="detail-content">
|
||||
<div class="detail-header">
|
||||
<span class="detail-title">{{$t('detail')}}</span>
|
||||
<span class="detail-close zy-svg" @click="closeDetail">
|
||||
<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">{{$t('close')}}</title>
|
||||
<span class="detail-title">详情</span>
|
||||
<span class="detail-close zy-svg" @click="close">
|
||||
<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>
|
||||
<path d="M6.34314575 6.34314575L17.6568542 17.6568542M6.34314575 17.6568542L17.6568542 6.34314575"></path>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<div class="detail-body zy-scroll" v-show="!loading" :style="{overflowY:scroll? 'auto' : 'hidden',paddingRight: scroll ? '0': '5px' }" @mouseenter="scroll = true" @mouseleave="scroll = false">
|
||||
<div class="info" v-html="vDetail.info"></div>
|
||||
<div class="desc" v-html="vDetail.desc" v-if="show.desc"></div>
|
||||
<div class="m3u8_urls">
|
||||
<div class="title">{{$t('play')}}:</div>
|
||||
<div class="box">
|
||||
<span v-for="(i, j) in vDetail.m3u8_urls" :key="j" @click="playEvent(j)">{{i | ftName}}</span>
|
||||
<div class="detail-body zy-scroll" v-show="!loading">
|
||||
<div class="info">
|
||||
<div class="info-left">
|
||||
<img :src="info.pic" alt="">
|
||||
</div>
|
||||
<div class="info-right">
|
||||
<div class="name">{{info.name}}</div>
|
||||
<div class="director" v-show="info.director">导演: {{info.director}}</div>
|
||||
<div class="actor" v-show="info.actor">主演: {{info.actor}}</div>
|
||||
<div class="type" v-show="info.type">类型: {{info.type}}</div>
|
||||
<div class="area" v-show="info.area">地区: {{info.area}}</div>
|
||||
<div class="lang" v-show="info.lang">语言: {{info.lang}}</div>
|
||||
<div class="year" v-show="info.year">上映: {{info.year}}</div>
|
||||
<div class="last" v-show="info.last">更新: {{info.last}}</div>
|
||||
<div class="note" v-show="info.note">备注: {{info.note}}</div>
|
||||
<div class="rate" v-show="info.rate">豆瓣评分: {{info.rate}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mp4_urls" v-if="show.download">
|
||||
<div class="title">{{$t('download')}}:</div>
|
||||
<div class="operate">
|
||||
<span @click="playEvent(0)">播放</span>
|
||||
<span @click="starEvent">收藏</span>
|
||||
<span @click="downloadEvent">下载</span>
|
||||
<span @click="shareEvent">分享</span>
|
||||
<span @click="doubanLinkEvent">豆瓣</span>
|
||||
<span @click="togglePlayOnlineEvent">
|
||||
<input type="checkbox" v-model="playOnline"> 播放在线高清视频
|
||||
</span>
|
||||
<span>
|
||||
<select v-model="selectedOnlineSite" class="vs-options">
|
||||
<option disabled value="">Please select one</option>
|
||||
<option v-for="(i, j) in onlineSites" :key="j">{{i}}</option>
|
||||
</select>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="desc" v-show="info.des">{{info.des}}</div>
|
||||
<div class="m3u8">
|
||||
<div class="box">
|
||||
<span v-for="(i, j) in vDetail.mp4_urls" :key="j" @click="download(i)">{{i | ftName}}</span>
|
||||
<span @click="allDownload" v-show="vDetail.mp4_urls.length > 1">{{$t('all_download')}}</span>
|
||||
<span v-for="(i, j) in m3u8List" :key="j" @click="playEvent(j)">{{i | ftName}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -35,19 +67,20 @@
|
||||
</template>
|
||||
<script>
|
||||
import { mapMutations } from 'vuex'
|
||||
import tools from '../lib/site/tools'
|
||||
import zy from '../lib/site/tools'
|
||||
import onlineVideo from '../lib/site/onlineVideo'
|
||||
import { star, history } from '../lib/dexie'
|
||||
const { clipboard } = require('electron')
|
||||
export default {
|
||||
name: 'detail',
|
||||
data () {
|
||||
return {
|
||||
scroll: false,
|
||||
loading: true,
|
||||
vDetail: {},
|
||||
show: {
|
||||
desc: false,
|
||||
download: false
|
||||
}
|
||||
m3u8List: [],
|
||||
info: {},
|
||||
playOnline: false,
|
||||
selectedOnlineSite: '哔嘀',
|
||||
onlineSites: ['哔嘀', '素白白', '简影', '极品', '喜欢看', '1080影视']
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
@@ -65,6 +98,14 @@ export default {
|
||||
this.SET_VIEW(val)
|
||||
}
|
||||
},
|
||||
detail: {
|
||||
get () {
|
||||
return this.$store.getters.getDetail
|
||||
},
|
||||
set (val) {
|
||||
this.SET_DETAIL(val)
|
||||
}
|
||||
},
|
||||
video: {
|
||||
get () {
|
||||
return this.$store.getters.getVideo
|
||||
@@ -73,274 +114,340 @@ export default {
|
||||
this.SET_VIDEO(val)
|
||||
}
|
||||
},
|
||||
detail: {
|
||||
share: {
|
||||
get () {
|
||||
return this.$store.getters.getDetail
|
||||
return this.$store.getters.getShare
|
||||
},
|
||||
set (val) {
|
||||
this.SET_DETAIL(val)
|
||||
this.SET_SHARE(val)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SET_VIEW', 'SET_VIDEO', 'SET_DETAIL']),
|
||||
closeDetail () {
|
||||
...mapMutations(['SET_VIEW', 'SET_VIDEO', 'SET_DETAIL', 'SET_SHARE']),
|
||||
close () {
|
||||
this.detail.show = false
|
||||
},
|
||||
getDetail () {
|
||||
tools.detail_get(this.detail.v.site, this.detail.v.detail).then(res => {
|
||||
this.vDetail = res
|
||||
if (res.desc.length > 0) {
|
||||
this.show.desc = true
|
||||
async playEvent (n) {
|
||||
if (!this.playOnline) {
|
||||
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 } }
|
||||
}
|
||||
if (res.mp4_urls.length > 0) {
|
||||
this.show.download = true
|
||||
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 = {
|
||||
site: this.detail.key,
|
||||
ids: this.detail.info.id,
|
||||
name: this.detail.info.name,
|
||||
type: this.detail.info.type,
|
||||
year: this.detail.info.year,
|
||||
index: n,
|
||||
time: '',
|
||||
detail: this.info
|
||||
}
|
||||
history.add(doc)
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.loading = false
|
||||
onlineVideo.playVideoOnline(this.selectedOnlineSite, this.detail.info.name, n)
|
||||
}
|
||||
},
|
||||
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) {
|
||||
star.update(db.id, doc)
|
||||
this.$message.success('收藏更新成功')
|
||||
} else {
|
||||
star.add(doc).then(res => {
|
||||
this.$message.success('收藏成功')
|
||||
})
|
||||
}
|
||||
},
|
||||
togglePlayOnlineEvent () {
|
||||
this.playOnline = !this.playOnline
|
||||
},
|
||||
playVideoOnline (videoName, videoIndex) {
|
||||
switch (this.selectedOnlineSite) {
|
||||
case '哔嘀':
|
||||
onlineVideo.playVideoOnBde4(videoName, videoIndex)
|
||||
break
|
||||
case '1080影视':
|
||||
onlineVideo.playVideoOnK1080(videoName, videoIndex)
|
||||
break
|
||||
case '素白白':
|
||||
onlineVideo.playVideoOnSubaibai(videoName, videoIndex)
|
||||
break
|
||||
case '哆咪动漫':
|
||||
onlineVideo.playVideoOndmdm2020(videoName, videoIndex)
|
||||
break
|
||||
case '樱花动漫':
|
||||
onlineVideo.playVideoOnYhdm(videoName, videoIndex)
|
||||
break
|
||||
case '简影':
|
||||
onlineVideo.playVideoOnSyrme(videoName, videoIndex)
|
||||
break
|
||||
case '极品':
|
||||
onlineVideo.playVideoOnJpysvip(videoName, videoIndex)
|
||||
break
|
||||
default:
|
||||
this.$message.console.error(`不支持该网站:${this.selectedOnlineSite}`)
|
||||
}
|
||||
},
|
||||
downloadEvent () {
|
||||
zy.download(this.detail.key, this.info.id).then(res => {
|
||||
if (res && res.dl && res.dl.dd) {
|
||||
const text = res.dl.dd._t
|
||||
if (text) {
|
||||
const list = text.split('#')
|
||||
let downloadUrl = res.name + '\n'
|
||||
for (const i of list) {
|
||||
const url = encodeURI(i.split('$')[1])
|
||||
downloadUrl += (url + '\n')
|
||||
}
|
||||
clipboard.writeText(downloadUrl)
|
||||
this.$message.success('『MP4』格式的链接已复制, 快去下载吧!')
|
||||
} else {
|
||||
this.$message.warning('没有查询到下载链接.')
|
||||
}
|
||||
} else {
|
||||
const list = [...this.m3u8List]
|
||||
let downloadUrl = this.detail.info.name + '\n'
|
||||
for (const i of list) {
|
||||
const url = encodeURI(i.split('$')[1])
|
||||
downloadUrl += (url + '\n')
|
||||
}
|
||||
clipboard.writeText(downloadUrl)
|
||||
this.$message.success('『M3U8』格式的链接已复制, 快去下载吧!')
|
||||
}
|
||||
})
|
||||
},
|
||||
playEvent (n) {
|
||||
const v = { ...this.detail.v }
|
||||
v.index = n
|
||||
this.video = v
|
||||
this.detail.show = false
|
||||
this.view = 'Play'
|
||||
},
|
||||
download (e) {
|
||||
const name = e.split('$')[0]
|
||||
const txt = encodeURI(e.split('$')[1])
|
||||
clipboard.writeText(txt)
|
||||
this.$m.success(name + this.$t('copy_success'))
|
||||
},
|
||||
allDownload () {
|
||||
const urls = [...this.vDetail.mp4_urls]
|
||||
let txt = ''
|
||||
for (const i of urls) {
|
||||
const url = encodeURI(i.split('$')[1])
|
||||
txt += (url + '\n')
|
||||
shareEvent () {
|
||||
this.share = {
|
||||
show: true,
|
||||
key: this.detail.key,
|
||||
info: this.detail.info
|
||||
}
|
||||
clipboard.writeText(txt)
|
||||
this.$m.success(this.$t('copy_success'))
|
||||
},
|
||||
doubanLinkEvent () {
|
||||
const name = this.detail.info.name.trim()
|
||||
zy.doubanLink(name).then(link => {
|
||||
const open = require('open')
|
||||
open(link)
|
||||
})
|
||||
},
|
||||
getDoubanRate () {
|
||||
const name = this.detail.info.name.trim()
|
||||
zy.doubanRate(name).then(res => {
|
||||
this.info.rate = res
|
||||
})
|
||||
},
|
||||
getDetailInfo () {
|
||||
const id = this.detail.info.ids || this.detail.info.id
|
||||
zy.detail(this.detail.key, id).then(res => {
|
||||
if (res) {
|
||||
this.info = res
|
||||
this.$set(this.info, 'rate', '')
|
||||
this.m3u8List = res.m3u8List
|
||||
this.getDoubanRate()
|
||||
this.loading = false
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getDetail()
|
||||
this.getDetailInfo()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.detail{
|
||||
<style lang="scss" scoped>
|
||||
.detail {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
left: 80px;
|
||||
right: 20px;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
width: calc(100% - 100px);
|
||||
height: calc(100% - 40px);
|
||||
z-index: 999;
|
||||
.detail-content{
|
||||
z-index: 888;
|
||||
.detail-content {
|
||||
height: calc(100% - 10px);
|
||||
padding: 0 60px;
|
||||
position: relative;
|
||||
.detail-header{
|
||||
.detail-header {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 -40px;
|
||||
.detail-title{
|
||||
justify-content: space-between;
|
||||
.detail-title {
|
||||
font-size: 16px;
|
||||
}
|
||||
.detail-close{
|
||||
.detail-close {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.detail-body{
|
||||
height: calc(100% - 50px);
|
||||
overflow-y: auto;
|
||||
.info{
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid;
|
||||
border-radius: 2px;
|
||||
margin-bottom: 10px;
|
||||
.vodImg{
|
||||
width: 200px;
|
||||
img{
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
.vodAd{
|
||||
display: none;
|
||||
}
|
||||
.vodInfo{
|
||||
flex: 1;
|
||||
margin-left: 20px;
|
||||
overflow: hidden;
|
||||
.vodh{
|
||||
margin-bottom: 6px;
|
||||
h2{
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
}
|
||||
span{
|
||||
font-size: 12px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
label{
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
.cont, .tags{
|
||||
display: none;
|
||||
}
|
||||
ul{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
a{
|
||||
display: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
li{
|
||||
list-style: none;
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
height: 18px;
|
||||
overflow: hidden;
|
||||
span{
|
||||
word-wrap: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
.whitetitle{
|
||||
}
|
||||
.detail-body {
|
||||
height: calc(100% - 50px);
|
||||
overflow-y: auto;
|
||||
.info {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
border: 1px solid;
|
||||
border-radius: 2px;
|
||||
margin-bottom: 10px;
|
||||
height: auto;
|
||||
.info-left {
|
||||
width: 200px;
|
||||
height: 100%;
|
||||
img {
|
||||
width: 100%;
|
||||
font-size: 22px;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
.info-right {
|
||||
flex: 1;
|
||||
margin-left: 20px;
|
||||
.name {
|
||||
font-size: 20px;
|
||||
margin-bottom: 10px;
|
||||
font-weight: bold;
|
||||
margin: 4px 0;
|
||||
}
|
||||
.people{
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
.left{
|
||||
width: 200px;
|
||||
img{
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
.right{
|
||||
flex: 1;
|
||||
margin-left: 20px;
|
||||
overflow: hidden;
|
||||
p{
|
||||
font-size: 14px;
|
||||
}
|
||||
a{
|
||||
pointer-events: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
.director,
|
||||
.actor,
|
||||
.type,
|
||||
.area,
|
||||
.lang,
|
||||
.year,
|
||||
.last,
|
||||
.note {
|
||||
font-size: 14px;
|
||||
line-height: 26px;
|
||||
}
|
||||
}
|
||||
.desc{
|
||||
border: 1px solid;
|
||||
padding: 10px;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 2px;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
.m3u8_urls, .mp4_urls{
|
||||
border: 1px solid;
|
||||
padding: 10px;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 2px;
|
||||
.title{
|
||||
.rate {
|
||||
font-size: 16px;
|
||||
line-height: 26px;
|
||||
font-weight: bolder;
|
||||
}
|
||||
.box{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
span{
|
||||
font-size: 12px;
|
||||
border: 1px solid;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
margin: 6px 6px 0px 0px;
|
||||
padding: 8px 22px;
|
||||
}
|
||||
&::after {
|
||||
content: '';
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
.mp4_urls{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
.detail-mask{
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
left: 0;
|
||||
.operate {
|
||||
border: 1px solid;
|
||||
padding: 10px;
|
||||
width: 100%;
|
||||
height: calc(100 - 50px);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.loader {
|
||||
font-size: 8px;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
text-indent: -9999em;
|
||||
animation: load4 1.3s infinite linear;
|
||||
transform: translateZ(0);
|
||||
margin-bottom: 10px;
|
||||
border-radius: 2px;
|
||||
span {
|
||||
margin-right: 20px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
@keyframes load4 {
|
||||
0%,
|
||||
100% {
|
||||
box-shadow: 0 -3em 0 0.2em, 2em -2em 0 0em, 3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 0;
|
||||
}
|
||||
12.5% {
|
||||
box-shadow: 0 -3em 0 0, 2em -2em 0 0.2em, 3em 0 0 0, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 -1em;
|
||||
}
|
||||
25% {
|
||||
box-shadow: 0 -3em 0 -0.5em, 2em -2em 0 0, 3em 0 0 0.2em, 2em 2em 0 0, 0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 -1em;
|
||||
}
|
||||
37.5% {
|
||||
box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0em 0 0, 2em 2em 0 0.2em, 0 3em 0 0em, -2em 2em 0 -1em, -3em 0em 0 -1em, -2em -2em 0 -1em;
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 0em, 0 3em 0 0.2em, -2em 2em 0 0, -3em 0em 0 -1em, -2em -2em 0 -1em;
|
||||
}
|
||||
62.5% {
|
||||
box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 0, -2em 2em 0 0.2em, -3em 0 0 0, -2em -2em 0 -1em;
|
||||
}
|
||||
75% {
|
||||
box-shadow: 0em -3em 0 -1em, 2em -2em 0 -1em, 3em 0em 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 0, -3em 0em 0 0.2em, -2em -2em 0 0;
|
||||
}
|
||||
87.5% {
|
||||
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;
|
||||
}
|
||||
.desc {
|
||||
border: 1px solid;
|
||||
padding: 10px;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 2px;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
.m3u8 {
|
||||
border: 1px solid;
|
||||
padding: 10px 0 10px 10px;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 2px;
|
||||
.box {
|
||||
width: 100%;
|
||||
span {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
border: 1px solid;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
margin: 6px 10px 0px 0px;
|
||||
padding: 8px 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.detail-mask {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: calc(100% - 50px);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.loader {
|
||||
font-size: 8px;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
text-indent: -9999em;
|
||||
animation: load4 1.3s infinite linear;
|
||||
transform: translateZ(0);
|
||||
}
|
||||
@keyframes load4 {
|
||||
0%,
|
||||
100% {
|
||||
box-shadow: 0 -3em 0 0.2em, 2em -2em 0 0em, 3em 0 0 -1em, 2em 2em 0 -1em,
|
||||
0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 0;
|
||||
}
|
||||
12.5% {
|
||||
box-shadow: 0 -3em 0 0, 2em -2em 0 0.2em, 3em 0 0 0, 2em 2em 0 -1em,
|
||||
0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 -1em;
|
||||
}
|
||||
25% {
|
||||
box-shadow: 0 -3em 0 -0.5em, 2em -2em 0 0, 3em 0 0 0.2em, 2em 2em 0 0,
|
||||
0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 -1em;
|
||||
}
|
||||
37.5% {
|
||||
box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0em 0 0, 2em 2em 0 0.2em,
|
||||
0 3em 0 0em, -2em 2em 0 -1em, -3em 0em 0 -1em, -2em -2em 0 -1em;
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 0em,
|
||||
0 3em 0 0.2em, -2em 2em 0 0, -3em 0em 0 -1em, -2em -2em 0 -1em;
|
||||
}
|
||||
62.5% {
|
||||
box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 -1em,
|
||||
0 3em 0 0, -2em 2em 0 0.2em, -3em 0 0 0, -2em -2em 0 -1em;
|
||||
}
|
||||
75% {
|
||||
box-shadow: 0em -3em 0 -1em, 2em -2em 0 -1em, 3em 0em 0 -1em,
|
||||
2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 0, -3em 0em 0 0.2em,
|
||||
-2em -2em 0 0;
|
||||
}
|
||||
87.5% {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
504
src/components/EditSites.vue
Normal file
504
src/components/EditSites.vue
Normal file
@@ -0,0 +1,504 @@
|
||||
<template>
|
||||
<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"
|
||||
:data="sites"
|
||||
@select="selectionCellClick"
|
||||
@selection-change="handleSelectionChange"
|
||||
@sort-change="handleSortChange">
|
||||
<el-table-column
|
||||
type="selection"
|
||||
v-if="enableBatchEdit">
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="name"
|
||||
label="资源名">
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="isActive"
|
||||
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"
|
||||
@click.native.stop='isActiveChangeEvent(scope.row)'>
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="group"
|
||||
label="分组"
|
||||
:filters="getFilters"
|
||||
:filter-method="(value, row) => value === row.group"
|
||||
filter-placement="bottom-end">
|
||||
</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="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>
|
||||
<el-dialog :visible.sync="dialogVisible" v-if='dialogVisible' :title="dialogType==='edit'?'编辑源':'新增源'" :append-to-body="true" @close="closeDialog">
|
||||
<el-form :model="siteInfo" ref='siteInfo' label-width="75px" label-position="left" :rules="rules">
|
||||
<el-form-item label="源站名" prop='name'>
|
||||
<el-input v-model="siteInfo.name" placeholder="请输入源站名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="API接口" prop='api'>
|
||||
<el-input v-model="siteInfo.api" :autosize="{ minRows: 2, maxRows: 4}" type="textarea" placeholder="请输入API接口地址"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="下载接口" prop='download'>
|
||||
<el-input v-model="siteInfo.download" :autosize="{ minRows: 2, maxRows: 4}" type="textarea" placeholder="请输入Download接口地址,可以空着"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="分组" prop='group'>
|
||||
<el-select v-model="siteInfo.group" allow-create filterable default-first-option placeholder="请输入分组">
|
||||
<el-option v-for="item in siteGroup" :key="item" :label="item" :value="item"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="源站标识" prop='key'>
|
||||
<el-input v-model="siteInfo.key" placeholder="请输入源站标识,如果为空,系统则自动生成" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="closeDialog">取消</el-button>
|
||||
<el-button type="primary" @click="addOrEditSite">保存</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapMutations } from 'vuex'
|
||||
import { sites, setting } from '../lib/dexie'
|
||||
import zy from '../lib/site/tools'
|
||||
import { remote } from 'electron'
|
||||
import { sites as defaultSites } from '../lib/dexie/initData'
|
||||
import fs from 'fs'
|
||||
import Sortable from 'sortablejs'
|
||||
|
||||
export default {
|
||||
name: 'editSites',
|
||||
data () {
|
||||
return {
|
||||
show: false,
|
||||
sites: [],
|
||||
dialogType: 'new',
|
||||
dialogVisible: false,
|
||||
siteInfo: {
|
||||
key: '',
|
||||
name: '',
|
||||
api: '',
|
||||
download: '',
|
||||
group: '',
|
||||
isActive: true
|
||||
},
|
||||
siteGroup: [],
|
||||
rules: {
|
||||
name: [
|
||||
{ required: true, message: '源站名不能为空', trigger: 'blur' }
|
||||
],
|
||||
api: [
|
||||
{ required: true, message: 'API地址不能为空', trigger: 'blur' }
|
||||
]
|
||||
},
|
||||
enableBatchEdit: false,
|
||||
batchGroupName: '',
|
||||
batchIsActive: true,
|
||||
shiftDown: false,
|
||||
selectionBegin: '',
|
||||
selectionEnd: '',
|
||||
multipleSelection: [],
|
||||
checkAllSitesLoading: false,
|
||||
checkProgress: 0,
|
||||
stopFlag: false,
|
||||
editOldkey: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
setting: {
|
||||
get () {
|
||||
return this.$store.getters.getSetting
|
||||
},
|
||||
set (val) {
|
||||
this.SET_SETTING(val)
|
||||
}
|
||||
},
|
||||
getFilters () {
|
||||
const groups = [...new Set(this.sites.map(site => site.group))]
|
||||
var filters = []
|
||||
groups.forEach(g => {
|
||||
var doc = {
|
||||
text: g,
|
||||
value: g
|
||||
}
|
||||
filters.push(doc)
|
||||
})
|
||||
return filters
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
enableBatchEdit () {
|
||||
if (this.checkAllSitesLoading) {
|
||||
this.$message.info('正在检测, 请勿操作.')
|
||||
this.enableBatchEdit = false
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SET_SETTING']),
|
||||
excludeR18FilmsChangeEvent () {
|
||||
setting.find().then(res => {
|
||||
res.excludeR18Films = this.setting.excludeR18Films
|
||||
setting.update(res)
|
||||
})
|
||||
},
|
||||
selectionCellClick (selection, row) {
|
||||
if (this.shiftDown && this.selectionBegin !== '' && selection.includes(row)) {
|
||||
this.selectionEnd = row.id
|
||||
const start = this.sites.findIndex(e => e.id === Math.min(this.selectionBegin, this.selectionEnd))
|
||||
const end = this.sites.findIndex(e => e.id === Math.max(this.selectionBegin, this.selectionEnd))
|
||||
const selections = this.sites.slice(start, end + 1)
|
||||
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 () {
|
||||
this.multipleSelection.forEach(ele => {
|
||||
if (this.batchGroupName) {
|
||||
ele.group = this.batchGroupName
|
||||
}
|
||||
ele.isActive = this.batchIsActive
|
||||
})
|
||||
this.updateDatabase()
|
||||
},
|
||||
getSites () {
|
||||
sites.all().then(res => {
|
||||
this.sites = res
|
||||
})
|
||||
},
|
||||
getSitesGroup () {
|
||||
const arr = []
|
||||
for (const i of this.sites) {
|
||||
if (arr.indexOf(i.group) < 0) {
|
||||
arr.push(i.group)
|
||||
}
|
||||
}
|
||||
this.siteGroup = arr
|
||||
},
|
||||
addSite () {
|
||||
if (this.checkAllSitesLoading) {
|
||||
this.$message.info('正在检测, 请勿操作.')
|
||||
return false
|
||||
}
|
||||
this.getSitesGroup()
|
||||
this.dialogType = 'new'
|
||||
this.dialogVisible = true
|
||||
this.siteInfo = {
|
||||
key: '',
|
||||
name: '',
|
||||
api: '',
|
||||
download: '',
|
||||
group: '',
|
||||
isActive: true
|
||||
}
|
||||
},
|
||||
editSite (siteInfo) {
|
||||
if (this.checkAllSitesLoading) {
|
||||
this.$message.info('正在检测, 请勿操作.')
|
||||
return false
|
||||
}
|
||||
this.getSitesGroup()
|
||||
this.dialogType = 'edit'
|
||||
this.dialogVisible = true
|
||||
this.siteInfo = siteInfo
|
||||
this.editOldkey = siteInfo.key
|
||||
},
|
||||
closeDialog () {
|
||||
this.dialogVisible = false
|
||||
this.getSites()
|
||||
},
|
||||
removeEvent (e) {
|
||||
if (this.checkAllSitesLoading) {
|
||||
this.$message.info('正在检测, 请勿操作.')
|
||||
return false
|
||||
}
|
||||
sites.remove(e.id).then(res => {
|
||||
this.getSites()
|
||||
}).catch(err => {
|
||||
this.$message.warning('删除源失败, 错误信息: ' + err)
|
||||
})
|
||||
},
|
||||
checkSiteKey (e) {
|
||||
if (this.dialogType === 'edit' && this.editOldkey === this.siteInfo.key) {
|
||||
return true
|
||||
} else {
|
||||
for (const i of this.sites) {
|
||||
if (i.key === this.siteInfo.key) {
|
||||
this.$message.warning(`源站标识: ${i.key} 已存在, 请勿重复填写.`)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
},
|
||||
addOrEditSite () {
|
||||
if (!this.siteInfo.name || !this.siteInfo.api) {
|
||||
this.$message.error('名称和API接口不能为空。')
|
||||
return false
|
||||
}
|
||||
if (!this.checkSiteKey()) {
|
||||
return false
|
||||
}
|
||||
var randomstring = require('randomstring')
|
||||
var doc = {
|
||||
key: this.dialogType === 'edit' ? this.siteInfo.key : this.siteInfo.key ? this.siteInfo.key : randomstring.generate(6),
|
||||
id: this.dialogType === 'edit' ? this.siteInfo.id : this.sites.length ? this.sites[this.sites.length - 1].id + 1 : 1,
|
||||
name: this.siteInfo.name,
|
||||
api: this.siteInfo.api,
|
||||
download: this.siteInfo.download,
|
||||
group: this.siteInfo.group,
|
||||
isActive: this.siteInfo.isActive
|
||||
}
|
||||
if (this.dialogType === 'edit') sites.remove(this.siteInfo.id)
|
||||
sites.add(doc).then(res => {
|
||||
this.siteInfo = {
|
||||
key: '',
|
||||
name: '',
|
||||
api: '',
|
||||
download: '',
|
||||
group: ''
|
||||
}
|
||||
this.dialogType === 'edit' ? this.$message.success('修改成功!') : this.$message.success('新增源成功!')
|
||||
this.dialogVisible = false
|
||||
this.getSites()
|
||||
})
|
||||
this.editOldkey = ''
|
||||
},
|
||||
exportSites () {
|
||||
this.getSites()
|
||||
const arr = [...this.sites]
|
||||
const str = JSON.stringify(arr, null, 2)
|
||||
const options = {
|
||||
filters: [
|
||||
{ name: 'JSON file', extensions: ['json'] },
|
||||
{ name: 'Normal text file', extensions: ['txt'] },
|
||||
{ name: 'All types', extensions: ['*'] }
|
||||
]
|
||||
}
|
||||
remote.dialog.showSaveDialog(options).then(result => {
|
||||
if (!result.canceled) {
|
||||
fs.writeFileSync(result.filePath, str)
|
||||
this.$message.success('已保存成功')
|
||||
}
|
||||
}).catch(err => {
|
||||
this.$message.error(err)
|
||||
})
|
||||
},
|
||||
importSites () {
|
||||
if (this.checkAllSitesLoading) {
|
||||
this.$message.info('正在检测, 请勿操作.')
|
||||
return false
|
||||
}
|
||||
const options = {
|
||||
filters: [
|
||||
{ name: 'JSON file', extensions: ['json'] },
|
||||
{ name: 'Normal text file', extensions: ['txt'] },
|
||||
{ name: 'All types', extensions: ['*'] }
|
||||
],
|
||||
properties: ['openFile', 'multiSelections']
|
||||
}
|
||||
remote.dialog.showOpenDialog(options).then(result => {
|
||||
if (!result.canceled) {
|
||||
result.filePaths.forEach(file => {
|
||||
var str = fs.readFileSync(file)
|
||||
const json = JSON.parse(str)
|
||||
json.forEach(ele => {
|
||||
if (ele.api && this.sites.filter(x => x.key === ele.key).length === 0 && this.sites.filter(x => x.name === ele.name && x.api === ele.api).length === 0) {
|
||||
// 不含该key 同时也不含名字和url一样的
|
||||
if (ele.isActive === undefined) {
|
||||
ele.isActive = true
|
||||
}
|
||||
if (ele.group === undefined) {
|
||||
ele.group = '导入'
|
||||
}
|
||||
this.sites.push(ele)
|
||||
}
|
||||
})
|
||||
this.resetId(this.sites)
|
||||
sites.clear().then(sites.bulkAdd(this.sites))
|
||||
this.$message.success('导入成功')
|
||||
this.getSites()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
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.checkAllSitesLoading) {
|
||||
this.$message.info('正在检测, 请勿操作.')
|
||||
return false
|
||||
}
|
||||
this.sites.sort(function (x, y) { return x.key === i.key ? -1 : y.key === i.key ? 1 : 0 })
|
||||
this.updateDatabase()
|
||||
},
|
||||
syncTableData () {
|
||||
if (this.$refs.editSitesTable.tableData && this.$refs.editSitesTable.tableData.length === this.sites.length) {
|
||||
this.sites = this.$refs.editSitesTable.tableData
|
||||
}
|
||||
},
|
||||
isActiveChangeEvent (row) {
|
||||
sites.remove(row.id)
|
||||
sites.add(row)
|
||||
},
|
||||
resetId (inArray) {
|
||||
var id = 1
|
||||
inArray.forEach(ele => {
|
||||
ele.id = id
|
||||
id += 1
|
||||
})
|
||||
},
|
||||
updateDatabase () {
|
||||
// 因为el-table的数据是单向绑定,我们先同步el-table里的数据和其绑定的数据
|
||||
this.syncTableData()
|
||||
sites.clear().then(res => {
|
||||
var id = 1
|
||||
this.sites.forEach(ele => {
|
||||
ele.id = id
|
||||
id += 1
|
||||
})
|
||||
sites.bulkAdd(this.sites).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, {
|
||||
onEnd ({ newIndex, oldIndex }) {
|
||||
const currRow = _this.sites.splice(oldIndex, 1)[0]
|
||||
_this.sites.splice(newIndex, 0, currRow)
|
||||
_this.updateDatabase()
|
||||
}
|
||||
})
|
||||
},
|
||||
async checkAllSite () {
|
||||
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
|
||||
}
|
||||
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()
|
||||
addEventListener('keydown', code => { if (code.keyCode === 16) this.shiftDown = true })
|
||||
addEventListener('keyup', code => { if (code.keyCode === 16) this.shiftDown = false })
|
||||
},
|
||||
created () {
|
||||
this.getSites()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,49 @@
|
||||
<template>
|
||||
<div class="frame">
|
||||
<span class="min" @click="frameClickEvent('min')"></span>
|
||||
<span class="close" @click="frameClickEvent('close')"></span>
|
||||
<span class="top" @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="appState.windowIsOnTop ? '#555555' : '#ffffff'"></path></svg>
|
||||
</span>
|
||||
<span class="min" @click="frameClickEvent('min')" title="最小化">
|
||||
<svg t="1595917239849" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1155" style="width:8px;height:14px"><path d="M0 479.936C0 444.64 28.448 416 64.064 416L959.936 416C995.328 416 1024 444.736 1024 479.936L1024 544.064C1024 579.392 995.552 608 959.936 608L64.064 608C28.672 608 0 579.264 0 544.064L0 479.936Z" p-id="1156" fill="#ffffff"></path></svg>
|
||||
</span>
|
||||
<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="关闭">
|
||||
<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>
|
||||
</template>
|
||||
<script>
|
||||
const ipc = require('electron').ipcRenderer
|
||||
const { remote } = require('electron')
|
||||
export default {
|
||||
name: 'frame',
|
||||
computed: {
|
||||
appState: {
|
||||
get () {
|
||||
return this.$store.getters.getAppState
|
||||
},
|
||||
set (val) {
|
||||
this.SET_APPSTATE(val)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
frameClickEvent (e) {
|
||||
ipc.send(e)
|
||||
const win = remote.getCurrentWindow()
|
||||
if (e === 'min') {
|
||||
win.minimize()
|
||||
}
|
||||
if (e === 'max') {
|
||||
win.isMaximized() ? win.unmaximize() : win.maximize()
|
||||
}
|
||||
if (e === 'close') {
|
||||
win.destroy()
|
||||
}
|
||||
if (e === 'top') {
|
||||
this.appState.windowIsOnTop = !this.appState.windowIsOnTop
|
||||
win.setAlwaysOnTop(this.appState.windowIsOnTop)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,46 +53,20 @@ export default {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
user-select: none;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
-webkit-app-region: drag;
|
||||
span{
|
||||
-webkit-app-region: no-drag;
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
margin-left: 10px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
cursor: pointer;
|
||||
opacity: 0.5;
|
||||
&:hover{
|
||||
animation: heartbeat 3s ease-in-out infinite both;
|
||||
}
|
||||
@keyframes heartbeat {
|
||||
from {
|
||||
transform: scale(1);
|
||||
transform-origin: center center;
|
||||
animation-timing-function: ease-out;
|
||||
}
|
||||
10% {
|
||||
opacity: 1;
|
||||
transform: scale(0.91);
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
17% {
|
||||
transform: scale(0.98);
|
||||
animation-timing-function: ease-out;
|
||||
}
|
||||
33% {
|
||||
transform: scale(0.87);
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
45% {
|
||||
transform: scale(1);
|
||||
animation-timing-function: ease-out;
|
||||
}
|
||||
}
|
||||
margin-left: 10px;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
line-height: 14px;
|
||||
display: inline-block;
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
339
src/components/History.vue
Normal file
339
src/components/History.vue
Normal file
@@ -0,0 +1,339 @@
|
||||
<template>
|
||||
<div class="listpage" id="history">
|
||||
<div class="listpage-header" id="history-header">
|
||||
<el-switch v-model="viewMode" active-text="海报" active-value="picture" inactive-text="列表" inactive-value="table" @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-body">
|
||||
<div class="show-table" id="history-table" v-show="viewMode === 'table'">
|
||||
<el-table size="mini" fit height="100%" :data="history" row-key="id" @row-click="detailEvent">
|
||||
<el-table-column
|
||||
prop="name"
|
||||
label="片名">
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="site"
|
||||
width="120"
|
||||
label="片源">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ getSiteName(scope.row.site) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="index"
|
||||
width="180"
|
||||
label="观看至">
|
||||
<template slot-scope="scope">
|
||||
<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="操作"
|
||||
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="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>
|
||||
</template>
|
||||
<script>
|
||||
import { mapMutations } from 'vuex'
|
||||
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 {
|
||||
name: 'history',
|
||||
data () {
|
||||
return {
|
||||
history: [],
|
||||
sites: [],
|
||||
viewMode: setting.historyViewMode
|
||||
}
|
||||
},
|
||||
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)
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
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,
|
||||
key: e.site,
|
||||
info: {
|
||||
id: e.ids,
|
||||
name: e.name
|
||||
}
|
||||
}
|
||||
},
|
||||
async playEvent (e) {
|
||||
const db = await history.find({ site: e.site, ids: e.ids })
|
||||
if (db) {
|
||||
this.video = { key: db.site, info: { id: db.ids, name: db.name, index: db.index } }
|
||||
} 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) {
|
||||
this.share = {
|
||||
show: true,
|
||||
key: e.site,
|
||||
info: e
|
||||
}
|
||||
},
|
||||
downloadEvent (e) {
|
||||
zy.download(e.site, e.ids).then(res => {
|
||||
if (res && res.m3u8List) {
|
||||
const list = res.m3u8List.split('#')
|
||||
let downloadUrl = ''
|
||||
for (const i of list) {
|
||||
const url = encodeURI(i.split('$')[1])
|
||||
downloadUrl += (url + '\n')
|
||||
}
|
||||
clipboard.writeText(downloadUrl)
|
||||
this.$message.success('『MP4』格式的链接已复制, 快去下载吧!')
|
||||
} else {
|
||||
zy.detail(e.site, e.ids).then(res => {
|
||||
const list = [...res.m3u8List]
|
||||
let downloadUrl = ''
|
||||
for (const i of list) {
|
||||
const url = encodeURI(i.split('$')[1])
|
||||
downloadUrl += (url + '\n')
|
||||
}
|
||||
clipboard.writeText(downloadUrl)
|
||||
this.$message.success('『M3U8』格式的链接已复制, 快去下载吧!')
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
exportHistory () {
|
||||
this.getAllhistory()
|
||||
const arr = [...this.history]
|
||||
const str = JSON.stringify(arr, null, 2)
|
||||
const options = {
|
||||
filters: [
|
||||
{ name: 'JSON file', extensions: ['json'] }
|
||||
]
|
||||
}
|
||||
remote.dialog.showSaveDialog(options).then(result => {
|
||||
if (!result.canceled) {
|
||||
fs.writeFileSync(result.filePath, str)
|
||||
this.$message.success('已保存成功')
|
||||
}
|
||||
}).catch(err => {
|
||||
this.$message.error(err)
|
||||
})
|
||||
},
|
||||
importHistory () {
|
||||
const options = {
|
||||
filters: [
|
||||
{ name: 'JSON file', extensions: ['json'] }
|
||||
],
|
||||
properties: ['openFile', 'multiSelections']
|
||||
}
|
||||
remote.dialog.showOpenDialog(options).then(result => {
|
||||
if (!result.canceled) {
|
||||
result.filePaths.forEach(file => {
|
||||
var str = fs.readFileSync(file)
|
||||
const json = JSON.parse(str)
|
||||
history.bulkAdd(json).then(res => {
|
||||
this.$message.success('导入成功')
|
||||
this.getAllhistory()
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
clearAllHistory () {
|
||||
history.clear().then(res => {
|
||||
this.history = []
|
||||
})
|
||||
},
|
||||
getAllhistory () {
|
||||
history.all().then(res => {
|
||||
this.history = res.reverse()
|
||||
})
|
||||
},
|
||||
getAllsites () {
|
||||
sites.all().then(res => {
|
||||
this.sites = res
|
||||
})
|
||||
},
|
||||
getSiteName (key) {
|
||||
var site = this.sites.find(e => e.key === key)
|
||||
if (site) {
|
||||
return site.name
|
||||
}
|
||||
},
|
||||
deleteEvent (e) {
|
||||
history.remove(e.id).then(res => {
|
||||
this.getAllhistory()
|
||||
}).catch(err => {
|
||||
this.$message.warning('删除历史记录失败, 错误信息: ' + err)
|
||||
})
|
||||
},
|
||||
updateDatabase (data) {
|
||||
history.clear().then(res => {
|
||||
var id = length
|
||||
data.forEach(ele => {
|
||||
ele.id = id
|
||||
id -= 1
|
||||
history.add(ele)
|
||||
})
|
||||
})
|
||||
},
|
||||
rowDrop () {
|
||||
const tbody = document.getElementById('history-table').querySelector('.el-table__body-wrapper tbody')
|
||||
const _this = this
|
||||
Sortable.create(tbody, {
|
||||
onEnd ({ newIndex, oldIndex }) {
|
||||
const currRow = _this.history.splice(oldIndex, 1)[0]
|
||||
_this.history.splice(newIndex, 0, currRow)
|
||||
_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>
|
||||
637
src/components/IPTV.vue
Normal file
637
src/components/IPTV.vue
Normal file
@@ -0,0 +1,637 @@
|
||||
<template>
|
||||
<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="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" id="iptv-header" v-show="enableBatchEdit">
|
||||
<el-switch v-model="enableBatchEdit" active-text="批处理及频道调整"></el-switch>
|
||||
<el-input placeholder="新组名/新频道名" v-model="inputContent"></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 type="primary" icon="el-icon-film" @click.stop="mergeChannel">{{ this.multipleSelection.length === 1 ? '频道重命名' : '频道合并' }}</el-button>
|
||||
<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"
|
||||
lazy
|
||||
:load="(row, treeNode, resolve) => resolve(row.channels)"
|
||||
:tree-props="{hasChildren: 'hasChildren'}"
|
||||
@expand-change="expandChange"
|
||||
@select="selectionCellClick"
|
||||
@selection-change="handleSelectionChange"
|
||||
@sort-change="handleSortChange">
|
||||
<el-table-column
|
||||
type="selection"
|
||||
v-if="enableBatchEdit">
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
default-sort="ascending"
|
||||
prop="name"
|
||||
:class-name="enableBatchEdit ? 'disableExpand' : ''"
|
||||
label="频道名">
|
||||
<template #header>
|
||||
<el-input
|
||||
placeholder="搜索"
|
||||
size="mini"
|
||||
v-model.trim="searchTxt">
|
||||
<i slot="prefix" class="el-input__icon el-icon-search"></i>
|
||||
</el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
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="(a , b) => sortByLocaleCompare(a.group, b.group)"
|
||||
prop="group"
|
||||
label="分组"
|
||||
:filters="getFilters"
|
||||
: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="操作"
|
||||
align="right"
|
||||
:width="200">
|
||||
<template #header>
|
||||
<span>{{ enableBatchEdit ? `频道总数:${channelList.length}` : `资源总数:${iptvList.length}` }}</span>
|
||||
</template>
|
||||
<template slot-scope="scope">
|
||||
<el-button @click.stop="moveToTopEvent(scope.row)" type="text" v-if="scope.row.channels">置顶</el-button>
|
||||
<el-button @click.stop="playEvent(scope.row)" type="text">播放</el-button>
|
||||
<!-- 检测时先强制批量检测一遍,如果不强制直接单个检测时第一次不会显示“检测中”-->
|
||||
<el-button size="mini" v-if="iptvList.every(channel => channel.status)" v-show="!checkAllChannelsLoading" @click.stop="checkChannel(scope.row)" type="text">检测</el-button>
|
||||
<el-button @click.stop="removeEvent(scope.row)" type="text">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapMutations } from 'vuex'
|
||||
import { iptv, channelList } from '../lib/dexie'
|
||||
import { iptv as defaultChannels } from '../lib/dexie/initData'
|
||||
import zy from '../lib/site/tools'
|
||||
import { remote } from 'electron'
|
||||
import fs from 'fs'
|
||||
import Sortable from 'sortablejs'
|
||||
export default {
|
||||
name: 'iptv',
|
||||
data () {
|
||||
return {
|
||||
iptvList: [],
|
||||
channelList: [],
|
||||
searchTxt: '',
|
||||
enableBatchEdit: false,
|
||||
inputContent: '',
|
||||
batchIsActive: true,
|
||||
shiftDown: false,
|
||||
selectionBegin: '',
|
||||
selectionEnd: '',
|
||||
multipleSelection: [],
|
||||
expandedRows: [],
|
||||
checkAllChannelsLoading: false,
|
||||
checkProgress: 0,
|
||||
stopFlag: false,
|
||||
sortableTable: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
view: {
|
||||
get () {
|
||||
return this.$store.getters.getView
|
||||
},
|
||||
set (val) {
|
||||
this.SET_VIEW(val)
|
||||
}
|
||||
},
|
||||
setting () {
|
||||
return this.$store.getters.getSetting
|
||||
},
|
||||
video: {
|
||||
get () {
|
||||
return this.$store.getters.getVideo
|
||||
},
|
||||
set (val) {
|
||||
this.SET_VIDEO(val)
|
||||
}
|
||||
},
|
||||
filteredTableData () {
|
||||
if (this.searchTxt) {
|
||||
return this.channelList.filter(x => x.name.toLowerCase().includes(this.searchTxt.toLowerCase()))
|
||||
} else {
|
||||
return this.channelList
|
||||
}
|
||||
},
|
||||
getFilters () {
|
||||
const groups = [...new Set(this.channelList.map(iptv => iptv.group))]
|
||||
var filters = []
|
||||
groups.forEach(g => {
|
||||
var doc = {
|
||||
text: g,
|
||||
value: g
|
||||
}
|
||||
filters.push(doc)
|
||||
})
|
||||
return filters
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
view () {
|
||||
if (this.view === 'IPTV' && !this.checkAllChannelsLoading) {
|
||||
this.getChannelList()
|
||||
}
|
||||
},
|
||||
enableBatchEdit () {
|
||||
if (this.checkAllChannelsLoading) {
|
||||
this.$message.info('正在检测, 请勿操作.')
|
||||
this.enableBatchEdit = false
|
||||
return
|
||||
}
|
||||
if (this.enableBatchEdit) {
|
||||
this.$nextTick(() => {
|
||||
this.expandedRows.forEach(e => this.$refs.iptvTable.toggleRowExpansion(e, false))
|
||||
})
|
||||
this.rowDrop()
|
||||
} else {
|
||||
this.sortableTable.destroy()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SET_VIEW', 'SET_DETAIL', 'SET_VIDEO', 'SET_SHARE']),
|
||||
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 = this.channelList.findIndex(e => e.id === Math.min(this.selectionBegin, this.selectionEnd))
|
||||
const end = this.channelList.findIndex(e => e.id === Math.max(this.selectionBegin, this.selectionEnd))
|
||||
const selections = this.channelList.slice(start, end + 1) // 多选时强制不让展开
|
||||
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 = ''
|
||||
}
|
||||
},
|
||||
expandChange (row, expanded) {
|
||||
const index = this.expandedRows.indexOf(row)
|
||||
if (expanded && index === -1) {
|
||||
this.expandedRows.push(row)
|
||||
} else if (!expanded && index !== -1) {
|
||||
this.expandedRows.splice(index, 1)
|
||||
}
|
||||
},
|
||||
handleSelectionChange (rows) {
|
||||
this.multipleSelection = rows
|
||||
},
|
||||
handleSortChange (column, prop, order) {
|
||||
if (this.checkAllChannelsLoading) {
|
||||
this.$message.info('正在检测, 请勿操作.')
|
||||
return
|
||||
}
|
||||
this.updateDatabase()
|
||||
},
|
||||
saveBatchEdit () {
|
||||
this.multipleSelection.forEach(ele => {
|
||||
if (this.inputContent) {
|
||||
ele.group = this.inputContent
|
||||
}
|
||||
ele.isActive = this.batchIsActive
|
||||
})
|
||||
this.updateDatabase()
|
||||
},
|
||||
mergeChannel () {
|
||||
if (this.inputContent && this.multipleSelection.length) {
|
||||
var channels = []
|
||||
const id = this.multipleSelection[0].id
|
||||
this.multipleSelection.forEach(ele => {
|
||||
channels = channels.concat(ele.channels)
|
||||
channels.forEach(e => { e.channelID = id })
|
||||
channelList.remove(ele.id)
|
||||
})
|
||||
const mergeChannel = { id: id, name: this.inputContent, isActive: channels.some(c => c.isActive), group: this.determineGroup(this.inputContent), hasChildren: channels.length > 1, channels: channels }
|
||||
channelList.add(mergeChannel)
|
||||
this.getChannelList()
|
||||
this.updateDatabase()
|
||||
}
|
||||
},
|
||||
playEvent (e) {
|
||||
if (e.url) {
|
||||
this.video = { iptv: e }
|
||||
} else {
|
||||
const prefer = e.prefer ? e.channels.find(c => c.id === e.prefer) : e.channels.filter(c => c.isActive)[0]
|
||||
if (!prefer) return
|
||||
this.video = { iptv: prefer }
|
||||
}
|
||||
this.view = 'Play'
|
||||
},
|
||||
containsearchTxt (i) {
|
||||
if (this.searchTxt) {
|
||||
return i.name.toLowerCase().includes(this.searchTxt.toLowerCase())
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
},
|
||||
removeEvent (row) {
|
||||
if (this.checkAllChannelsLoading) {
|
||||
this.$message.info('正在检测, 请勿操作.')
|
||||
return false
|
||||
}
|
||||
try {
|
||||
if (row.url) { // tree树形控件节点一旦展开,就不再重新加载节点数据
|
||||
const ele = this.channelList.find(e => e.id === row.channelID)
|
||||
ele.channels.splice(ele.channels.findIndex(e => e.id === row.id), 1)
|
||||
channelList.remove(row.channelID)
|
||||
if (ele.channels.length) {
|
||||
if (ele.channels.length === 1) ele.hasChildren = false
|
||||
channelList.add(ele)
|
||||
this.$set(this.$refs.iptvTable.store.states.lazyTreeNodeMap, ele.id, ele.channels)
|
||||
}
|
||||
} else {
|
||||
channelList.remove(row.id)
|
||||
}
|
||||
this.getChannelList()
|
||||
} catch (err) {
|
||||
this.$message.warning('删除频道失败, 错误信息: ' + err)
|
||||
}
|
||||
},
|
||||
exportChannels () { // 导出导入m3u为iptvList,json为channelList
|
||||
const options = {
|
||||
filters: [
|
||||
{ name: 'm3u file', extensions: ['m3u'] },
|
||||
{ name: 'JSON file', extensions: ['json'] }
|
||||
]
|
||||
}
|
||||
remote.dialog.showSaveDialog(options).then(result => {
|
||||
if (!result.canceled) {
|
||||
if (result.filePath.endsWith('m3u')) {
|
||||
var writer = require('m3u').extendedWriter()
|
||||
this.iptvList.forEach(e => {
|
||||
writer.file(e.url, -1, e.name)
|
||||
})
|
||||
fs.writeFileSync(result.filePath, writer.toString())
|
||||
this.$message.success('已保存成功')
|
||||
} else {
|
||||
const arr = [...this.channelList] // 要保存channelList必须选json
|
||||
const str = JSON.stringify(arr, null, 2)
|
||||
fs.writeFileSync(result.filePath, str)
|
||||
this.$message.success('已保存成功')
|
||||
}
|
||||
}
|
||||
}).catch(err => {
|
||||
this.$message.error(err)
|
||||
})
|
||||
},
|
||||
importChannels () {
|
||||
if (this.checkAllChannelsLoading) {
|
||||
this.$message.info('正在检测, 请勿操作.')
|
||||
return false
|
||||
}
|
||||
const options = {
|
||||
filters: [
|
||||
{ name: 'm3u file', extensions: ['m3u', 'm3u8'] },
|
||||
{ name: 'JSON file', extensions: ['json'] }
|
||||
],
|
||||
properties: ['openFile', 'multiSelections']
|
||||
}
|
||||
remote.dialog.showOpenDialog(options).then(result => {
|
||||
if (!result.canceled) {
|
||||
result.filePaths.forEach(file => {
|
||||
if (file.endsWith('m3u') || file.endsWith('m3u8')) {
|
||||
const docs = []
|
||||
const URL = require('url')
|
||||
let id = this.channelList.length ? this.channelList.slice(-1)[0].id + 1 : 1
|
||||
const parser = require('iptv-playlist-parser')
|
||||
const playlist = fs.readFileSync(file, { encoding: 'utf-8' })
|
||||
const result = parser.parse(playlist)
|
||||
result.items.forEach(ele => {
|
||||
const urls = ele.url.split('#').filter(e => e.startsWith('http')) // 网址带#时自动分割
|
||||
urls.forEach(url => {
|
||||
if (ele.name && url && new URL.URL(url).pathname.endsWith('.m3u8')) { // 网址可能带参数
|
||||
var doc = {
|
||||
id: id,
|
||||
name: ele.name,
|
||||
url: url,
|
||||
isActive: true
|
||||
}
|
||||
id += 1
|
||||
docs.push(doc)
|
||||
}
|
||||
})
|
||||
})
|
||||
// 获取url不重复的列表
|
||||
const uniqueList = [...new Map(docs.map(item => [item.url, item])).values()]
|
||||
iptv.clear().then(res => {
|
||||
iptv.bulkAdd(uniqueList).then(e => { // 支持导入同名频道,群里反馈
|
||||
this.updateChannelList()
|
||||
})
|
||||
})
|
||||
} else {
|
||||
// Import Json file
|
||||
const importedList = JSON.parse(fs.readFileSync(file))
|
||||
importedList.forEach(ele => {
|
||||
const commonEle = this.channelList.find(e => e.name === ele.name)
|
||||
if (commonEle) {
|
||||
const urls = commonEle.channels.map(c => c.url)
|
||||
const channels = ele.channels.filter(e => !urls.includes(e.url))
|
||||
commonEle.channels = commonEle.channels.concat(channels)
|
||||
} else {
|
||||
ele.id = this.channelList.length ? this.channelList.slice(-1)[0].id + 1 : 1
|
||||
this.channelList.push(ele)
|
||||
}
|
||||
})
|
||||
this.updateDatabase()
|
||||
}
|
||||
})
|
||||
this.$message.success('导入成功')
|
||||
}
|
||||
})
|
||||
},
|
||||
determineGroup (name) {
|
||||
if (name.toLowerCase().includes('cctv') && (name.includes('蓝光') || name.includes('高清'))) {
|
||||
return '央视高清'
|
||||
} else if (name.toLowerCase().includes('cctv')) {
|
||||
return '央视'
|
||||
} else if (name.includes('卫视')) {
|
||||
return '卫视'
|
||||
} else if (name.includes('香港') || name.includes('澳门') || name.includes('台湾') || name.includes('凤凰')) {
|
||||
return '港澳台'
|
||||
} else if (name.includes('高清') || name.includes('蓝光') || name.includes('1080P')) {
|
||||
return '高清'
|
||||
} else {
|
||||
return '其他'
|
||||
}
|
||||
},
|
||||
resetChannelsEvent () {
|
||||
this.stopFlag = true
|
||||
if (this.checkAllChannelsLoading) {
|
||||
this.$message.info('部分检测还未完全终止, 请稍等...')
|
||||
return
|
||||
}
|
||||
this.channelList = []
|
||||
this.iptvList = []
|
||||
iptv.clear().then(iptv.bulkAdd(defaultChannels).then(this.updateChannelList()))
|
||||
},
|
||||
removeSelectedChannels () {
|
||||
this.multipleSelection.forEach(e => channelList.remove(e.id))
|
||||
this.$refs.iptvTable.clearFilter()
|
||||
this.getChannelList()
|
||||
this.updateDatabase()
|
||||
this.enableBatchEdit = false
|
||||
},
|
||||
updateChannelList () {
|
||||
iptv.all().then(res => {
|
||||
res = res.filter(o => !this.iptvList.find(e => o.url === e.url))
|
||||
const resClone = JSON.parse(JSON.stringify(res))
|
||||
const uniqueChannelName = {}
|
||||
for (var i = 0; i < resClone.length; i++) {
|
||||
var channelName = resClone[i].name.trim().replace(/[- ]?(1080p|蓝光|超清|高清|标清|hd|cq|4k)(\d{1,2})?$/i, '')
|
||||
if (channelName.match(/cctv/i)) channelName = channelName.replace('-', '')
|
||||
if (Object.keys(uniqueChannelName).some(name => channelName.match(new RegExp(`${name}(1080p|4k|(?!\\d))`, 'i')))) continue // 避免重复
|
||||
const matchRule = new RegExp(`${channelName}(1080p|4k|(?!\\d))`, 'i')
|
||||
for (var j = i; j < resClone.length; j++) {
|
||||
if (resClone[j].name.match(/cctv/i)) {
|
||||
resClone[j].name = resClone[j].name.replace('-', '')
|
||||
}
|
||||
if (matchRule.test(resClone[j].name)) {
|
||||
if (uniqueChannelName[channelName]) {
|
||||
!uniqueChannelName[channelName].includes(res[j]) && uniqueChannelName[channelName].push(res[j])
|
||||
} else {
|
||||
uniqueChannelName[channelName] = [res[j]]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
res.forEach(ele => {
|
||||
if (ele.isActive === undefined) {
|
||||
ele.isActive = true
|
||||
}
|
||||
})
|
||||
Object.keys(uniqueChannelName).forEach(k => {
|
||||
const ele = this.channelList.find(e => e.name === k)
|
||||
if (ele) {
|
||||
ele.channels = ele.channels.concat(uniqueChannelName[k])
|
||||
delete uniqueChannelName[k]
|
||||
}
|
||||
})
|
||||
if (Object.keys(uniqueChannelName).length) {
|
||||
let id = this.channelList.length ? this.channelList.slice(-1)[0].id + 1 : 1
|
||||
const channelList = Object.keys(uniqueChannelName).map(e => { return { id: id++, name: e, isActive: uniqueChannelName[e].some(c => c.isActive), group: this.determineGroup(e), hasChildren: uniqueChannelName[e].length > 1, channels: uniqueChannelName[e] } })
|
||||
this.channelList = this.channelList.concat(channelList)
|
||||
}
|
||||
this.updateDatabase()
|
||||
iptv.clear() // iptv默认清空状态
|
||||
})
|
||||
},
|
||||
async getChannelList () {
|
||||
await channelList.all().then(res => {
|
||||
this.channelList = res
|
||||
this.getIptvList()
|
||||
})
|
||||
},
|
||||
getIptvList () {
|
||||
this.iptvList = this.channelList.reduce((result, item) => { item.channels.forEach(e => { e.channelID = item.id }); return result.concat(item.channels) }, [])
|
||||
},
|
||||
moveToTopEvent (row) {
|
||||
if (this.checkAllChannelsLoading) {
|
||||
this.$message.info('正在检测, 请勿操作.')
|
||||
return false
|
||||
}
|
||||
// this.channelList.sort(function (x, y) { return (x.name === i.name && x.url === i.url) ? -1 : (y.name === i.name && y.url === i.url) ? 1 : 0 })
|
||||
if (row.channels) {
|
||||
this.channelList.splice(this.channelList.findIndex(e => e.id === row.id), 1)
|
||||
this.channelList.unshift(row)
|
||||
this.updateDatabase()
|
||||
}
|
||||
},
|
||||
syncTableData () {
|
||||
if (this.$refs.iptvTable.tableData && this.$refs.iptvTable.tableData.length === this.channelList.length) {
|
||||
this.channelList = this.$refs.iptvTable.tableData
|
||||
}
|
||||
},
|
||||
updateDatabase () {
|
||||
this.syncTableData()
|
||||
Object.values(this.$refs.iptvTable.store.states.treeData).forEach(e => { e.loaded = false })
|
||||
channelList.clear().then(res => {
|
||||
this.resetId(this.channelList)
|
||||
channelList.bulkAdd(this.channelList)
|
||||
this.getChannelList()
|
||||
})
|
||||
},
|
||||
resetId (channelList) {
|
||||
var id = 1
|
||||
channelList.forEach(ele => {
|
||||
ele.id = id
|
||||
id += 1
|
||||
ele.channels.forEach(e => {
|
||||
e.channelID = ele.id
|
||||
const embedChannelID = ele.id + '_'
|
||||
const prefer = ele.prefer ? ele.channels.find(e => e.id === ele.prefer) : ''
|
||||
ele.channels.forEach((e, index) => { e.id = embedChannelID + index }) // 为避免混杂,给内置iptv重起id
|
||||
if (prefer) ele.prefer = prefer.id
|
||||
})
|
||||
if (ele.channels.length === 1) {
|
||||
ele.hasChildren = false
|
||||
} else {
|
||||
ele.hasChildren = true
|
||||
}
|
||||
})
|
||||
},
|
||||
rowDrop () {
|
||||
if (this.checkAllChannelsLoading) {
|
||||
this.$message.info('正在检测, 请勿操作.')
|
||||
return false
|
||||
}
|
||||
const tbody = document.getElementById('iptv-table').querySelector('.el-table__body-wrapper tbody')
|
||||
const _this = this
|
||||
this.sortableTable = new Sortable(tbody, {
|
||||
filter: '.el-table__row--level-1', // 禁止children拖动
|
||||
onEnd ({ newIndex, oldIndex }) {
|
||||
const currRow = _this.channelList.splice(oldIndex, 1)[0]
|
||||
_this.channelList.splice(newIndex, 0, currRow)
|
||||
_this.updateDatabase()
|
||||
}
|
||||
})
|
||||
},
|
||||
isActiveChangeEvent (row) {
|
||||
if (row.url) {
|
||||
const ele = this.channelList.find(e => e.id === row.channelID)
|
||||
ele.isActive = ele.channels.some(e => e.isActive)
|
||||
channelList.remove(row.channelID)
|
||||
channelList.add(ele)
|
||||
} else {
|
||||
if (row.channels.length === 1) row.channels[0].isActive = row.isActive
|
||||
channelList.remove(row.id)
|
||||
channelList.add(row)
|
||||
}
|
||||
},
|
||||
async checkAllChannels () {
|
||||
this.checkAllChannelsLoading = true
|
||||
this.stopFlag = false
|
||||
this.checkProgress = 0
|
||||
this.channelList.filter(e => e.channels.length).forEach(e => { e.status = ' '; e.hasCheckedNum = 0 })
|
||||
const uncheckedList = this.iptvList.filter(e => e.status === undefined || e.status === ' ') // 未检测过的优先
|
||||
const other = this.iptvList.filter(e => !uncheckedList.includes(e))
|
||||
await this.checkChannelsBySite(uncheckedList)
|
||||
await this.checkChannelsBySite(other).then(res => {
|
||||
this.checkAllChannelsLoading = false
|
||||
this.getChannelList()
|
||||
})
|
||||
},
|
||||
async checkChannelsBySite (channels) {
|
||||
var siteList = {}
|
||||
channels.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 (channel) {
|
||||
if (this.setting.allowPassWhenIptvCheck && !channel.isActive) {
|
||||
this.checkProgress += 1
|
||||
return
|
||||
}
|
||||
channel.status = ' '
|
||||
const ele = this.channelList.find(e => e.id === channel.channelID)
|
||||
if (this.stopFlag) {
|
||||
this.checkProgress += 1
|
||||
return channel.status
|
||||
}
|
||||
const flag = await zy.checkChannel(channel.url)
|
||||
this.checkProgress += 1
|
||||
ele.hasCheckedNum++
|
||||
if (flag) {
|
||||
channel.status = '可用'
|
||||
} else {
|
||||
channel.status = '失效'
|
||||
channel.isActive = false
|
||||
if (this.setting.autocleanWhenIptvCheck) {
|
||||
ele.channels.splice(ele.channels.findIndex(e => e.id === channel.id), 1)
|
||||
ele.hasCheckedNum--
|
||||
}
|
||||
}
|
||||
if (ele.hasCheckedNum === ele.channels.length) {
|
||||
ele.status = ele.channels.some(channel => channel.status === '可用') ? '可用' : '失效'
|
||||
if (ele.status === '失效') ele.isActive = false
|
||||
channelList.remove(channel.channelID)
|
||||
if (ele.channels.length === 1) ele.hasChildren = false
|
||||
if (ele.channels.length) channelList.add(ele)
|
||||
}
|
||||
return channel.status
|
||||
},
|
||||
async checkChannel (row) {
|
||||
if (row.channels) {
|
||||
row.status = ' '
|
||||
row.hasCheckedNum = 0
|
||||
row.channels.forEach(e => this.checkSingleChannel(e))
|
||||
} else {
|
||||
this.checkSingleChannel(row)
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
addEventListener('keydown', code => { if (code.keyCode === 16) this.shiftDown = true })
|
||||
addEventListener('keyup', code => { if (code.keyCode === 16) this.shiftDown = false })
|
||||
},
|
||||
async created () {
|
||||
await this.getChannelList()
|
||||
if (!this.channelList.length) this.resetChannelsEvent()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
File diff suppressed because it is too large
Load Diff
348
src/components/Recommendation.vue
Normal file
348
src/components/Recommendation.vue
Normal file
@@ -0,0 +1,348 @@
|
||||
<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="table" @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 === 'table'">
|
||||
<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/cuiocean/ZY-Player-Resources/main/Recommendations/Recommendations.json'
|
||||
this.loading = true
|
||||
const axios = require('axios')
|
||||
axios.get(url).then(res => {
|
||||
if (res.status === 200) {
|
||||
if (res.data.length > 0) {
|
||||
this.recommendations = res.data
|
||||
recommendation.clear().then(recommendation.bulkAdd(this.recommendations))
|
||||
this.getFilterData()
|
||||
this.$message.success('更新推荐成功. 仅根据作者cuiocean个人喜好推荐,不喜请无视.')
|
||||
}
|
||||
}
|
||||
this.loading = false
|
||||
}).catch(error => {
|
||||
this.loading = false
|
||||
this.$message.error('更新推荐失败. ' + error)
|
||||
this.$message.warning('最新的推荐数据保存在Github上,请考虑使用代理或者等待下一版本内置数据更新.')
|
||||
})
|
||||
},
|
||||
async playEvent (e) {
|
||||
const db = await history.find({ site: e.key, ids: e.ids })
|
||||
if (db) {
|
||||
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('删除失败')
|
||||
}
|
||||
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) {
|
||||
const text = res.m3u8List
|
||||
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 {
|
||||
zy.detail(e.key, e.ids).then(res => {
|
||||
const list = [...res.m3u8List]
|
||||
let downloadUrl = ''
|
||||
for (const i of list) {
|
||||
const url = encodeURI(i.split('$')[1])
|
||||
downloadUrl += (url + '\n')
|
||||
}
|
||||
clipboard.writeText(downloadUrl)
|
||||
this.$message.success('『M3U8』格式的链接已复制, 快去下载吧!')
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
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>
|
||||
@@ -1,31 +1,119 @@
|
||||
<template>
|
||||
<div class="setting">
|
||||
<div class="setting-box zy-scroll" v-if="show.setting">
|
||||
<div class="logo"><img src="@/assets/image/logo.png"></div>
|
||||
<div class="setting-box zy-scroll">
|
||||
<div class="logo"><img src="@/assets/image/logo.png" alt=""></div>
|
||||
<div class="info">
|
||||
<a @click="linkOpen('https://github.com/Hunlongyu/ZY-Player')">{{$t('website')}}</a>
|
||||
<a @click="linkOpen('https://github.com/Hunlongyu/ZY-Player/issues')">v{{pkg.version}} {{$t('issues')}}</a>
|
||||
<a @click="linkOpen('http://zyplayer.fun/')">官网</a>
|
||||
<a @click="linkOpen('https://github.com/Hunlongyu/ZY-Player')">Github</a>
|
||||
<a @click="linkOpen('https://github.com/Hunlongyu/ZY-Player/issues')">当前版本v{{pkg.version}} 反馈</a>
|
||||
<a style="color:#38dd77" @click="quitAndInstall()" v-show="latestVersion !== pkg.version" >最新版本v{{latestVersion}}</a>
|
||||
</div>
|
||||
<div class="change">
|
||||
<div class="zy-select" @mouseleave="show.language = false">
|
||||
<div class="vs-placeholder" @click="show.language = true">{{$t('language')}}</div>
|
||||
<div class="vs-options" v-show="show.language">
|
||||
<ul>
|
||||
<li :class="s.language === i.key ? 'active' : ''" v-for="(i, j) in languages" :key="j" @click="languageClick(i.key)">{{ i.name }}</li>
|
||||
</ul>
|
||||
<div class="view">
|
||||
<div class="title">视图</div>
|
||||
<div class="view-box">
|
||||
<div class="zy-select" @mouseleave="show.view = false">
|
||||
<div class="vs-placeholder" @click="show.view = true">默认视图</div>
|
||||
<div class="vs-options" v-show="show.view">
|
||||
<ul class="zy-scroll">
|
||||
<li :class="d.view === 'picture' ? 'active' : ''" @click="changeView('picture')">海报</li>
|
||||
<li :class="d.view === 'table' ? 'active' : ''" @click="changeView('table')">列表</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="zy-select" @mouseleave="show.site = false">
|
||||
<div class="vs-placeholder" @click="show.site = true">{{$t('default_site')}}</div>
|
||||
<div class="vs-options" v-show="show.site">
|
||||
<ul>
|
||||
<li :class="s.site === i.key ? 'active' : ''" v-for="(i, j) in sites" :key="j" @click="siteClick(i.key)">{{ i.name }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="shortcut">
|
||||
<div class="title">快捷键</div>
|
||||
<div class="shortcut-box">
|
||||
<div class="zy-select" @mouseleave="show.shortcut = false">
|
||||
<div class="vs-placeholder" @click="show.shortcut = true">快捷键</div>
|
||||
<div class="vs-options" v-show="show.shortcut">
|
||||
<ul class="zy-scroll">
|
||||
<li :class="d.shortcut === true ? 'active' : ''" @click="changeShortcut(true)">开启</li>
|
||||
<li :class="d.shortcut === false ? 'active' : ''" @click="changeShortcut(false)">关闭</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="zy-select">
|
||||
<div class="vs-placeholder vs-noAfter" @click="expShortcut">导出</div>
|
||||
</div>
|
||||
<div class="zy-select">
|
||||
<div class="vs-placeholder vs-noAfter" @click="impShortcut">导入</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="shortcut">
|
||||
<div class="title">缓存</div>
|
||||
<div class="shortcut-box">
|
||||
<div class="zy-select">
|
||||
<div class="vs-placeholder vs-noAfter" @click="clearCache">清理视频缓存</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="site">
|
||||
<div class="title">定位时间设置</div>
|
||||
<div class="zy-input">
|
||||
左/右方向键:<input style="width:50px" type="number" v-model = "d.forwardTimeInSec" @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 = "show.editPlayerPath = true">
|
||||
<div class="vs-placeholder vs-noAfter" v-show = "show.editPlayerPath == false">
|
||||
<label>编辑</label>
|
||||
</div>
|
||||
<input class="zy-input" v-show = "show.editPlayerPath == true" v-model = "d.externalPlayer"
|
||||
@blur= "updateSettingEvent"
|
||||
@keyup.enter = "updateSettingEvent">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="site">
|
||||
<div class="title">直播源管理</div>
|
||||
<div class="site-box">
|
||||
<div class="zy-select">
|
||||
<div class="vs-placeholder vs-noAfter" @click="view = 'IPTV'">编辑直播源</div>
|
||||
</div>
|
||||
<div class="zy-input">
|
||||
<input type="checkbox" v-model = "d.allowPassWhenIptvCheck" @change="updateSettingEvent"> 检测时自动跳过停用源
|
||||
</div>
|
||||
<div class="zy-input">
|
||||
<input type="checkbox" v-model = "d.autocleanWhenIptvCheck" @change="updateSettingEvent"> 检测时自动清理无效源
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="site">
|
||||
<div class="title">源管理</div>
|
||||
<div class="site-box">
|
||||
<div class="zy-select">
|
||||
<div class="vs-placeholder vs-noAfter" @click="editSitesEvent">编辑源</div>
|
||||
</div>
|
||||
<div class="zy-input" @click="toggleExcludeRootClasses">
|
||||
<input type="checkbox" v-model = "d.excludeRootClasses" @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">
|
||||
<div class="title">{{$t('theme')}}</div>
|
||||
<div class="title">主题</div>
|
||||
<div class="theme-box">
|
||||
<div @click="changeTheme('light')" class="theme-item light">
|
||||
<div class="theme-image">
|
||||
@@ -54,121 +142,364 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="qrcode">
|
||||
<div class="title">{{$t('donate')}}</div>
|
||||
<div class="title">请作者吃辣条</div>
|
||||
<div class="qrcode-box">
|
||||
<img class="qrcode-item" src="../assets/image/alipay.png">
|
||||
<img class="qrcode-item" src="../assets/image/wepay.jpg">
|
||||
<img class="qrcode-item" src="../assets/image/wepay-hunlongyu.png">
|
||||
<img class="qrcode-item" src="../assets/image/wepay_cuiocean.jpg">
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearDB">
|
||||
<span @click="clearDBEvent" class="clearBtn">{{$t('clearDB')}}</span>
|
||||
<span class="clearTips">{{$t('clearTips')}}</span>
|
||||
<span @click="clearDBEvent" class="clearBtn">软件重置</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>
|
||||
import { mapMutations } from 'vuex'
|
||||
import setting from '../lib/dexie/setting'
|
||||
import { sites } from '../lib/site/sites'
|
||||
import db from '../lib/dexie/index'
|
||||
import '../lib/cloud/index.js'
|
||||
import { shell } from 'electron'
|
||||
import pkg from '../../package.json'
|
||||
const ipc = require('electron').ipcRenderer
|
||||
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,
|
||||
s: {},
|
||||
languages: [
|
||||
{
|
||||
key: 'zhCn',
|
||||
name: '中文'
|
||||
},
|
||||
{
|
||||
key: 'en',
|
||||
name: 'English'
|
||||
}
|
||||
],
|
||||
sites: sites,
|
||||
shortcutList: [],
|
||||
show: {
|
||||
setting: false,
|
||||
language: false,
|
||||
site: false
|
||||
site: false,
|
||||
shortcut: false,
|
||||
view: false,
|
||||
editPlayerPath: false,
|
||||
checkPasswordDialog: false,
|
||||
changePasswordDialog: false,
|
||||
proxy: false,
|
||||
proxyDialog: false
|
||||
},
|
||||
d: { },
|
||||
latestVersion: pkg.version,
|
||||
inputPassword: '',
|
||||
action: '',
|
||||
proxy: {
|
||||
type: '',
|
||||
scheme: '',
|
||||
url: '',
|
||||
port: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
theme: {
|
||||
view: {
|
||||
get () {
|
||||
return this.$store.getters.getTheme
|
||||
return this.$store.getters.getView
|
||||
},
|
||||
set (val) {
|
||||
this.SET_THEME(val)
|
||||
this.SET_VIEW(val)
|
||||
}
|
||||
},
|
||||
language: {
|
||||
setting: {
|
||||
get () {
|
||||
return this.$store.getters.getLanguage
|
||||
return this.$store.getters.getSetting
|
||||
},
|
||||
set (val) {
|
||||
this.SET_LANGUAGE(val)
|
||||
}
|
||||
},
|
||||
site: {
|
||||
get () {
|
||||
return this.$store.getters.getSite
|
||||
},
|
||||
set (val) {
|
||||
this.SET_SITE(val)
|
||||
this.SET_SETTING(val)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SET_THEME', 'SET_LANGUAGE', 'SET_SITE']),
|
||||
...mapMutations(['SET_SETTING', 'SET_VIEW']),
|
||||
linkOpen (e) {
|
||||
shell.openExternal(e)
|
||||
},
|
||||
languageClick (e) {
|
||||
this.language = e
|
||||
this.show.language = false
|
||||
this.$i18n.locale = e
|
||||
this.s.language = e
|
||||
setting.update(this.s).then(res => {
|
||||
this.$m.success(this.$t('set_success'))
|
||||
getSetting () {
|
||||
setting.find().then(res => {
|
||||
this.d = res
|
||||
this.setting = this.d
|
||||
})
|
||||
},
|
||||
siteClick (e) {
|
||||
this.site = e
|
||||
this.show.site = false
|
||||
this.s.site = e
|
||||
setting.update(this.s).then(res => {
|
||||
this.$m.success(this.$t('set_success'))
|
||||
getSites () {
|
||||
sites.all().then(res => {
|
||||
if (res.length <= 0) {
|
||||
this.$message.warning('检测到视频源未能正常加载, 即将重置源.')
|
||||
sites.clear().then(sites.bulkAdd(defaultSites).then(this.getSites()))
|
||||
}
|
||||
})
|
||||
},
|
||||
getShortcut () {
|
||||
shortcut.all().then(res => {
|
||||
this.shortcutList = res
|
||||
})
|
||||
},
|
||||
changeView (e) {
|
||||
this.d.view = e
|
||||
this.updateSettingEvent()
|
||||
this.show.view = false
|
||||
},
|
||||
async clearCache () {
|
||||
const win = remote.getCurrentWindow()
|
||||
const ses = win.webContents.session
|
||||
const size = await ses.getCacheSize() / 1024 / 1024
|
||||
const mb = size.toFixed(2)
|
||||
await ses.clearCache()
|
||||
this.$message.success(`清除缓存成功, 共清理 ${mb} MB`)
|
||||
},
|
||||
updateSettingEvent () {
|
||||
this.show.editPlayerPath = false
|
||||
this.setting = this.d
|
||||
setting.update(this.d)
|
||||
},
|
||||
toggleExcludeR18Films () {
|
||||
this.d.excludeR18Films = !this.d.excludeR18Films
|
||||
this.updateSettingEvent()
|
||||
},
|
||||
toggleExcludeRootClasses () {
|
||||
this.d.excludeRootClasses = !this.d.excludeRootClasses
|
||||
this.updateSettingEvent()
|
||||
},
|
||||
selectLocalPlayer () {
|
||||
const options = {
|
||||
filters: [
|
||||
{ name: 'Executable file', extensions: ['exe'] },
|
||||
{ name: 'All types', extensions: ['*'] }
|
||||
],
|
||||
properties: ['openFile']
|
||||
}
|
||||
remote.dialog.showOpenDialog(options).then(result => {
|
||||
if (!result.canceled) {
|
||||
var playerPath = result.filePaths[0].replace(/\\/g, '/')
|
||||
this.$message.success('设定第三方播放器路径为:' + result.filePaths[0])
|
||||
this.d.externalPlayer = playerPath
|
||||
this.updateSettingEvent()
|
||||
}
|
||||
}).catch(err => {
|
||||
this.$message.error(err)
|
||||
})
|
||||
},
|
||||
resetLocalPlayer () {
|
||||
this.d.externalPlayer = ''
|
||||
setting.update(this.d).then(res => {
|
||||
this.updateSettingEvent()
|
||||
this.$message.success('重置第三方播放器成功')
|
||||
})
|
||||
},
|
||||
updatePlayerPath () {
|
||||
this.$message.success('设定第三方播放器路径为:' + this.d.externalPlayer)
|
||||
this.show.editPlayerPath = false
|
||||
this.updateSettingEvent()
|
||||
},
|
||||
editSitesEvent () {
|
||||
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.theme = e
|
||||
this.s.theme = e
|
||||
setting.update(this.s).then(res => {
|
||||
this.$m.success(this.$t('set_success'))
|
||||
this.d.theme = e
|
||||
this.updateSettingEvent()
|
||||
},
|
||||
changeShortcut (e) {
|
||||
this.d.shortcut = e
|
||||
this.updateSettingEvent()
|
||||
this.show.shortcut = false
|
||||
},
|
||||
expShortcut () {
|
||||
const arr = [...this.shortcutList]
|
||||
const str = JSON.stringify(arr, null, 2)
|
||||
clipboard.writeText(str)
|
||||
this.$message.success('已复制到剪贴板')
|
||||
},
|
||||
impShortcut () {
|
||||
const str = clipboard.readText()
|
||||
const json = JSON.parse(str)
|
||||
shortcut.clear().then(res => {
|
||||
this.$message.info('已清空原数据')
|
||||
shortcut.add(json).then(e => {
|
||||
this.$message.success('已添加成功')
|
||||
this.getSites()
|
||||
})
|
||||
})
|
||||
},
|
||||
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.$m.success(this.$t('set_success'))
|
||||
ipc.send('close')
|
||||
this.$message.success('重置成功')
|
||||
const win = remote.getCurrentWindow()
|
||||
win.destroy()
|
||||
})
|
||||
},
|
||||
openDoc (e) {
|
||||
if (e === 'sites') {
|
||||
this.linkOpen('http://zyplayer.fun/doc/sites/')
|
||||
return false
|
||||
}
|
||||
if (e === 'shortcut') {
|
||||
this.linkOpen('http://zyplayer.fun/doc/shortcut/')
|
||||
return false
|
||||
}
|
||||
},
|
||||
getLatestVersion () {
|
||||
ipcRenderer.send('checkForUpdate')
|
||||
ipcRenderer.on('update-available', (e, info) => {
|
||||
this.latestVersion = info.version
|
||||
})
|
||||
ipcRenderer.on('update-error', () => {
|
||||
this.$message.warning = '更新出错.'
|
||||
})
|
||||
ipcRenderer.on('update-downloaded', () => {
|
||||
this.$message.info = '下载完毕, 退出安装'
|
||||
})
|
||||
},
|
||||
quitAndInstall () {
|
||||
this.$message.success('已开始下载更新,下载完毕后,将自动退出安装。')
|
||||
ipcRenderer.send('quitAndInstall')
|
||||
},
|
||||
createContextMenu () {
|
||||
const { Menu, MenuItem } = remote
|
||||
const menu = new Menu()
|
||||
menu.append(new MenuItem({ label: '快速复制', role: 'copy' }))
|
||||
menu.append(new MenuItem({ label: '快速粘贴', role: 'paste' }))
|
||||
menu.append(new MenuItem({ label: '编辑', role: 'editMenu' }))
|
||||
window.addEventListener('contextmenu', e => {
|
||||
e.preventDefault()
|
||||
menu.popup(remote.getCurrentWindow())
|
||||
})
|
||||
}
|
||||
},
|
||||
created () {
|
||||
setting.find().then(res => {
|
||||
this.s = res
|
||||
this.theme = res.theme
|
||||
this.$i18n.locale = this.s.language
|
||||
this.show.setting = true
|
||||
})
|
||||
this.getSites()
|
||||
this.getSetting()
|
||||
this.getShortcut()
|
||||
this.getLatestVersion()
|
||||
this.createContextMenu()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -176,16 +507,16 @@ export default {
|
||||
.setting{
|
||||
height: calc(100% - 40px);
|
||||
width: 100%;
|
||||
border-radius: 5px;
|
||||
padding: 20px 0;
|
||||
.setting-box{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 5px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.logo{
|
||||
.logo{
|
||||
margin-top: 10px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
@@ -205,14 +536,37 @@ export default {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.change{
|
||||
.view{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
padding-left: 20px;
|
||||
margin-top: 40px;
|
||||
.zy-select{
|
||||
margin-right: 20px;
|
||||
padding: 20px;
|
||||
margin-top: 20px;
|
||||
.view-box{
|
||||
margin-top: 10px;
|
||||
.zy-select{
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.site{
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
margin-top: 20px;
|
||||
.site-box{
|
||||
margin-top: 10px;
|
||||
.zy-select{
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.shortcut{
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
margin-top: 20px;
|
||||
.shortcut-box{
|
||||
margin-top: 10px;
|
||||
.zy-select{
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.theme{
|
||||
@@ -221,6 +575,7 @@ export default {
|
||||
margin-top: 20px;
|
||||
.theme-box{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
margin-top: 10px;
|
||||
.theme-item{
|
||||
@@ -276,10 +631,15 @@ export default {
|
||||
line-height: 32px;
|
||||
}
|
||||
.clearTips{
|
||||
margin: 10px 0 0 20px;
|
||||
font-size: 12px;
|
||||
color: #ff000088;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
.Tips{
|
||||
margin: 20px;
|
||||
font-size: 12px;
|
||||
color: #ff000066;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<template>
|
||||
<div class="share" id="share" @click="shareClickEvent">
|
||||
<div class="share" id="share" @click="shareClickEvent" v-on-clickaway="shareClickEvent">
|
||||
<div class="left">
|
||||
<img :src="this.card.img" alt="">
|
||||
<img :src="pic" alt="" @load="picLoadEvent">
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="title">{{ card.name }}</div>
|
||||
<qrcode-vue id="qr" :value="value" :size="160" level="L" />
|
||||
<div class="right" id="right">
|
||||
<div class="title">{{ share.info.name }}</div>
|
||||
<qrcode-vue id="qr" :value="link" :size="160" level="L" />
|
||||
<div class="tips">
|
||||
<p>{{$t('qr_tips')}}</p>
|
||||
<p>长按二维码,识别播放。</p>
|
||||
<p><img src="@/assets/image/logo.png"></p>
|
||||
<p class="zy">{{$t('zy_tips')}}</p>
|
||||
<p class="zy">『ZY Player』技术支持,严禁传播违法资源。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="share-mask" v-show="loading">
|
||||
@@ -19,21 +19,19 @@
|
||||
</template>
|
||||
<script>
|
||||
import { mapMutations } from 'vuex'
|
||||
import tools from '../lib/site/tools'
|
||||
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',
|
||||
data () {
|
||||
return {
|
||||
card: {
|
||||
img: '',
|
||||
name: '',
|
||||
png: ''
|
||||
},
|
||||
value: 'https://www.baidu.com',
|
||||
loading: true
|
||||
pic: '',
|
||||
png: '',
|
||||
link: '',
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
@@ -52,46 +50,48 @@ export default {
|
||||
watch: {
|
||||
share: {
|
||||
handler () {
|
||||
this.getDetail()
|
||||
this.getDetail(
|
||||
this.loading = true
|
||||
)
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
directives: {
|
||||
onClickaway: onClickaway
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SET_SHARE']),
|
||||
getDetail () {
|
||||
this.loading = true
|
||||
tools.detail_get(this.share.v.site, this.share.v.detail).then(res => {
|
||||
const info = res.info
|
||||
const parser = new DOMParser()
|
||||
const html = parser.parseFromString(info, 'text/html')
|
||||
const img = html.querySelector('img').src
|
||||
this.card.img = img
|
||||
this.card.name = this.share.v.name
|
||||
const urls = res.m3u8_urls
|
||||
const url = urls[this.share.v.index].split('$')[1]
|
||||
this.value = 'http://zyplayer.fun/player/player.html?url=' + url + '&title=' + this.share.v.name
|
||||
this.loading = false
|
||||
this.$nextTick(() => {
|
||||
const dom = document.getElementById('share')
|
||||
html2canvas(dom, { allowTaint: true, useCORS: true }).then(res => {
|
||||
const png = res.toDataURL('image/png')
|
||||
const p = nativeImage.createFromDataURL(png)
|
||||
clipboard.writeImage(p)
|
||||
this.$m.success(this.$t('share_tips'))
|
||||
this.share.show = true
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
shareClickEvent () {
|
||||
this.share = {
|
||||
show: false,
|
||||
v: {}
|
||||
info: {}
|
||||
}
|
||||
},
|
||||
getDetail () {
|
||||
this.loading = true
|
||||
const id = this.share.info.ids || this.share.info.id
|
||||
zy.detail(this.share.key, id).then(res => {
|
||||
if (res) {
|
||||
this.pic = res.pic
|
||||
var m3u8List = res.m3u8List
|
||||
const url = m3u8List[1]
|
||||
this.link = 'http://zyplayer.fun/player/player.html?url=' + url + '&title=' + this.share.info.name
|
||||
}
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
picLoadEvent () {
|
||||
const dom = document.getElementById('share')
|
||||
html2canvas(dom, { useCORS: true, allowTaint: true }).then(res => {
|
||||
const png = res.toDataURL('image/png')
|
||||
const p = nativeImage.createFromDataURL(png)
|
||||
clipboard.writeImage(p)
|
||||
this.$message.success('已复制到剪贴板,快去分享吧~ 严禁传播违法资源!!!')
|
||||
})
|
||||
}
|
||||
},
|
||||
created () {
|
||||
mounted () {
|
||||
this.getDetail()
|
||||
}
|
||||
}
|
||||
@@ -107,8 +107,8 @@ export default {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
z-index: 888;
|
||||
padding: 0px;
|
||||
z-index: 999;
|
||||
.left, .right{
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
@@ -124,6 +124,7 @@ export default {
|
||||
}
|
||||
}
|
||||
.right{
|
||||
padding: 10px;
|
||||
.title{
|
||||
font-size: 18px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
@@ -1,55 +1,158 @@
|
||||
<template>
|
||||
<div class="star">
|
||||
<div class="zy-table">
|
||||
<div class="tHead">
|
||||
<span class="name">{{$t('videoName')}}</span>
|
||||
<span class="type">{{$t('type')}}</span>
|
||||
<span class="time">{{$t('time')}}</span>
|
||||
<span class="from">{{$t('from')}}</span>
|
||||
<span class="operate" style="width: 220px">{{$t('operate')}}</span>
|
||||
<div class="listpage" id="star">
|
||||
<div class="listpage-header" id="star-header">
|
||||
<el-switch v-model="viewMode" active-text="海报" active-value="picture" inactive-text="列表" inactive-value="table" @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-body">
|
||||
<div class="show-table" id="star-table" v-show="viewMode === 'table'">
|
||||
<el-table size="mini" fit height="100%" row-key="id"
|
||||
ref="starTable"
|
||||
:data="list"
|
||||
:cell-class-name="checkUpdate"
|
||||
@row-click="detailEvent"
|
||||
@sort-change="handleSortChange">
|
||||
<el-table-column
|
||||
sortable
|
||||
:sort-method="(a , b) => sortByLocaleCompare(a.name, b.name)"
|
||||
prop="name"
|
||||
label="片名">
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
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="(a , b) => sortByLocaleCompare(a.detail.type, b.detail.type)"
|
||||
prop="detail.type"
|
||||
label="类型"
|
||||
width="100">
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
sortable
|
||||
:sort-by="['detail.year', 'name']"
|
||||
prop="detail.year"
|
||||
label="上映"
|
||||
width="100">
|
||||
</el-table-column>
|
||||
<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"
|
||||
label="观看至">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ getHistoryNote(scope.row.index) }}</span>
|
||||
</template>
|
||||
</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="tBody zy-scroll">
|
||||
<ul v-show="!loading">
|
||||
<li v-for="(i, j) in data" :key="j" @click="detailEvent(i)">
|
||||
<span class="name">{{i.name}}</span>
|
||||
<span class="type">{{i.type}}</span>
|
||||
<span class="time">{{i.time}}</span>
|
||||
<span class="from">{{i.site | ftSite}}</span>
|
||||
<span class="operate" style="width: 220px">
|
||||
<span class="btn" @click.stop="playEvent(i)">{{$t('play')}}</span>
|
||||
<span class="btn" @click.stop="deleteEvent(i)">{{$t('delete')}}</span>
|
||||
<span class="btn" @click.stop="shareEvent(i)">{{$t('share')}}</span>
|
||||
<span class="btn" @click.stop="updateEvent(i)">{{$t('sync')}}</span>
|
||||
<span class="btn" @click.stop="downloadEvent(i)">{{$t('download')}}</span>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tBody-mask" v-show="loading">
|
||||
<div class="loader"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tFooter">
|
||||
<span class="tFooter-span">{{data.length}} {{$t('total')}}</span>
|
||||
<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 tools from '../lib/site/tools'
|
||||
import video from '../lib/dexie/video'
|
||||
import { sites, getSite } from '../lib/site/sites'
|
||||
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 {
|
||||
sites: sites,
|
||||
data: [],
|
||||
loading: true,
|
||||
checkFlag: false
|
||||
list: [],
|
||||
sites: [],
|
||||
viewMode: 'picture',
|
||||
numNoUpdate: 0
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Waterfall
|
||||
},
|
||||
computed: {
|
||||
view: {
|
||||
get () {
|
||||
@@ -59,14 +162,6 @@ export default {
|
||||
this.SET_VIEW(val)
|
||||
}
|
||||
},
|
||||
detail: {
|
||||
get () {
|
||||
return this.$store.getters.getDetail
|
||||
},
|
||||
set (val) {
|
||||
this.SET_DETAIL(val)
|
||||
}
|
||||
},
|
||||
video: {
|
||||
get () {
|
||||
return this.$store.getters.getVideo
|
||||
@@ -75,6 +170,14 @@ export default {
|
||||
this.SET_VIDEO(val)
|
||||
}
|
||||
},
|
||||
detail: {
|
||||
get () {
|
||||
return this.$store.getters.getDetail
|
||||
},
|
||||
set (val) {
|
||||
this.SET_DETAIL(val)
|
||||
}
|
||||
},
|
||||
share: {
|
||||
get () {
|
||||
return this.$store.getters.getShare
|
||||
@@ -84,105 +187,307 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
ftSite (e) {
|
||||
const name = getSite(e).name
|
||||
return name
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
view () {
|
||||
this.getAllStar()
|
||||
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: {
|
||||
...mapMutations(['SET_VIEW', 'SET_DETAIL', 'SET_VIDEO', 'SET_SHARE']),
|
||||
handleSortChange (column, prop, order) {
|
||||
this.updateDatabase()
|
||||
},
|
||||
sortByLocaleCompare (a, b) {
|
||||
return a.localeCompare(b, 'zh')
|
||||
},
|
||||
detailEvent (e) {
|
||||
this.detail = {
|
||||
show: true,
|
||||
v: e
|
||||
key: e.key,
|
||||
info: {
|
||||
id: e.ids,
|
||||
name: e.name
|
||||
}
|
||||
}
|
||||
if (e.hasUpdate) {
|
||||
this.clearHasUpdateFlag(e)
|
||||
}
|
||||
},
|
||||
playEvent (e) {
|
||||
this.video = e
|
||||
async playEvent (e) {
|
||||
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 }, detail: e.detail }
|
||||
}
|
||||
if (e.hasUpdate) {
|
||||
this.clearHasUpdateFlag(e)
|
||||
}
|
||||
this.view = 'Play'
|
||||
},
|
||||
deleteEvent (e) {
|
||||
video.remove(e.id).then(res => {
|
||||
star.remove(e.id).then(res => {
|
||||
if (res) {
|
||||
this.$m.warning(this.$t('delete_failed'))
|
||||
} else {
|
||||
this.$m.success(this.$t('delete_success'))
|
||||
this.$message.warning('删除失败')
|
||||
}
|
||||
this.getAllStar()
|
||||
this.getFavorites()
|
||||
})
|
||||
},
|
||||
shareEvent (e) {
|
||||
this.share = {
|
||||
show: true,
|
||||
v: e
|
||||
key: e.key,
|
||||
info: e
|
||||
}
|
||||
},
|
||||
checkUpdate ({ row, rowIndex }) {
|
||||
if (this.list[rowIndex].hasUpdate) {
|
||||
return 'highlight'
|
||||
}
|
||||
},
|
||||
async clearHasUpdateFlag (e) {
|
||||
const db = await star.find({ id: e.id })
|
||||
if (db) {
|
||||
db.hasUpdate = false
|
||||
star.update(e.id, db)
|
||||
this.getFavorites()
|
||||
}
|
||||
},
|
||||
updateEvent (e) {
|
||||
tools.detail_get(e.site, e.detail).then(res => {
|
||||
const nameOne = e.name.replace(/\s*/g, '')
|
||||
const nameTwo = res.name.replace(/\s*/g, '')
|
||||
if (nameOne === nameTwo) {
|
||||
this.$m.info(this.$t('async_failed'))
|
||||
zy.detail(e.key, e.ids).then(detailRes => {
|
||||
var doc = {
|
||||
id: e.id,
|
||||
key: e.key,
|
||||
ids: e.ids,
|
||||
site: e.site,
|
||||
name: e.name,
|
||||
detail: detailRes,
|
||||
index: e.index
|
||||
}
|
||||
star.get(e.id).then(resStar => {
|
||||
if (!e.hasUpdate && e.detail.last !== detailRes.last) {
|
||||
doc.hasUpdate = true
|
||||
var msg = `同步"${e.name}"成功, 检查到更新。`
|
||||
this.$message.success(msg)
|
||||
} else {
|
||||
this.numNoUpdate += 1
|
||||
}
|
||||
star.update(e.id, doc)
|
||||
this.getFavorites()
|
||||
})
|
||||
}).catch(err => {
|
||||
var msg = `同步"${e.name}"失败, 请重试。`
|
||||
this.$message.warning(msg, err)
|
||||
})
|
||||
},
|
||||
updateAllEvent () {
|
||||
this.numNoUpdate = 0
|
||||
this.list.forEach(e => {
|
||||
this.updateEvent(e)
|
||||
})
|
||||
},
|
||||
downloadEvent (e) {
|
||||
zy.download(e.key, e.ids).then(res => {
|
||||
if (res) {
|
||||
const text = res.m3u8List
|
||||
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 {
|
||||
const h = e
|
||||
h.name = res.name
|
||||
video.update(h.id, h).then(res => {
|
||||
this.$m.success(this.$t('async_success'))
|
||||
zy.detail(e.key, e.ids).then(res => {
|
||||
const list = [...res.m3u8List]
|
||||
let downloadUrl = ''
|
||||
for (const i of list) {
|
||||
const url = encodeURI(i.split('$')[1])
|
||||
downloadUrl += (url + '\n')
|
||||
}
|
||||
clipboard.writeText(downloadUrl)
|
||||
this.$message.success('『M3U8』格式的链接已复制, 快去下载吧!')
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
downloadEvent (e) {
|
||||
tools.detail_get(e.site, e.detail).then(res => {
|
||||
if (res.mp4_urls.length > 0) {
|
||||
const urls = [...res.mp4_urls]
|
||||
let txt = `${e.name}\n`
|
||||
for (const i of urls) {
|
||||
const name = i.split('$')[0]
|
||||
const url = encodeURI(i.split('$')[1])
|
||||
txt += (name + ': ' + url + '\n')
|
||||
}
|
||||
clipboard.writeText(txt)
|
||||
this.$m.success('〖MP4〗: ' + this.$t('copy_success'))
|
||||
return false
|
||||
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
|
||||
}
|
||||
if (res.m3u8_urls.length > 0) {
|
||||
const urls = [...res.m3u8_urls]
|
||||
let txt = `${e.name}\n`
|
||||
for (const i of urls) {
|
||||
const name = i.split('$')[0]
|
||||
const url = encodeURI(i.split('$')[1])
|
||||
txt += (name + ': ' + url + '\n')
|
||||
}
|
||||
clipboard.writeText(txt)
|
||||
this.$m.success('〖M3U8〗: ' + this.$t('copy_success'))
|
||||
}
|
||||
},
|
||||
getHistoryNote (index) {
|
||||
if (index !== null && index !== undefined) {
|
||||
return `第${index + 1}集`
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
},
|
||||
getFavorites () {
|
||||
star.all().then(res => {
|
||||
this.list = res.sort(function (a, b) {
|
||||
return b.id - a.id
|
||||
})
|
||||
})
|
||||
},
|
||||
getAllsites () {
|
||||
sites.all().then(res => {
|
||||
this.sites = res
|
||||
})
|
||||
},
|
||||
exportFavoritesEvent () {
|
||||
const arr = [...this.list]
|
||||
const str = JSON.stringify(arr, null, 2)
|
||||
const options = {
|
||||
filters: [
|
||||
{ name: 'JSON file', extensions: ['json'] },
|
||||
{ name: 'Normal text file', extensions: ['txt'] },
|
||||
{ name: 'All types', extensions: ['*'] }
|
||||
]
|
||||
}
|
||||
remote.dialog.showSaveDialog(options).then(result => {
|
||||
if (!result.canceled) {
|
||||
fs.writeFileSync(result.filePath, str)
|
||||
this.$message.success('导出收藏成功')
|
||||
}
|
||||
}).catch(err => {
|
||||
this.$message.error(err)
|
||||
})
|
||||
},
|
||||
importFavoritesEvent () {
|
||||
const options = {
|
||||
filters: [
|
||||
{ name: 'JSON file', extensions: ['json'] },
|
||||
{ name: 'Normal text file', extensions: ['txt'] },
|
||||
{ name: 'All types', extensions: ['*'] }
|
||||
],
|
||||
properties: ['openFile', 'multiSelections']
|
||||
}
|
||||
remote.dialog.showOpenDialog(options).then(result => {
|
||||
if (!result.canceled) {
|
||||
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.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,
|
||||
hasUpdate: ele.hasUpdate,
|
||||
index: ele.index,
|
||||
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)
|
||||
}
|
||||
})
|
||||
})
|
||||
star.clear().then(star.bulkAdd(starList).then(res => {
|
||||
this.getFavorites()
|
||||
this.$message.success('导入收藏成功')
|
||||
}))
|
||||
}
|
||||
}).catch(err => {
|
||||
this.$message.error(err)
|
||||
})
|
||||
},
|
||||
clearFavoritesEvent () {
|
||||
star.clear().then(e => {
|
||||
this.getFavorites()
|
||||
})
|
||||
},
|
||||
syncTableData () {
|
||||
if (this.$refs.starTable.tableData && this.$refs.starTable.tableData.length === this.list.length) {
|
||||
this.list = this.$refs.starTable.tableData
|
||||
}
|
||||
},
|
||||
updateDatabase () {
|
||||
this.syncTableData()
|
||||
star.clear().then(res => {
|
||||
var id = this.list.length
|
||||
this.list.forEach(ele => {
|
||||
ele.id = id
|
||||
id -= 1
|
||||
})
|
||||
star.bulkAdd(this.list)
|
||||
})
|
||||
},
|
||||
rowDrop () {
|
||||
const tbody = document.getElementById('star-table').querySelector('.el-table__body-wrapper tbody')
|
||||
const _this = this
|
||||
Sortable.create(tbody, {
|
||||
onEnd ({ newIndex, oldIndex }) {
|
||||
const currRow = _this.list.splice(oldIndex, 1)[0]
|
||||
_this.list.splice(newIndex, 0, currRow)
|
||||
_this.updateDatabase()
|
||||
}
|
||||
})
|
||||
},
|
||||
getAllStar () {
|
||||
video.all().then(res => {
|
||||
this.data = res.reverse()
|
||||
this.loading = false
|
||||
getViewMode () {
|
||||
setting.find().then(res => {
|
||||
this.viewMode = res.starViewMode
|
||||
})
|
||||
},
|
||||
updateViewMode () {
|
||||
setting.find().then(res => {
|
||||
res.starViewMode = this.viewMode
|
||||
setting.update(res)
|
||||
})
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getAllStar()
|
||||
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>
|
||||
<style lang="scss" scoped>
|
||||
.star{
|
||||
height: calc(100% - 40px);
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,22 +1,29 @@
|
||||
import Vue from 'vue'
|
||||
import Aside from './Aside'
|
||||
import Detail from './Detail'
|
||||
import Film from './Film'
|
||||
import Frame from './Frame'
|
||||
import Film from './Film'
|
||||
import Play from './Play'
|
||||
import Setting from './Setting'
|
||||
import Share from './Share'
|
||||
import Star from './Star'
|
||||
|
||||
import Setting from './Setting'
|
||||
import Detail from './Detail'
|
||||
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)
|
||||
Vue.component('Detail', Detail)
|
||||
Vue.component('Film', Film)
|
||||
Vue.component('Frame', Frame)
|
||||
Vue.component('Film', Film)
|
||||
Vue.component('Play', Play)
|
||||
Vue.component('Setting', Setting)
|
||||
Vue.component('Share', Share)
|
||||
Vue.component('Star', Star)
|
||||
Vue.component('Setting', Setting)
|
||||
Vue.component('Detail', Detail)
|
||||
Vue.component('Share', Share)
|
||||
Vue.component('History', History)
|
||||
Vue.component('EditSites', EditSites)
|
||||
Vue.component('IPTV', IPTV)
|
||||
Vue.component('Recommendation', Recommendation)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
const os = require('os')
|
||||
const macaddress = require('macaddress')
|
||||
const AV = require('leancloud-storage')
|
||||
|
||||
macaddress.one((err, mac) => {
|
||||
if (err) {
|
||||
return false
|
||||
}
|
||||
AV.init({
|
||||
appId: 'X6TRIcMjgOG7EJ0t1l5r9In1-gzGzoHsz',
|
||||
appKey: 'JmkGF9UqkWGQNYDcJ2g1QV1b',
|
||||
serverURL: 'https://x6tricmj.lc-cn-n1-shared.com'
|
||||
})
|
||||
const system = os.hostname() + ' ' + os.type() + ' ' + os.arch()
|
||||
const query = new AV.Query('ZYPlayer')
|
||||
query.equalTo('os', system)
|
||||
query.equalTo('mac', mac)
|
||||
query.find().then(res => {
|
||||
// 存储新用户数据
|
||||
if (res.length === 0) {
|
||||
const ZYPlayer = AV.Object.extend('ZYPlayer')
|
||||
const zyPlayer = new ZYPlayer()
|
||||
zyPlayer.set('os', system)
|
||||
zyPlayer.set('mac', mac)
|
||||
zyPlayer.set('times', 1)
|
||||
zyPlayer.save()
|
||||
return false
|
||||
}
|
||||
// 统计启动次数
|
||||
if (res.length === 1) {
|
||||
const id = res[0].id
|
||||
const times = AV.Object.createWithoutData('ZYPlayer', id)
|
||||
times.increment('times', 1)
|
||||
times.save()
|
||||
return false
|
||||
}
|
||||
// 清除冗余数据
|
||||
if (res.length > 1) {
|
||||
const arr = res
|
||||
arr.shift()
|
||||
AV.Object.destroyAll(arr)
|
||||
}
|
||||
})
|
||||
})
|
||||
25
src/lib/dexie/channelList.js
Normal file
25
src/lib/dexie/channelList.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import db from './dexie'
|
||||
const { channelList } = db
|
||||
export default {
|
||||
async all () {
|
||||
return await channelList.toArray()
|
||||
},
|
||||
async clear () {
|
||||
return await channelList.clear()
|
||||
},
|
||||
async add (doc) {
|
||||
return await channelList.add(doc)
|
||||
},
|
||||
async bulkAdd (doc) {
|
||||
return await channelList.bulkAdd(doc)
|
||||
},
|
||||
async find (doc) {
|
||||
return await channelList.get(doc)
|
||||
},
|
||||
async update (id, docs) {
|
||||
return await channelList.update(id, docs)
|
||||
},
|
||||
async remove (id) {
|
||||
return await channelList.delete(id)
|
||||
}
|
||||
}
|
||||
29
src/lib/dexie/dexie.js
Normal file
29
src/lib/dexie/dexie.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import Dexie from 'dexie'
|
||||
import { setting, sites, localKey, iptv, recommendations } from './initData'
|
||||
|
||||
const db = new Dexie('zy')
|
||||
|
||||
db.version(4).stores({
|
||||
search: '++id, keywords',
|
||||
setting: 'id, theme, site, shortcut, view, volume, externalPlayer, searchGroup, excludeRootClasses, excludeR18Films, forwardTimeInSec, starViewMode, recommandationViewMode, searchViewMode, password, proxy, allowPassWhenIptvCheck, autocleanWhenIptvCheck',
|
||||
shortcut: 'name, key, desc',
|
||||
star: '++id, [key+ids], site, name, detail, index, rate, hasUpdate',
|
||||
recommendation: '++id, [key+ids], site, name, detail, index, rate, hasUpdate',
|
||||
sites: '++id, key, name, api, download, isActive, group',
|
||||
history: '++id, [site+ids], name, type, year, index, time, duration, detail',
|
||||
mini: 'id, bounds',
|
||||
iptv: '++id, name, url, isActive',
|
||||
channelList: '++id, name, prefer, channels, group, isActive'
|
||||
})
|
||||
|
||||
db.on('populate', () => {
|
||||
db.setting.bulkAdd(setting)
|
||||
db.sites.bulkAdd(sites)
|
||||
db.shortcut.bulkAdd(localKey)
|
||||
db.iptv.bulkAdd(iptv)
|
||||
db.recommendation.bulkAdd(recommendations)
|
||||
})
|
||||
|
||||
db.open()
|
||||
|
||||
export default db
|
||||
@@ -1,11 +1,14 @@
|
||||
import db from './index'
|
||||
import db from './dexie'
|
||||
const { history } = db
|
||||
export default {
|
||||
async add (doc) {
|
||||
return await history.add(doc)
|
||||
},
|
||||
async bulkAdd (doc) {
|
||||
return await history.bulkAdd(doc)
|
||||
},
|
||||
async find (doc) {
|
||||
return await history.get(doc)
|
||||
return await history.where(doc).first()
|
||||
},
|
||||
async update (id, docs) {
|
||||
return await history.update(id, docs)
|
||||
|
||||
@@ -1,33 +1,23 @@
|
||||
import Dexie from 'dexie'
|
||||
import history from './history'
|
||||
import mini from './mini'
|
||||
import setting from './setting'
|
||||
import shortcut from './shortcut'
|
||||
import star from './star'
|
||||
import sites from './sites'
|
||||
import search from './search'
|
||||
import iptv from './iptv'
|
||||
import channelList from './channelList'
|
||||
import recommendation from './recommendation'
|
||||
|
||||
const db = new Dexie('zy')
|
||||
|
||||
db.version(1).stores({
|
||||
theme: '++id, theme',
|
||||
site: '++id, site',
|
||||
video: '++id, name, type, time, detail, urls, index'
|
||||
})
|
||||
|
||||
db.version(2).stores({
|
||||
setting: 'id, theme, site, language, cloud, cloudKey',
|
||||
video: '++id, site, name, type, time, detail, index',
|
||||
history: '++id, site, name, type, time, detail, index, currentTime',
|
||||
mini: 'id, site, name, type, time, detail, index, currentTime'
|
||||
})
|
||||
|
||||
const initData = [{
|
||||
id: 0,
|
||||
theme: 'light',
|
||||
site: 'zuidazy',
|
||||
language: 'zhCn',
|
||||
cloud: false,
|
||||
cloudKey: ''
|
||||
}]
|
||||
|
||||
db.on('populate', () => {
|
||||
db.setting.bulkAdd(initData)
|
||||
})
|
||||
|
||||
db.open()
|
||||
|
||||
export default db
|
||||
export {
|
||||
history,
|
||||
mini,
|
||||
setting,
|
||||
shortcut,
|
||||
star,
|
||||
sites,
|
||||
iptv,
|
||||
channelList,
|
||||
search,
|
||||
recommendation
|
||||
}
|
||||
|
||||
1598
src/lib/dexie/iniData/Iptv.json
Normal file
1598
src/lib/dexie/iniData/Iptv.json
Normal file
File diff suppressed because it is too large
Load Diff
10382
src/lib/dexie/iniData/Recommendations.json
Normal file
10382
src/lib/dexie/iniData/Recommendations.json
Normal file
File diff suppressed because one or more lines are too long
259
src/lib/dexie/iniData/Sites.json
Normal file
259
src/lib/dexie/iniData/Sites.json
Normal file
@@ -0,0 +1,259 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"key": "mahuazy",
|
||||
"name": "麻花资源",
|
||||
"api": "http://www.mhapi123.com/inc/ldg_api.php",
|
||||
"download": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"key": "1886zy",
|
||||
"name": "1886 资源",
|
||||
"api": "http://cj.1886zy.co/inc/api.php",
|
||||
"download": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
},
|
||||
{
|
||||
"key": "wolongzy",
|
||||
"id": 3,
|
||||
"name": "卧龙资源网",
|
||||
"api": "https://www.mhapi123.com/inc/api.php",
|
||||
"download": "",
|
||||
"group": "默认",
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"key": "123ku",
|
||||
"name": "123 资源",
|
||||
"api": "http://cj.123ku2.com:12315/inc/api.php",
|
||||
"download": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"key": "subo988",
|
||||
"name": "速播资源站",
|
||||
"api": "https://www.subo988.com/inc/api.php",
|
||||
"download": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"key": "88zyw",
|
||||
"name": "88 影视资源站",
|
||||
"api": "http://www.88zyw.net/inc/api.php",
|
||||
"download": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
},
|
||||
{
|
||||
"key": "zuidazy",
|
||||
"id": 7,
|
||||
"name": "最大资源网",
|
||||
"api": "http://www.zdziyuan.com/inc/ldg_sea.php",
|
||||
"download": "http://www.zdziyuan.com/inc/apidown.php",
|
||||
"group": "默认",
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"key": "mbo",
|
||||
"id": 8,
|
||||
"name": "秒播资源",
|
||||
"api": "http://caiji.mb77.vip/inc/seacmsapi.php",
|
||||
"download": "",
|
||||
"group": "默认",
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"key": "apibdzy",
|
||||
"name": "百度云资源",
|
||||
"api": "https://api.apibdzy.com/api.php/provide/vod/at/xml",
|
||||
"download": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"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": 11,
|
||||
"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": 12,
|
||||
"key": "kubozy",
|
||||
"name": "酷播资源",
|
||||
"api": "http://api.kbzyapi.com/inc/api.php",
|
||||
"download": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"key": "yongjiuzy",
|
||||
"name": "永久资源",
|
||||
"api": "http://cj.yongjiuzyw.com/inc/api.php",
|
||||
"download": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"key": "rrzy",
|
||||
"name": "人人资源",
|
||||
"api": "https://www.rrzyw.cc/api.php/provide/vod/from/rrm3u8/at/xml/",
|
||||
"download": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"key": "bbkdj",
|
||||
"name": "步步高顶尖资源网",
|
||||
"api": "http://api.bbkdj.com/api",
|
||||
"download": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
},
|
||||
{
|
||||
"id": 16,
|
||||
"key": "solezy",
|
||||
"name": "搜乐资源网",
|
||||
"api": "https://www.caijizy.vip/api.php/provide/vod/at/xml/",
|
||||
"download": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
},
|
||||
{
|
||||
"id": 17,
|
||||
"key": "zuixinzy",
|
||||
"name": "最新资源",
|
||||
"api": "http://api.zuixinapi.com/inc/api.php",
|
||||
"download": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
},
|
||||
{
|
||||
"id": 18,
|
||||
"key": "605zy",
|
||||
"name": "605资源",
|
||||
"api": "http://www.605zy.net/inc/seacmsapi.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": "mokazy",
|
||||
"name": "魔卡资源网",
|
||||
"api": "https://cj.heiyap.com/api.php/provide/vod/at/xml/",
|
||||
"download": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
},
|
||||
{
|
||||
"id": 25,
|
||||
"key": "158zy",
|
||||
"name": "壹伍捌资源网",
|
||||
"api": "http://cj.158zyz.net:158/inc/api.php",
|
||||
"download": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
},
|
||||
{
|
||||
"id": 26,
|
||||
"key": "kyzy",
|
||||
"name": "快影资源站",
|
||||
"api": "https://www.kyzy.tv/api.php/kyyun/vod/at/xml/",
|
||||
"download": "",
|
||||
"group": "默认",
|
||||
"isActive": true,
|
||||
"status": "可用"
|
||||
}
|
||||
]
|
||||
144
src/lib/dexie/initData.js
Normal file
144
src/lib/dexie/initData.js
Normal file
@@ -0,0 +1,144 @@
|
||||
const setting = [
|
||||
{
|
||||
id: 0,
|
||||
theme: 'light',
|
||||
shortcut: true,
|
||||
view: 'picture',
|
||||
externalPlayer: '',
|
||||
searchGroup: '全站',
|
||||
excludeRootClasses: true,
|
||||
excludeR18Films: true,
|
||||
forwardTimeInSec: 5,
|
||||
starViewMode: 'picture',
|
||||
recommendationViewMode: 'picture',
|
||||
historyViewMode: 'picture',
|
||||
searchViewMode: 'picture',
|
||||
password: '',
|
||||
proxy: {
|
||||
type: 'none',
|
||||
scheme: '',
|
||||
url: '',
|
||||
port: ''
|
||||
},
|
||||
allowPassWhenIptvCheck: true,
|
||||
autocleanWhenIptvCheck: false
|
||||
}
|
||||
]
|
||||
|
||||
const localKey = [
|
||||
{
|
||||
name: 'playAndPause',
|
||||
desc: '播放或暂停',
|
||||
key: 'space'
|
||||
},
|
||||
{
|
||||
name: 'forward',
|
||||
desc: '快进',
|
||||
key: 'right'
|
||||
},
|
||||
{
|
||||
name: 'back',
|
||||
desc: '快退',
|
||||
key: 'left'
|
||||
},
|
||||
{
|
||||
name: 'volumeUp',
|
||||
desc: '音量调高',
|
||||
key: 'up'
|
||||
},
|
||||
{
|
||||
name: 'volumeDown',
|
||||
desc: '音量调低',
|
||||
key: 'down'
|
||||
},
|
||||
{
|
||||
name: 'mute',
|
||||
desc: '静音',
|
||||
key: 'm'
|
||||
},
|
||||
{
|
||||
name: 'top',
|
||||
desc: '置顶或退出置顶',
|
||||
key: 't'
|
||||
},
|
||||
{
|
||||
name: 'fullscreen',
|
||||
desc: '进入或退出全屏',
|
||||
key: 'f'
|
||||
},
|
||||
{
|
||||
name: 'escape',
|
||||
desc: '退出全屏/精简模式',
|
||||
key: 'esc'
|
||||
},
|
||||
{
|
||||
name: 'next',
|
||||
desc: '下一集',
|
||||
key: 'alt+right'
|
||||
},
|
||||
{
|
||||
name: 'prev',
|
||||
desc: '上一集',
|
||||
key: 'alt+left'
|
||||
},
|
||||
{
|
||||
name: 'home',
|
||||
desc: '跳到视频开始位置',
|
||||
key: 'home'
|
||||
},
|
||||
{
|
||||
name: 'end',
|
||||
desc: '跳到视频结束位置',
|
||||
key: 'end'
|
||||
},
|
||||
{
|
||||
name: 'opacityUp',
|
||||
desc: '透明度调高',
|
||||
key: 'alt+up'
|
||||
},
|
||||
{
|
||||
name: 'opacityDown',
|
||||
desc: '透明度调低',
|
||||
key: 'alt+down'
|
||||
},
|
||||
{
|
||||
name: 'playbackRateUp',
|
||||
desc: '播放倍速加快',
|
||||
key: 'pageup'
|
||||
},
|
||||
{
|
||||
name: 'playbackRateDown',
|
||||
desc: '播放倍速减慢',
|
||||
key: 'pagedown'
|
||||
},
|
||||
{
|
||||
name: 'mini',
|
||||
desc: '进入或退出mini模式',
|
||||
key: 'alt+m'
|
||||
},
|
||||
{
|
||||
name: 'resetMini',
|
||||
desc: '重置mini窗口',
|
||||
key: 'ctrl+0'
|
||||
}
|
||||
]
|
||||
|
||||
const getSite = (key) => {
|
||||
for (const i of sites) {
|
||||
if (key === i.key) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
25
src/lib/dexie/iptv.js
Normal file
25
src/lib/dexie/iptv.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import db from './dexie'
|
||||
const { iptv } = db
|
||||
export default {
|
||||
async all () {
|
||||
return await iptv.toArray()
|
||||
},
|
||||
async clear () {
|
||||
return await iptv.clear()
|
||||
},
|
||||
async add (doc) {
|
||||
return await iptv.add(doc)
|
||||
},
|
||||
async bulkAdd (doc) {
|
||||
return await iptv.bulkAdd(doc)
|
||||
},
|
||||
async find (doc) {
|
||||
return await iptv.get(doc)
|
||||
},
|
||||
async update (id, docs) {
|
||||
return await iptv.update(id, docs)
|
||||
},
|
||||
async remove (id) {
|
||||
return await iptv.delete(id)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import db from './index'
|
||||
import db from './dexie'
|
||||
const { mini } = db
|
||||
export default {
|
||||
async add (doc) {
|
||||
|
||||
28
src/lib/dexie/recommendation.js
Normal file
28
src/lib/dexie/recommendation.js
Normal 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()
|
||||
}
|
||||
}
|
||||
22
src/lib/dexie/search.js
Normal file
22
src/lib/dexie/search.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import db from './dexie'
|
||||
const { search } = db
|
||||
export default {
|
||||
async add (doc) {
|
||||
return await search.add(doc)
|
||||
},
|
||||
async find (doc) {
|
||||
return await search.get(doc)
|
||||
},
|
||||
async update (id, docs) {
|
||||
return await search.update(id, docs)
|
||||
},
|
||||
async all () {
|
||||
return await search.toArray()
|
||||
},
|
||||
async remove (id) {
|
||||
return await search.delete(id)
|
||||
},
|
||||
async clear () {
|
||||
return await search.clear()
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import db from './index'
|
||||
import db from './dexie'
|
||||
const { setting } = db
|
||||
|
||||
export default {
|
||||
async find () {
|
||||
return await setting.get({ id: 0 })
|
||||
|
||||
14
src/lib/dexie/shortcut.js
Normal file
14
src/lib/dexie/shortcut.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import db from './dexie'
|
||||
const { shortcut } = db
|
||||
|
||||
export default {
|
||||
async all () {
|
||||
return await shortcut.toArray()
|
||||
},
|
||||
async clear () {
|
||||
return await shortcut.clear()
|
||||
},
|
||||
async add (doc) {
|
||||
return await shortcut.bulkAdd(doc)
|
||||
}
|
||||
}
|
||||
22
src/lib/dexie/sites.js
Normal file
22
src/lib/dexie/sites.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import db from './dexie'
|
||||
const { sites } = db
|
||||
export default {
|
||||
async all () {
|
||||
return await sites.toArray()
|
||||
},
|
||||
async clear () {
|
||||
return await sites.clear()
|
||||
},
|
||||
async bulkAdd (doc) {
|
||||
return await sites.bulkAdd(doc)
|
||||
},
|
||||
async find (doc) {
|
||||
return await sites.get(doc)
|
||||
},
|
||||
async add (doc) {
|
||||
return await sites.add(doc)
|
||||
},
|
||||
async remove (id) {
|
||||
return await sites.delete(id)
|
||||
}
|
||||
}
|
||||
28
src/lib/dexie/star.js
Normal file
28
src/lib/dexie/star.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import db from './dexie'
|
||||
const { star } = db
|
||||
export default {
|
||||
async add (doc) {
|
||||
return await star.add(doc)
|
||||
},
|
||||
async bulkAdd (doc) {
|
||||
return await star.bulkAdd(doc)
|
||||
},
|
||||
async find (doc) {
|
||||
return await star.where(doc).first()
|
||||
},
|
||||
async update (id, docs) {
|
||||
return await star.update(id, docs)
|
||||
},
|
||||
async all () {
|
||||
return await star.toArray()
|
||||
},
|
||||
async remove (id) {
|
||||
return await star.delete(id)
|
||||
},
|
||||
async get (id) {
|
||||
return await star.get(id)
|
||||
},
|
||||
async clear () {
|
||||
return await star.clear()
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import db from './index'
|
||||
const { video } = db
|
||||
export default {
|
||||
async add (doc) {
|
||||
return await video.add(doc)
|
||||
},
|
||||
async find (doc) {
|
||||
return await video.get(doc)
|
||||
},
|
||||
async update (id, docs) {
|
||||
return await video.update(id, docs)
|
||||
},
|
||||
async all () {
|
||||
return await video.toArray()
|
||||
},
|
||||
async remove (id) {
|
||||
return await video.delete(id)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,20 @@
|
||||
import Vue from 'vue'
|
||||
import { Message, Pagination } from 'element-ui'
|
||||
|
||||
Vue.use(Pagination)
|
||||
|
||||
Vue.prototype.$m = Message
|
||||
import { Message, Button, Table, TableColumn, Tag, Input, Dialog, Form, FormItem, Switch, Select, Option, Checkbox, Autocomplete, Col, Tree } from 'element-ui'
|
||||
import Plugin from 'v-fit-columns'
|
||||
Vue.use(Button)
|
||||
Vue.use(Col)
|
||||
Vue.use(Table)
|
||||
Vue.use(TableColumn)
|
||||
Vue.use(Tag)
|
||||
Vue.use(Input)
|
||||
Vue.use(Dialog)
|
||||
Vue.use(Form)
|
||||
Vue.use(FormItem)
|
||||
Vue.use(Switch)
|
||||
Vue.use(Plugin)
|
||||
Vue.use(Select)
|
||||
Vue.use(Option)
|
||||
Vue.use(Checkbox)
|
||||
Vue.use(Autocomplete)
|
||||
Vue.use(Tree)
|
||||
Vue.prototype.$message = Message
|
||||
|
||||
317
src/lib/site/onlineVideo.js
Normal file
317
src/lib/site/onlineVideo.js
Normal file
@@ -0,0 +1,317 @@
|
||||
import open from 'open'
|
||||
import axios from 'axios'
|
||||
import cheerio from 'cheerio'
|
||||
|
||||
const onlineVideo = {
|
||||
playVideoOnline (selectedOnlineSite, videoName, videoIndex) {
|
||||
switch (selectedOnlineSite) {
|
||||
case '哔嘀':
|
||||
onlineVideo.playVideoOnBde4(videoName, videoIndex)
|
||||
break
|
||||
case '1080影视':
|
||||
onlineVideo.playVideoOnK1080(videoName, videoIndex)
|
||||
break
|
||||
case '素白白':
|
||||
onlineVideo.playVideoOnSubaibai(videoName, videoIndex)
|
||||
break
|
||||
case '哆咪动漫':
|
||||
onlineVideo.playVideoOndmdm2020(videoName, videoIndex)
|
||||
break
|
||||
case '樱花动漫':
|
||||
onlineVideo.playVideoOnYhdm(videoName, videoIndex)
|
||||
break
|
||||
case '简影':
|
||||
onlineVideo.playVideoOnSyrme(videoName, videoIndex)
|
||||
break
|
||||
case '极品':
|
||||
onlineVideo.playVideoOnJpysvip(videoName, videoIndex)
|
||||
break
|
||||
case '喜欢看':
|
||||
onlineVideo.playVideoOnXhkan(videoName, videoIndex)
|
||||
break
|
||||
default:
|
||||
this.$message.console.error(`不支持该网站:${this.selectedOnlineSite}`)
|
||||
}
|
||||
},
|
||||
playVideoOnBde4 (videoName, videoIndex) {
|
||||
videoName = videoName.replace(/\s/g, '')
|
||||
var url = `https://bde4.com/search/${videoName}`
|
||||
axios.get(url).then(res => {
|
||||
const $ = cheerio.load(res.data)
|
||||
var e = $('div.search-list')
|
||||
var searchResult = $(e).find('div>div>div>div>a').toArray()
|
||||
// 获取第一个搜索结果的视频链接
|
||||
var detailPageLink = $(searchResult[0]).attr('href')
|
||||
// 获取第一个搜索结果的title
|
||||
var title = $(searchResult[0]).attr('title')
|
||||
if (title === null || title === undefined || !title.replace(/\s/g, '').includes(videoName)) {
|
||||
// 如果第一个搜索结果不符合,打开搜索页面
|
||||
open(url)
|
||||
} else {
|
||||
var detailPageFullLink = 'https://bde4.com/' + detailPageLink
|
||||
// 解析详情页面
|
||||
axios.get(detailPageFullLink).then(res => {
|
||||
const $ = cheerio.load(res.data)
|
||||
var e = $('div.info1')
|
||||
var videoList = $(e).find('a').toArray()
|
||||
var videoFullLink = detailPageFullLink
|
||||
// 获取index视频链接
|
||||
if (videoIndex < videoList.length) {
|
||||
var indexVideoLink = $(videoList[videoIndex]).attr('href')
|
||||
if (indexVideoLink.includes('.htm')) {
|
||||
videoFullLink = 'https://bde4.com' + indexVideoLink
|
||||
}
|
||||
}
|
||||
open(videoFullLink)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
playVideoOnK1080 (videoName, videoIndex) {
|
||||
videoName = videoName.replace(/\s/g, '')
|
||||
var url = `https://k1080.net/vodsearch123/-------------.html?wd=${videoName}&submit=`
|
||||
axios.get(url).then(res => {
|
||||
const $ = cheerio.load(res.data)
|
||||
var e = $('#searchList')
|
||||
var searchResult = $(e).find('li>div>a').toArray()
|
||||
// 获取第一个搜索结果的视频链接
|
||||
var detailPageLink = $(searchResult[0]).attr('href')
|
||||
// 获取第一个搜索结果的title
|
||||
var title = $(searchResult[0]).attr('title')
|
||||
if (title === null || title === undefined || !title.replace(/\s/g, '').includes(videoName)) {
|
||||
// 如果第一个搜索结果不符合,打开搜索页面
|
||||
open(url)
|
||||
} else {
|
||||
// 解析详情页面
|
||||
var detailPageFullLink = 'https://k1080.net' + detailPageLink
|
||||
axios.get(detailPageFullLink).then(res2 => {
|
||||
const $ = cheerio.load(res2.data)
|
||||
// 获取playlist1
|
||||
var e = $('#playlist1')
|
||||
// 获取所有视频链接
|
||||
var videoList = $(e).find('div>ul>li>a').toArray()
|
||||
var videoFullLink = detailPageFullLink
|
||||
// 获取index视频链接
|
||||
if (videoIndex < videoList.length) {
|
||||
var indexVideoLink = $(videoList[videoIndex]).attr('href')
|
||||
if (indexVideoLink.includes('.htm')) {
|
||||
videoFullLink = 'https://k1080.net' + indexVideoLink
|
||||
}
|
||||
}
|
||||
open(videoFullLink)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
playVideoOnSubaibai (videoName, videoIndex) {
|
||||
videoName = videoName.replace(/\s/g, '')
|
||||
var url = `https://www.subaibai.com/xssearch?q=${videoName}`
|
||||
axios.get(url).then(res => {
|
||||
const $ = cheerio.load(res.data)
|
||||
var e = $('div.search_list')
|
||||
var searchResult = $(e).find('div>ul>li>h3>a').toArray()
|
||||
// 获取第一个搜索结果的视频链接
|
||||
var detailPageLink = $(searchResult[0]).attr('href')
|
||||
// 获取第一个搜索结果的title
|
||||
var title = $(searchResult[0]).text()
|
||||
if (title === null || title === undefined || !title.replace(/\s/g, '').includes(videoName)) {
|
||||
// 如果第一个搜索结果不符合,打开搜索页面
|
||||
open(url)
|
||||
} else {
|
||||
// 解析详情页面
|
||||
var detailPageFullLink = detailPageLink
|
||||
axios.get(detailPageFullLink).then(res2 => {
|
||||
const $ = cheerio.load(res2.data)
|
||||
// 获取playlist1
|
||||
var e = $('div.paly_list_btn')
|
||||
// 获取所有视频链接
|
||||
var videoList = $(e).find('a').toArray()
|
||||
// 获取index视频链接
|
||||
var videoFullLink = detailPageFullLink
|
||||
if (videoIndex < videoList.length) {
|
||||
var indexVideoLink = $(videoList[videoIndex]).attr('href')
|
||||
if (indexVideoLink.includes('.htm')) {
|
||||
videoFullLink = indexVideoLink
|
||||
}
|
||||
}
|
||||
open(videoFullLink)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
playVideoOnYhdm (videoName, videoIndex) {
|
||||
videoName = videoName.replace(/\s/g, '')
|
||||
var url = `http://www.yhdm.tv/search/${videoName}`
|
||||
axios.get(url).then(res => {
|
||||
const $ = cheerio.load(res.data)
|
||||
var e = $('div.lpic')
|
||||
var searchResult = $(e).find('div>ul>li>h2>a').toArray()
|
||||
// 获取第一个搜索结果的视频链接
|
||||
var detailPageLink = $(searchResult[0]).attr('href')
|
||||
// 获取第一个搜索结果的title
|
||||
var title = $(searchResult[0]).attr('title')
|
||||
if (title === null || title === undefined || !title.replace(/\s/g, '').includes(videoName)) {
|
||||
// 如果第一个搜索结果不符合,打开搜索页面
|
||||
open(url)
|
||||
} else {
|
||||
// 解析详情页面
|
||||
var detailPageFullLink = 'http://www.yhdm.tv/' + detailPageLink
|
||||
axios.get(detailPageFullLink).then(res2 => {
|
||||
const $ = cheerio.load(res2.data)
|
||||
// 获取playlist1
|
||||
var e = $('div.movurl')
|
||||
// 获取所有视频链接
|
||||
var videoList = $(e).find('div>ul>li>a').toArray()
|
||||
// 获取index视频链接
|
||||
var videoFullLink = detailPageFullLink
|
||||
if (videoIndex < videoList.length) {
|
||||
var indexVideoLink = $(videoList[videoIndex]).attr('href')
|
||||
if (indexVideoLink.includes('.htm')) {
|
||||
videoFullLink = 'http://www.yhdm.tv/' + indexVideoLink
|
||||
}
|
||||
}
|
||||
open(videoFullLink)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
playVideoOndmdm2020 (videoName, videoIndex) {
|
||||
videoName = videoName.replace(/\s/g, '')
|
||||
var url = `http://www.dmdm2020.com/dongmansearch.html?wd=${videoName}&submit=`
|
||||
axios.get(url).then(res => {
|
||||
const $ = cheerio.load(res.data)
|
||||
var e = $('#searchList')
|
||||
var searchResult = $(e).find('ul>li>div>h4>a').toArray()
|
||||
// 获取第一个搜索结果的视频链接
|
||||
var detailPageLink = $(searchResult[0]).attr('href')
|
||||
// 获取第一个搜索结果的title
|
||||
var title = $(searchResult[0]).text()
|
||||
if (title === null || title === undefined || !title.replace(/\s/g, '').includes(videoName)) {
|
||||
// 如果第一个搜索结果不符合,打开搜索页面
|
||||
open(url)
|
||||
} else {
|
||||
// 解析详情页面
|
||||
var detailPageFullLink = 'http://www.dmdm2020.com' + detailPageLink
|
||||
axios.get(detailPageFullLink).then(res2 => {
|
||||
const $ = cheerio.load(res2.data)
|
||||
// 获取playlist1
|
||||
var e = $('#playlist1')
|
||||
// 获取所有视频链接
|
||||
var videoList = $(e).find('div>ul>li>a').toArray()
|
||||
// 获取index视频链接
|
||||
var videoFullLink = detailPageFullLink
|
||||
if (videoIndex < videoList.length) {
|
||||
var indexVideoLink = $(videoList[videoIndex]).attr('href')
|
||||
if (indexVideoLink.includes('.htm')) {
|
||||
videoFullLink = 'http://www.dmdm2020.com' + indexVideoLink
|
||||
}
|
||||
}
|
||||
open(videoFullLink)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
playVideoOnSyrme (videoName, videoIndex) {
|
||||
videoName = videoName.replace(/\s/g, '')
|
||||
var url = `https://syrme.top/searchs?q=${videoName}`
|
||||
axios.get(url).then(res => {
|
||||
const $ = cheerio.load(res.data)
|
||||
var e = $('ul.MovieList')
|
||||
var searchResult = $(e).find('ul>li>article>a').toArray()
|
||||
// 获取第一个搜索结果的视频链接
|
||||
var detailPageLink = $(searchResult[0]).attr('href')
|
||||
// 获取第一个搜索结果的title
|
||||
var title = $(searchResult[0]).find('a>h2').text()
|
||||
if (title === null || title === undefined || !title.replace(/\s/g, '').includes(videoName)) {
|
||||
// 如果第一个搜索结果不符合,打开搜索页面
|
||||
open(url)
|
||||
} else {
|
||||
// 解析详情页面
|
||||
var detailPageFullLink = 'https://syrme.top' + detailPageLink
|
||||
axios.get(detailPageFullLink).then(res2 => {
|
||||
const $ = cheerio.load(res2.data)
|
||||
// 获取playlist1
|
||||
var e = $('#categories-2')
|
||||
// 获取所有视频链接
|
||||
var videoList = $(e).find('div>ul>li>a').toArray()
|
||||
// 获取index视频链接
|
||||
var videoFullLink = detailPageFullLink
|
||||
if (videoIndex < videoList.length) {
|
||||
var indexVideoLink = $(videoList[videoIndex]).attr('href')
|
||||
videoFullLink = 'https://syrme.top' + indexVideoLink
|
||||
}
|
||||
open(videoFullLink)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
playVideoOnJpysvip (videoName, videoIndex) {
|
||||
videoName = videoName.replace(/\s/g, '')
|
||||
var url = `https://www.jpysvip.net/vodsearch/-------------.html?wd=${videoName}&submit=`
|
||||
axios.get(url).then(res => {
|
||||
const $ = cheerio.load(res.data)
|
||||
var e = $('#searchList')
|
||||
var searchResult = $(e).find('ul>li>div>a').toArray()
|
||||
// 获取第一个搜索结果的视频链接
|
||||
var detailPageLink = $(searchResult[0]).attr('href')
|
||||
// 获取第一个搜索结果的title
|
||||
var title = $(searchResult[0]).attr('title')
|
||||
if (title === null || title === undefined || !title.replace(/\s/g, '').includes(videoName)) {
|
||||
// 如果第一个搜索结果不符合,打开搜索页面
|
||||
open(url)
|
||||
} else {
|
||||
// 解析详情页面
|
||||
var detailPageFullLink = 'https://www.jpysvip.net' + detailPageLink
|
||||
axios.get(detailPageFullLink).then(res2 => {
|
||||
const $ = cheerio.load(res2.data)
|
||||
// 获取playlist1
|
||||
var e = $('#playlist1')
|
||||
// 获取所有视频链接
|
||||
var videoList = $(e).find('div>ul>li>a').toArray()
|
||||
// 获取index视频链接
|
||||
var videoFullLink = detailPageFullLink
|
||||
if (videoIndex < videoList.length) {
|
||||
var indexVideoLink = $(videoList[videoIndex]).attr('href')
|
||||
videoFullLink = 'https://www.jpysvip.net/' + indexVideoLink
|
||||
}
|
||||
open(videoFullLink)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
playVideoOnXhkan (videoName, videoIndex) {
|
||||
videoName = videoName.replace(/\s/g, '')
|
||||
var url = `https://www.xhkan.com/vodsearch.html?wd=${videoName}&submit=`
|
||||
axios.get(url).then(res => {
|
||||
const $ = cheerio.load(res.data)
|
||||
var e = $('#searchList')
|
||||
var searchResult = $(e).find('ul>li>div>a').toArray()
|
||||
// 获取第一个搜索结果的视频链接
|
||||
var detailPageLink = $(searchResult[0]).attr('href')
|
||||
// 获取第一个搜索结果的title
|
||||
var title = $(searchResult[0]).attr('title')
|
||||
if (title === null || title === undefined || !title.replace(/\s/g, '').includes(videoName)) {
|
||||
// 如果第一个搜索结果不符合,打开搜索页面
|
||||
open(url)
|
||||
} else {
|
||||
// 解析详情页面
|
||||
var detailPageFullLink = detailPageLink
|
||||
axios.get(detailPageFullLink).then(res2 => {
|
||||
const $ = cheerio.load(res2.data)
|
||||
// 获取playlist1
|
||||
var e = $('#playlist1')
|
||||
// 获取所有视频链接
|
||||
var videoList = $(e).find('div>ul>li>a').toArray()
|
||||
// 获取index视频链接
|
||||
var videoFullLink = detailPageFullLink
|
||||
if (videoIndex < videoList.length) {
|
||||
var indexVideoLink = $(videoList[videoIndex]).attr('href')
|
||||
videoFullLink = indexVideoLink
|
||||
}
|
||||
open(videoFullLink)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
export default onlineVideo
|
||||
18
src/lib/site/server.js
Normal file
18
src/lib/site/server.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import express from 'express'
|
||||
import cors from 'cors'
|
||||
const Axios = require('axios')
|
||||
|
||||
const app = express()
|
||||
app.use(cors())
|
||||
app.use(express.json())
|
||||
app.use(express.urlencoded({ extended: true }))
|
||||
|
||||
app.post('/api', async (req, res) => {
|
||||
const result = await Axios.get(req.body.url)
|
||||
res.json({
|
||||
code: 1,
|
||||
info: result.data
|
||||
})
|
||||
})
|
||||
|
||||
app.listen(44444)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,478 +1,414 @@
|
||||
import { sites, setting } from '../dexie'
|
||||
import axios from 'axios'
|
||||
import { getSite } from './sites'
|
||||
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 = {
|
||||
key: 'zuidazy', // sites[n] 视频源
|
||||
id: 0, // 视频类型
|
||||
page: 1, // 第几页
|
||||
keywords: '', // 搜索关键字
|
||||
// 获取浏览列表
|
||||
film_get (key, id = 0, page = 1) {
|
||||
xmlConfig: { // XML 转 JSON 配置
|
||||
trimValues: true,
|
||||
textNodeName: '_t',
|
||||
ignoreAttributes: false,
|
||||
attributeNamePrefix: '_',
|
||||
parseAttributeValue: true
|
||||
},
|
||||
getSite (key) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const site = getSite(key)
|
||||
let url = ''
|
||||
if (id === 0) {
|
||||
url = site.new.replace(/{page}/, page)
|
||||
sites.all().then(res => {
|
||||
for (const i of res) {
|
||||
if (key === i.key) {
|
||||
resolve(i)
|
||||
}
|
||||
}
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 获取资源分类 和 所有资源的总数, 分页等信息
|
||||
* @param {*} key 资源网 key
|
||||
* @returns
|
||||
*/
|
||||
class (key) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.getSite(key).then(res => {
|
||||
const url = res.api
|
||||
axios.post(url).then(res => {
|
||||
const data = res.data
|
||||
const json = parser.parse(data, this.xmlConfig)
|
||||
const jsondata = json.rss === undefined ? json : json.rss
|
||||
const arr = []
|
||||
if (jsondata.class) {
|
||||
for (const i of jsondata.class.ty) {
|
||||
const j = {
|
||||
tid: i._id,
|
||||
name: i._t
|
||||
}
|
||||
arr.push(j)
|
||||
}
|
||||
}
|
||||
const doc = {
|
||||
class: arr,
|
||||
page: jsondata.list._page,
|
||||
pagecount: jsondata.list._pagecount,
|
||||
pagesize: jsondata.list._pagesize,
|
||||
recordcount: jsondata.list._recordcount
|
||||
}
|
||||
resolve(doc)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 获取资源列表
|
||||
* @param {*} key 资源网 key
|
||||
* @param {number} [pg=1] 翻页 page
|
||||
* @param {*} t 分类 type
|
||||
* @returns
|
||||
*/
|
||||
list (key, pg = 1, t) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.getSite(key).then(res => {
|
||||
const site = res
|
||||
let url = null
|
||||
if (t) {
|
||||
url = `${site.api}?ac=videolist&t=${t}&pg=${pg}`
|
||||
} else {
|
||||
url = `${site.api}?ac=videolist&pg=${pg}`
|
||||
}
|
||||
axios.post(url).then(async res => {
|
||||
const data = res.data
|
||||
const json = parser.parse(data, this.xmlConfig)
|
||||
const jsondata = json.rss === undefined ? json : json.rss
|
||||
const videoList = jsondata.list.video
|
||||
resolve(videoList)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 获取总资源数, 以及页数
|
||||
* @param {*} key 资源网
|
||||
* @param {*} t 分类 type
|
||||
* @returns page object
|
||||
*/
|
||||
page (key, t) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.getSite(key).then(res => {
|
||||
const site = res
|
||||
let url = ''
|
||||
if (t) {
|
||||
url = `${site.api}?ac=videolist&t=${t}`
|
||||
} else {
|
||||
url = `${site.api}?ac=videolist`
|
||||
}
|
||||
axios.post(url).then(async res => {
|
||||
const data = res.data
|
||||
const json = parser.parse(data, this.xmlConfig)
|
||||
const jsondata = json.rss === undefined ? json : json.rss
|
||||
const pg = {
|
||||
page: jsondata.list._page,
|
||||
pagecount: jsondata.list._pagecount,
|
||||
pagesize: jsondata.list._pagesize,
|
||||
recordcount: jsondata.list._recordcount
|
||||
}
|
||||
resolve(pg)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 搜索资源
|
||||
* @param {*} key 资源网 key
|
||||
* @param {*} wd 搜索关键字
|
||||
* @returns
|
||||
*/
|
||||
search (key, wd) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.getSite(key).then(res => {
|
||||
const site = res
|
||||
wd = encodeURI(wd)
|
||||
var url = `${site.api}?wd=${wd}`
|
||||
axios.post(url, { timeout: 3000 }).then(res => {
|
||||
const data = res.data
|
||||
const json = parser.parse(data, this.xmlConfig)
|
||||
const jsondata = json.rss === undefined ? json : json.rss
|
||||
if (json && jsondata && jsondata.list) {
|
||||
const videoList = jsondata.list.video
|
||||
resolve(videoList)
|
||||
}
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 获取资源详情
|
||||
* @param {*} key 资源网 key
|
||||
* @param {*} id 资源唯一标识符 id
|
||||
* @returns
|
||||
*/
|
||||
detail (key, id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.getSite(key).then(res => {
|
||||
const url = `${res.api}?ac=videolist&ids=${id}`
|
||||
axios.post(url).then(res => {
|
||||
const data = res.data
|
||||
const json = parser.parse(data, this.xmlConfig)
|
||||
const jsondata = json.rss === undefined ? json : json.rss
|
||||
const videoList = jsondata.list.video
|
||||
// Parse m3u8List
|
||||
var m3u8List = []
|
||||
const dd = videoList.dl.dd
|
||||
const type = Object.prototype.toString.call(dd)
|
||||
if (type === '[object Array]') {
|
||||
for (const i of dd) {
|
||||
m3u8List = i._t.split('#')
|
||||
}
|
||||
} else {
|
||||
m3u8List = dd._t.split('#')
|
||||
}
|
||||
videoList.m3u8List = m3u8List
|
||||
resolve(videoList)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 下载资源
|
||||
* @param {*} key 资源网 key
|
||||
* @param {*} id 资源唯一标识符 id
|
||||
* @returns
|
||||
*/
|
||||
download (key, id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.getSite(key).then(res => {
|
||||
const site = res
|
||||
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)
|
||||
const jsondata = json.rss === undefined ? json : json.rss
|
||||
const videoList = jsondata.list.video
|
||||
// Parse m3u8List
|
||||
var m3u8List = []
|
||||
const dd = videoList.dl.dd
|
||||
const type = Object.prototype.toString.call(dd)
|
||||
if (type === '[object Array]') {
|
||||
for (const i of dd) {
|
||||
m3u8List = i._t.split('#')
|
||||
}
|
||||
} else {
|
||||
m3u8List = dd._t.split('#')
|
||||
}
|
||||
videoList.m3u8List = m3u8List
|
||||
resolve(videoList)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
} else {
|
||||
resolve([])
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 检查资源
|
||||
* @param {*} key 资源网 key
|
||||
* @returns boolean
|
||||
*/
|
||||
async check (key, id) {
|
||||
try {
|
||||
const cls = await this.class(key)
|
||||
if (cls) {
|
||||
return true
|
||||
} else {
|
||||
url = site.view.replace(/{id}/, id).replace(/{page}/, page)
|
||||
return false
|
||||
}
|
||||
const type = site.type
|
||||
axios.get(url).then(async res => {
|
||||
const data = res.data
|
||||
if (type === 0) {
|
||||
const zeroData = await this.film_get_type_zero(data, key)
|
||||
resolve(zeroData)
|
||||
} 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)
|
||||
}
|
||||
if (type === 1) {
|
||||
const oneData = await this.film_get_type_one(data, key)
|
||||
resolve(oneData)
|
||||
}).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 (type === 2) {
|
||||
const twoData = await this.film_get_type_two(data, key)
|
||||
resolve(twoData)
|
||||
}
|
||||
if (type === 3) {
|
||||
const threeData = await this.film_get_type_three(data, key)
|
||||
resolve(threeData)
|
||||
if (link) {
|
||||
resolve(link)
|
||||
} else {
|
||||
// 如果没找到符合的链接,返回搜索页面
|
||||
resolve(doubanSearchLink)
|
||||
}
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
film_get_type_zero (txt, key) {
|
||||
/**
|
||||
* 获取豆瓣评分
|
||||
* @param {*} name 视频名称
|
||||
* @returns 豆瓣评分
|
||||
*/
|
||||
doubanRate (name) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const parser = new DOMParser()
|
||||
const html = parser.parseFromString(txt, 'text/html')
|
||||
const list = html.querySelectorAll('.xing_vb li')
|
||||
const d = { list: [], total: 0, update: 0 }
|
||||
const url = getSite(key).url
|
||||
for (let i = 1; i < list.length - 1; i++) {
|
||||
const info = {
|
||||
site: key,
|
||||
name: list[i].childNodes[1].innerText,
|
||||
type: list[i].childNodes[3].innerText,
|
||||
time: list[i].childNodes[5].innerText,
|
||||
detail: url + list[i].childNodes[1].querySelector('a').getAttribute('href'),
|
||||
index: 0
|
||||
}
|
||||
d.list.push(info)
|
||||
}
|
||||
d.update = parseInt(html.querySelectorAll('.xing_top_right li strong')[0].innerText)
|
||||
let t = html.querySelector('.pages').innerText
|
||||
t = t.split('条')[0]
|
||||
t = t.split('共')[1]
|
||||
d.total = parseInt(t)
|
||||
resolve(d)
|
||||
} catch (err) {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
},
|
||||
film_get_type_one (txt, key) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const parser = new DOMParser()
|
||||
const html = parser.parseFromString(txt, 'text/html')
|
||||
const list = html.querySelectorAll('.videoContent li')
|
||||
const d = { list: [], total: 0, update: 0 }
|
||||
const url = getSite(key).url
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const info = {
|
||||
site: key,
|
||||
name: list[i].querySelector('.videoName').innerText,
|
||||
type: list[i].querySelector('.category').innerText,
|
||||
time: list[i].querySelector('.time').innerText,
|
||||
detail: url + list[i].querySelector('.address').getAttribute('href'),
|
||||
index: 0
|
||||
}
|
||||
d.list.push(info)
|
||||
}
|
||||
d.update = parseInt(html.querySelectorAll('.header_list li span')[0].innerText)
|
||||
let t = html.querySelectorAll('.pagination li')
|
||||
t = t[t.length - 2].innerText
|
||||
d.total = parseInt(t) * 50
|
||||
resolve(d)
|
||||
} catch (err) {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
},
|
||||
film_get_type_two (txt, key) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const parser = new DOMParser()
|
||||
const html = parser.parseFromString(txt, 'text/html')
|
||||
const list = html.querySelectorAll('.nr')
|
||||
const d = { list: [], total: 0, update: 0 }
|
||||
const url = getSite(key).url
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const info = {
|
||||
site: key,
|
||||
name: '',
|
||||
type: list[i].querySelector('.btn_span').innerText,
|
||||
time: list[i].querySelector('.hours').innerText,
|
||||
detail: url + list[i].querySelector('.name').getAttribute('href'),
|
||||
index: 0
|
||||
}
|
||||
let name = list[i].querySelector('.name').innerText
|
||||
name = name.replace(/^\s*|\s*$/g, '')
|
||||
info.name = name
|
||||
d.list.push(info)
|
||||
}
|
||||
d.update = parseInt(html.querySelector('.kfs em').innerText)
|
||||
d.total = parseInt(html.querySelector('.date span').innerText)
|
||||
let t = html.querySelector('.pag2').innerText
|
||||
t = t.split('条')[0]
|
||||
t = t.split('共')[1]
|
||||
d.total = parseInt(t)
|
||||
resolve(d)
|
||||
} catch (err) {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
},
|
||||
film_get_type_three (txt, key) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const parser = new DOMParser()
|
||||
const html = parser.parseFromString(txt, 'text/html')
|
||||
const list = html.querySelectorAll('.xing_vb li')
|
||||
const d = { list: [], total: 0, update: 0 }
|
||||
const url = getSite(key).url
|
||||
for (let i = 1; i < list.length - 1; i++) {
|
||||
const info = {
|
||||
site: key,
|
||||
name: list[i].childNodes[1].innerText,
|
||||
type: list[i].childNodes[2].innerText,
|
||||
time: list[i].childNodes[3].innerText,
|
||||
detail: url + list[i].childNodes[1].querySelector('a').getAttribute('href'),
|
||||
index: 0
|
||||
}
|
||||
d.list.push(info)
|
||||
}
|
||||
d.update = parseInt(html.querySelectorAll('.xing_top_right li strong')[0].innerText)
|
||||
let t = html.querySelector('.pages').innerText
|
||||
t = t.split('条')[0]
|
||||
t = t.split('共')[1]
|
||||
d.total = parseInt(t)
|
||||
resolve(d)
|
||||
} catch (err) {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
},
|
||||
// 获取详情
|
||||
detail_get (key, url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const type = getSite(key).type
|
||||
axios.get(url).then(async res => {
|
||||
if (type === 0) {
|
||||
const zeroData = await this.detail_get_type_zero(res.data, key)
|
||||
resolve(zeroData)
|
||||
}
|
||||
if (type === 1) {
|
||||
const oneData = await this.detail_get_type_one(res.data, key)
|
||||
resolve(oneData)
|
||||
}
|
||||
if (type === 2) {
|
||||
const twoData = await this.detail_get_type_two(res.data, key)
|
||||
resolve(twoData)
|
||||
}
|
||||
if (type === 3) {
|
||||
const threeData = await this.detail_get_type_three(res.data, key)
|
||||
resolve(threeData)
|
||||
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)
|
||||
})
|
||||
})
|
||||
},
|
||||
detail_get_type_zero (txt, key) {
|
||||
async proxy () {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const parser = new DOMParser()
|
||||
const html = parser.parseFromString(txt, 'text/html')
|
||||
const data = {
|
||||
site: key,
|
||||
name: '',
|
||||
info: '',
|
||||
desc: '',
|
||||
m3u8_urls: [],
|
||||
mp4_urls: []
|
||||
}
|
||||
const vodBox = html.querySelector('.vodBox')
|
||||
data.info = vodBox.innerHTML
|
||||
const title = html.querySelector('.vodh h2').innerText
|
||||
const index = html.querySelector('.vodh span').innerText
|
||||
data.name = title + index
|
||||
const vodInfo = html.querySelectorAll('.playBox')
|
||||
for (let i = 0; i < vodInfo.length; i++) {
|
||||
const k = vodInfo[i].innerText
|
||||
if (k.indexOf('剧情介绍') >= 0) {
|
||||
data.desc = vodInfo[i].querySelector('.vodplayinfo').innerText
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
const vodLi = html.querySelectorAll('.ibox .vodplayinfo li')
|
||||
const m3u8UrlArr = []
|
||||
const mp4UrlArr = []
|
||||
for (let i = 0; i < vodLi.length; i++) {
|
||||
const j = vodLi[i].innerText
|
||||
if (j.indexOf('.m3u8') >= 0) {
|
||||
m3u8UrlArr.push(j)
|
||||
}
|
||||
if (j.indexOf('.mp4') >= 0) {
|
||||
mp4UrlArr.push(j)
|
||||
}
|
||||
}
|
||||
data.m3u8_urls = m3u8UrlArr
|
||||
data.mp4_urls = mp4UrlArr
|
||||
resolve(data)
|
||||
} catch (err) {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
},
|
||||
detail_get_type_one (txt, key) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const parser = new DOMParser()
|
||||
const html = parser.parseFromString(txt, 'text/html')
|
||||
const data = {
|
||||
site: key,
|
||||
name: '',
|
||||
info: '',
|
||||
desc: '',
|
||||
m3u8_urls: [],
|
||||
mp4_urls: []
|
||||
}
|
||||
let name = html.querySelector('.whitetitle').innerText
|
||||
name = name.split(':')[1].replace(/^\s*|\s*$/g, '')
|
||||
data.name = name
|
||||
const vodBox = html.querySelector('.white').innerHTML
|
||||
data.info = vodBox
|
||||
const vodInfo = html.querySelectorAll('.white')
|
||||
for (let i = 0; i < vodInfo.length; i++) {
|
||||
const k = vodInfo[i].innerText
|
||||
if (k.indexOf('剧情介绍') >= 0) {
|
||||
data.desc = vodInfo[i].querySelector('div').innerText
|
||||
}
|
||||
}
|
||||
const vodLi = html.querySelectorAll('.playlist li #m3u8')
|
||||
const m3u8UrlArr = []
|
||||
const mp4UrlArr = []
|
||||
for (let i = 0; i < vodLi.length; i++) {
|
||||
const j = vodLi[i].value
|
||||
if (j.indexOf('.m3u8') >= 0) {
|
||||
m3u8UrlArr.push(j)
|
||||
}
|
||||
if (j.indexOf('.mp4') >= 0) {
|
||||
mp4UrlArr.push(j)
|
||||
}
|
||||
}
|
||||
data.m3u8_urls = m3u8UrlArr
|
||||
data.mp4_urls = mp4UrlArr
|
||||
resolve(data)
|
||||
} catch (err) {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
},
|
||||
detail_get_type_two (txt, key) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const parser = new DOMParser()
|
||||
const html = parser.parseFromString(txt, 'text/html')
|
||||
const data = {
|
||||
site: key,
|
||||
name: '',
|
||||
info: '',
|
||||
desc: '',
|
||||
m3u8_urls: [],
|
||||
mp4_urls: []
|
||||
}
|
||||
const title = html.querySelector('.vodh h2').innerText
|
||||
const index = html.querySelector('.vodh span').innerText
|
||||
data.name = title + index
|
||||
const vodBox = html.querySelector('.vodBox').innerHTML
|
||||
data.info = vodBox
|
||||
data.desc = html.querySelector('.vodplayinfo').innerText
|
||||
const vodLi = html.querySelectorAll('.vodplayinfo li')
|
||||
const m3u8UrlArr = []
|
||||
const mp4UrlArr = []
|
||||
for (let i = 0; i < vodLi.length; i++) {
|
||||
const j = vodLi[i].innerText
|
||||
if (j.indexOf('.m3u8') >= 0) {
|
||||
m3u8UrlArr.push(j)
|
||||
}
|
||||
if (j.indexOf('.mp4') >= 0) {
|
||||
mp4UrlArr.push(j)
|
||||
}
|
||||
}
|
||||
data.m3u8_urls = m3u8UrlArr
|
||||
data.mp4_urls = mp4UrlArr
|
||||
resolve(data)
|
||||
} catch (err) {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
},
|
||||
detail_get_type_three (txt, key) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const parser = new DOMParser()
|
||||
const html = parser.parseFromString(txt, 'text/html')
|
||||
const data = {
|
||||
site: key,
|
||||
name: '',
|
||||
info: '',
|
||||
desc: '',
|
||||
m3u8_urls: [],
|
||||
mp4_urls: []
|
||||
}
|
||||
const vodBox = html.querySelector('.vodBox')
|
||||
data.info = vodBox.innerHTML
|
||||
const title = html.querySelector('.vodh h2').innerText
|
||||
const index = html.querySelector('.vodh span').innerText
|
||||
data.name = title + index
|
||||
const vodInfo = html.querySelectorAll('.playBox')
|
||||
for (let i = 0; i < vodInfo.length; i++) {
|
||||
const k = vodInfo[i].innerText
|
||||
if (k.indexOf('剧情介绍') >= 0) {
|
||||
data.desc = vodInfo[i].querySelector('.vodplayinfo').innerHTML
|
||||
}
|
||||
}
|
||||
const vodLi = html.querySelectorAll('.ibox .vodplayinfo li')
|
||||
const m3u8UrlArr = []
|
||||
const mp4UrlArr = []
|
||||
for (let i = 0; i < vodLi.length; i++) {
|
||||
const j = vodLi[i].innerText
|
||||
if (j.indexOf('.m3u8') >= 0) {
|
||||
m3u8UrlArr.unshift(j)
|
||||
}
|
||||
if (j.indexOf('.mp4') >= 0) {
|
||||
mp4UrlArr.unshift(j)
|
||||
}
|
||||
}
|
||||
data.m3u8_urls = m3u8UrlArr
|
||||
data.mp4_urls = mp4UrlArr
|
||||
resolve(data)
|
||||
} catch (err) {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
},
|
||||
// 搜索列表
|
||||
search_get (key, keywords = '', page = 1) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const site = getSite(key)
|
||||
const type = site.type
|
||||
let url = null
|
||||
if (type === 0) {
|
||||
url = site.search.replace(/{page}/, page).replace(/{keywords}/, keywords)
|
||||
}
|
||||
if (type === 1) {
|
||||
url = site.search.replace(/{keywords}/, keywords)
|
||||
}
|
||||
axios.get(url).then(async res => {
|
||||
const data = res.data
|
||||
if (type === 0) {
|
||||
const zeroData = await this.search_get_type_zero(data, key)
|
||||
resolve(zeroData)
|
||||
}
|
||||
if (type === 1) {
|
||||
const oneData = await this.search_get_type_one(data, key)
|
||||
resolve(oneData)
|
||||
}
|
||||
if (type === 3) {
|
||||
const threeData = await this.search_get_type_three(data, key)
|
||||
resolve(threeData)
|
||||
}
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
// 不要删了,留着测试用
|
||||
// axios.get('https://api.my-ip.io/ip').then(res => console.log(res))
|
||||
})
|
||||
})
|
||||
},
|
||||
search_get_type_zero (txt, key) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const parser = new DOMParser()
|
||||
const html = parser.parseFromString(txt, 'text/html')
|
||||
const list = html.querySelectorAll('.xing_vb li')
|
||||
const d = { list: [], total: 0 }
|
||||
const url = getSite(key).url
|
||||
for (let i = 1; i < list.length - 1; i++) {
|
||||
const info = {
|
||||
site: key,
|
||||
name: list[i].childNodes[1].innerText,
|
||||
type: list[i].childNodes[3].innerText,
|
||||
time: list[i].childNodes[5].innerText,
|
||||
detail: url + list[i].childNodes[1].querySelector('a').getAttribute('href'),
|
||||
index: 0
|
||||
}
|
||||
d.list.push(info)
|
||||
}
|
||||
const t = html.querySelector('.nvc dd').innerText.replace(/[^\d]/g, '')
|
||||
d.total = parseInt(t)
|
||||
resolve(d)
|
||||
} catch (err) {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
},
|
||||
search_get_type_one (txt, key) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const parser = new DOMParser()
|
||||
const html = parser.parseFromString(txt, 'text/html')
|
||||
const list = html.querySelectorAll('.videoContent li')
|
||||
const d = { list: [], total: 0 }
|
||||
const url = getSite(key).url
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const info = {
|
||||
site: key,
|
||||
name: list[i].querySelector('.videoName').innerText,
|
||||
type: list[i].querySelector('.category').innerText,
|
||||
time: list[i].querySelector('.time').innerText,
|
||||
detail: url + list[i].querySelector('.address').getAttribute('href'),
|
||||
index: 0
|
||||
}
|
||||
d.list.push(info)
|
||||
}
|
||||
d.total = list.length
|
||||
resolve(d)
|
||||
} catch (err) {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
},
|
||||
search_get_type_three (txt, key) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const parser = new DOMParser()
|
||||
const html = parser.parseFromString(txt, 'text/html')
|
||||
const list = html.querySelectorAll('.xing_vb li')
|
||||
const d = { list: [], total: 0 }
|
||||
const url = getSite(key).url
|
||||
for (let i = 1; i < list.length - 1; i++) {
|
||||
const info = {
|
||||
site: key,
|
||||
name: list[i].childNodes[1].innerText,
|
||||
type: list[i].childNodes[2].innerText,
|
||||
time: list[i].childNodes[3].innerText,
|
||||
detail: url + list[i].childNodes[1].querySelector('a').getAttribute('href'),
|
||||
index: 0
|
||||
}
|
||||
d.list.push(info)
|
||||
}
|
||||
const t = html.querySelector('.nvc dd').innerText.replace(/[^\d]/g, '')
|
||||
d.total = parseInt(t)
|
||||
resolve(d)
|
||||
} catch (err) {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
zy.proxy()
|
||||
|
||||
export default zy
|
||||
|
||||
48
src/lib/update/update.js
Normal file
48
src/lib/update/update.js
Normal file
@@ -0,0 +1,48 @@
|
||||
import { BrowserWindow, ipcMain } from 'electron'
|
||||
import { autoUpdater } from 'electron-updater'
|
||||
|
||||
export function initUpdater (win = BrowserWindow) {
|
||||
autoUpdater.autoDownload = false
|
||||
autoUpdater.autoInstallOnAppQuit = false
|
||||
|
||||
// 主进程监听检查更新事件
|
||||
ipcMain.on('checkForUpdate', () => {
|
||||
autoUpdater.checkForUpdates()
|
||||
})
|
||||
|
||||
// 主进程监听退出并安装事件
|
||||
ipcMain.on('quitAndInstall', () => {
|
||||
autoUpdater.downloadUpdate()
|
||||
})
|
||||
|
||||
// 开始检测是否有更新
|
||||
autoUpdater.on('checking-for-update', () => {
|
||||
win.webContents.send('checking-for-update')
|
||||
})
|
||||
|
||||
// 检测到有可用的更新
|
||||
autoUpdater.on('update-available', (info) => {
|
||||
win.webContents.send('update-available', info)
|
||||
})
|
||||
|
||||
// 没有检测到有可用的更新
|
||||
autoUpdater.on('update-not-available', () => {
|
||||
win.webContents.send('update-not-available')
|
||||
})
|
||||
|
||||
// 更新出错
|
||||
autoUpdater.on('update-error', err => {
|
||||
win.webContents.send('update-error', err)
|
||||
})
|
||||
|
||||
// 下载更新进度
|
||||
autoUpdater.on('download-progress', (progressObj) => {
|
||||
win.webContents.send('download-progress', progressObj)
|
||||
})
|
||||
|
||||
// 下载完成并退出安装
|
||||
autoUpdater.on('update-downloaded', () => {
|
||||
win.webContents.send('update-downloaded')
|
||||
autoUpdater.quitAndInstall()
|
||||
})
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
{
|
||||
"zh": "Chinese",
|
||||
"en": "English",
|
||||
"language": "Language",
|
||||
"default_site": "Default Site",
|
||||
"view": "View",
|
||||
"play": "Play",
|
||||
"star": "Star",
|
||||
"setting": "Setting",
|
||||
"exists": "Already exists",
|
||||
"videoName": "Video Name",
|
||||
"type": "Type",
|
||||
"time": "Time",
|
||||
"operate": "Operate",
|
||||
"share": "Share",
|
||||
"detail": "Detail",
|
||||
"close": "Close",
|
||||
"download": "Download",
|
||||
"all_download": "All Download",
|
||||
"next": "Next",
|
||||
"play_list": "Play List",
|
||||
"history": "History",
|
||||
"top": "Top",
|
||||
"mini": "Mini",
|
||||
"no_data": "No Data",
|
||||
"clear_data": "Clear Data",
|
||||
"delete": "Delete",
|
||||
"from": "From",
|
||||
"sync": "Sync",
|
||||
"total": "Items",
|
||||
"website": "Official Website",
|
||||
"issues": "Issues",
|
||||
"theme": "Theme",
|
||||
"donate": "Donate",
|
||||
"set_success": "Set up successfully.",
|
||||
"delete_success": "Delete successful.",
|
||||
"delete_failed": "Delete failed.",
|
||||
"star_success": "Collection success.",
|
||||
"first_video": "This is the first episode.",
|
||||
"last_video": "This is the last episode.",
|
||||
"qr_tips": "Long click recognition.",
|
||||
"zy_tips": "Prohibit the dissemination of illegal resources.",
|
||||
"share_tips": "It has been copied to the clipboard. Please share it~",
|
||||
"not_support_search": "Search is not supported on this site.",
|
||||
"copy_success": "has been copied, Download it now",
|
||||
"async_failed": "Synchronization successful, no updates found.",
|
||||
"async_success": "Synchronization succeeded, update found.",
|
||||
"no_history": "No history data.",
|
||||
"clearDB": "Reset software",
|
||||
"clearTips": "Click to clear the database and close the software",
|
||||
"rate": "The current video speed is: "
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import en from './en.json'
|
||||
import zhCn from './zh-cn'
|
||||
|
||||
export const defaultLocal = 'zhCn'
|
||||
|
||||
export const languages = {
|
||||
en: en,
|
||||
zhCn: zhCn
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
{
|
||||
"zh": "中文",
|
||||
"en": "英文",
|
||||
"language": "语言",
|
||||
"default_site": "默认源",
|
||||
"view": "浏览",
|
||||
"play": "播放",
|
||||
"star": "收藏",
|
||||
"setting": "设置",
|
||||
"exists": "已存在",
|
||||
"videoName": "视频名称",
|
||||
"type": "类型",
|
||||
"time": "时间",
|
||||
"operate": "操作",
|
||||
"share": "分享",
|
||||
"detail": "详情",
|
||||
"close": "关闭",
|
||||
"download": "下载",
|
||||
"all_download": "全集下载",
|
||||
"next": "下一集",
|
||||
"play_list": "播放列表",
|
||||
"history": "历史记录",
|
||||
"top": "置顶",
|
||||
"mini": "精简模式",
|
||||
"no_data": "无数据",
|
||||
"clear_data": "清空数据",
|
||||
"delete": "删除",
|
||||
"from": "来源",
|
||||
"sync": "同步",
|
||||
"total": "条数据",
|
||||
"website": "官网",
|
||||
"issues": "反馈",
|
||||
"theme": "主题",
|
||||
"donate": "捐赠",
|
||||
"set_success": "设置成功。",
|
||||
"delete_success": "删除成功。",
|
||||
"delete_failed": "删除失败。",
|
||||
"star_success": "收藏成功。",
|
||||
"first_video": "这已经是第一集了。",
|
||||
"last_video": "这已经是最后一集了。",
|
||||
"qr_tips": "长按二维码,识别播放。",
|
||||
"zy_tips": "『ZY Player』技术支持,严禁传播违法资源。",
|
||||
"share_tips": "已复制到剪贴板,快去分享吧~ 严禁传播违法资源!!!",
|
||||
"not_support_search": "这个网站不支持搜索。",
|
||||
"copy_success": "已复制,快去下载吧。",
|
||||
"async_failed": "同步成功, 未查询到更新。",
|
||||
"async_success": "同步成功, 查询到更新。",
|
||||
"no_history": "无历史记录",
|
||||
"clearDB": "重置软件",
|
||||
"clearTips": "软件没有问题,请勿重置软件,否则数据丢失概不负责.点击即清空数据库,并关闭软件.",
|
||||
"rate": "当前视频播放倍速为:"
|
||||
}
|
||||
15
src/main.js
15
src/main.js
@@ -3,24 +3,11 @@ import App from './App.vue'
|
||||
import store from './store'
|
||||
import 'modern-normalize'
|
||||
import Register from './components/register'
|
||||
import VueI18n from 'vue-i18n'
|
||||
import { languages, defaultLocal } from './locales/index'
|
||||
import './lib/element/index'
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
Register.registerComponents()
|
||||
|
||||
Vue.use(VueI18n)
|
||||
const messages = Object.assign(languages)
|
||||
const i18n = new VueI18n({
|
||||
locale: defaultLocal,
|
||||
fallbackLocale: 'zhCn',
|
||||
messages
|
||||
})
|
||||
|
||||
Vue.config.productionTip = false
|
||||
new Vue({
|
||||
store,
|
||||
i18n,
|
||||
render: h => h(App)
|
||||
}).$mount('#app')
|
||||
|
||||
@@ -1,337 +0,0 @@
|
||||
<template>
|
||||
<div class="mini">
|
||||
<div class="top">
|
||||
<div class="left">
|
||||
<span class="number" v-show="length > 0">{{index + 1}} / {{length}}</span>
|
||||
<span class="zy-svg" @click="prevEvent" v-show="index > 0">
|
||||
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-labelledby="backIconTitle">
|
||||
<title id="backIconTitle">上一集</title>
|
||||
<path d="M14 14.74L21 19V5l-7 4.26V5L2 12l12 7v-4.26z"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="zy-svg" @click="nextEvent" v-show="index < (length - 1)">
|
||||
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-labelledby="forwardIconTitle">
|
||||
<title id="forwardIconTitle">下一集</title>
|
||||
<path d="M10 14.74L3 19V5l7 4.26V5l12 7-12 7v-4.26z"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="opacity">
|
||||
<input type="number" min="5" max="100" v-model="opacity" @change="opacityChange"/>
|
||||
</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
<span class="min" @click="frameClickEvent('miniMin')"></span>
|
||||
<span class="close" @click="frameClickEvent('miniClose')"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<div id="xg"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import tools from '../lib/site/tools'
|
||||
import mini from '../lib/dexie/mini'
|
||||
import history from '../lib/dexie/history'
|
||||
import 'xgplayer'
|
||||
import Hls from 'xgplayer-hls.js'
|
||||
const ipc = require('electron').ipcRenderer
|
||||
export default {
|
||||
name: 'mini',
|
||||
data () {
|
||||
return {
|
||||
xg: null,
|
||||
config: {
|
||||
id: 'xg',
|
||||
lang: 'zh-cn',
|
||||
url: '',
|
||||
fluid: true,
|
||||
autoplay: false,
|
||||
videoInit: true,
|
||||
screenShot: true,
|
||||
keyShortcut: 'on',
|
||||
crossOrigin: true,
|
||||
defaultPlaybackRate: 1,
|
||||
playbackRate: [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 3, 4, 5]
|
||||
},
|
||||
opacity: 100,
|
||||
video: {},
|
||||
d: {},
|
||||
index: 0,
|
||||
length: 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
frameClickEvent (e) {
|
||||
ipc.send(e)
|
||||
},
|
||||
opacityChange (e) {
|
||||
ipc.send('miniOpacity', this.opacity / 100)
|
||||
},
|
||||
getUrls () {
|
||||
mini.find().then(res => {
|
||||
const v = res
|
||||
this.video = res
|
||||
tools.detail_get(v.site, v.detail).then(res => {
|
||||
this.d = res
|
||||
this.index = v.index
|
||||
this.length = this.d.m3u8_urls.length
|
||||
const link = res.m3u8_urls[v.index]
|
||||
const src = link.split('$')[1]
|
||||
this.xg.src = src
|
||||
const currentTime = v.currentTime
|
||||
if (currentTime !== '') {
|
||||
this.xg.play()
|
||||
this.xg.once('playing', () => {
|
||||
this.xg.currentTime = currentTime
|
||||
})
|
||||
} else {
|
||||
this.xg.play()
|
||||
}
|
||||
this.onPlayVideo()
|
||||
this.xg.on('ended', () => {
|
||||
if (this.d.m3u8_urls.length > 1 && (this.d.m3u8_urls.length - 1 > this.index)) {
|
||||
this.video.currentTime = 0
|
||||
this.video.index++
|
||||
this.index++
|
||||
let src = this.d.m3u8_urls[this.index]
|
||||
src = src.split('$')[1]
|
||||
this.xg.src = src
|
||||
this.xg.play()
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
onPlayVideo () {
|
||||
const h = { ...this.video }
|
||||
history.find({ detail: h.detail }).then(res => {
|
||||
if (res) {
|
||||
h.id = res.id
|
||||
history.update(res.id, h)
|
||||
} else {
|
||||
h.currentTime = ''
|
||||
delete h.id
|
||||
history.add(h)
|
||||
}
|
||||
})
|
||||
this.timerEvent(h.detail)
|
||||
},
|
||||
timerEvent (d) {
|
||||
this.timer = setInterval(() => {
|
||||
history.find({ detail: d }).then(res => {
|
||||
if (res) {
|
||||
const v = res
|
||||
v.currentTime = this.xg.currentTime
|
||||
v.index = this.index
|
||||
const id = v.id
|
||||
delete v.id
|
||||
history.update(id, v)
|
||||
}
|
||||
})
|
||||
}, 10000)
|
||||
},
|
||||
prevEvent () {
|
||||
if (this.index === 0) {
|
||||
return false
|
||||
}
|
||||
history.find({ detail: this.video.detail }).then(res => {
|
||||
const v = res
|
||||
v.index--
|
||||
const id = v.id
|
||||
delete v.id
|
||||
history.update(id, v).then(e => {
|
||||
let src = this.d.m3u8_urls[v.index]
|
||||
src = src.split('$')[1]
|
||||
this.xg.src = src
|
||||
this.index--
|
||||
})
|
||||
})
|
||||
},
|
||||
nextEvent () {
|
||||
if (this.index >= this.d.m3u8_urls.length - 1) {
|
||||
return false
|
||||
}
|
||||
history.find({ detail: this.video.detail }).then(res => {
|
||||
const v = res
|
||||
v.index++
|
||||
const id = v.id
|
||||
delete v.id
|
||||
history.update(id, v).then(e => {
|
||||
let src = this.d.m3u8_urls[v.index]
|
||||
src = src.split('$')[1]
|
||||
this.xg.src = src
|
||||
this.index++
|
||||
})
|
||||
})
|
||||
},
|
||||
playbackRateEvent (e) {
|
||||
let rate = this.xg.playbackRate
|
||||
if (rate > 0.25) {
|
||||
rate = rate + e
|
||||
this.xg.playbackRate = rate
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getUrls()
|
||||
},
|
||||
mounted () {
|
||||
this.xg = new Hls(this.config)
|
||||
ipc.on('next', () => {
|
||||
if (this.xg) {
|
||||
if (this.xg.hasStart) {
|
||||
this.nextEvent()
|
||||
}
|
||||
}
|
||||
})
|
||||
ipc.on('prev', () => {
|
||||
if (this.xg) {
|
||||
if (this.xg.hasStart) {
|
||||
this.prevEvent()
|
||||
}
|
||||
}
|
||||
})
|
||||
ipc.on('up', () => {
|
||||
if (this.opacity <= 95) {
|
||||
this.opacity = this.opacity + 5
|
||||
this.opacityChange(this.opacity)
|
||||
}
|
||||
})
|
||||
ipc.on('down', () => {
|
||||
if (this.opacity >= 10) {
|
||||
this.opacity = this.opacity - 5
|
||||
this.opacityChange(this.opacity)
|
||||
}
|
||||
})
|
||||
ipc.on('playbackRateUp', () => {
|
||||
if (this.xg) {
|
||||
if (this.xg.hasStart) {
|
||||
this.playbackRateEvent(0.25)
|
||||
}
|
||||
}
|
||||
})
|
||||
ipc.on('playbackRateDown', () => {
|
||||
if (this.xg) {
|
||||
if (this.xg.hasStart) {
|
||||
this.playbackRateEvent(-0.25)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
html,body{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
background-color: #000;
|
||||
}
|
||||
.mini{
|
||||
box-sizing: border-box;
|
||||
.top{
|
||||
-webkit-app-region: drag;
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
user-select: none;
|
||||
.zy-svg{
|
||||
-webkit-app-region: no-drag;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
svg{
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
stroke: #fff;
|
||||
stroke-width: 1;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
fill: none;
|
||||
}
|
||||
}
|
||||
.left{
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
.number{
|
||||
color: #fff;
|
||||
margin: 0 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.opacity{
|
||||
-webkit-app-region: no-drag;
|
||||
margin-left: 10px;
|
||||
input{
|
||||
text-indent: 4px;
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
border: 1px solid #aaa;
|
||||
}
|
||||
}
|
||||
}
|
||||
.right{
|
||||
width: 80px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
span{
|
||||
-webkit-app-region: no-drag;
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
margin-right: 10px;
|
||||
cursor: pointer;
|
||||
opacity: 0.5;
|
||||
&.min{
|
||||
background-color: #ffbe2a;
|
||||
}
|
||||
&.close{
|
||||
background-color: #ff5f56;
|
||||
}
|
||||
&:hover{
|
||||
animation: heartbeat 3s ease-in-out infinite both;
|
||||
}
|
||||
@keyframes heartbeat {
|
||||
from {
|
||||
transform: scale(1);
|
||||
transform-origin: center center;
|
||||
animation-timing-function: ease-out;
|
||||
}
|
||||
10% {
|
||||
opacity: 1;
|
||||
transform: scale(0.91);
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
17% {
|
||||
transform: scale(0.98);
|
||||
animation-timing-function: ease-out;
|
||||
}
|
||||
33% {
|
||||
transform: scale(0.87);
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
45% {
|
||||
transform: scale(1);
|
||||
animation-timing-function: ease-out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.bottom{
|
||||
width: 100%;
|
||||
height: 305px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
import Mini from './Mini'
|
||||
Vue.config.productionTip = false
|
||||
|
||||
new Vue({
|
||||
render: h => h(Mini)
|
||||
}).$mount('#app')
|
||||
@@ -6,63 +6,68 @@ Vue.use(Vuex)
|
||||
export default new Vuex.Store({
|
||||
state: {
|
||||
view: 'Film',
|
||||
theme: 'light',
|
||||
site: 'zuidazy',
|
||||
language: 'zhCn',
|
||||
setting: {
|
||||
theme: 'light',
|
||||
site: 'zuidazy',
|
||||
view: 'picture',
|
||||
shortcut: true
|
||||
},
|
||||
detail: {
|
||||
show: false,
|
||||
v: {}
|
||||
key: '',
|
||||
info: {}
|
||||
},
|
||||
share: {
|
||||
show: false,
|
||||
v: {}
|
||||
key: '',
|
||||
info: {}
|
||||
},
|
||||
video: {}
|
||||
video: {
|
||||
key: '',
|
||||
info: {}
|
||||
},
|
||||
appState: {
|
||||
windowIsOnTop: false
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
getView: state => {
|
||||
return state.view
|
||||
},
|
||||
getTheme: state => {
|
||||
return state.theme
|
||||
},
|
||||
getSite: state => {
|
||||
return state.site
|
||||
},
|
||||
getLanguage: state => {
|
||||
return state.language
|
||||
getSetting: state => {
|
||||
return state.setting
|
||||
},
|
||||
getDetail: state => {
|
||||
return state.detail
|
||||
},
|
||||
getShare: state => {
|
||||
return state.share
|
||||
},
|
||||
getVideo: state => {
|
||||
return state.video
|
||||
},
|
||||
getShare: state => {
|
||||
return state.share
|
||||
getAppState: state => {
|
||||
return state.appState
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
SET_VIEW: (state, payload) => {
|
||||
state.view = payload
|
||||
},
|
||||
SET_THEME: (state, payload) => {
|
||||
state.theme = payload
|
||||
},
|
||||
SET_SITE: (state, payload) => {
|
||||
state.site = payload
|
||||
},
|
||||
SET_LANGUAGE: (state, payload) => {
|
||||
state.language = payload
|
||||
SET_SETTING: (state, payload) => {
|
||||
state.setting = payload
|
||||
},
|
||||
SET_DETAIL: (state, payload) => {
|
||||
state.detail = payload
|
||||
},
|
||||
SET_SHARE: (state, payload) => {
|
||||
state.share = payload
|
||||
},
|
||||
SET_VIDEO: (state, payload) => {
|
||||
state.video = payload
|
||||
},
|
||||
SET_SHARE: (state, payload) => {
|
||||
state.share = payload
|
||||
SET_APPSTATE: (state, payload) => {
|
||||
state.appState = payload
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
module.exports = {
|
||||
pages: {
|
||||
index: 'src/main.js',
|
||||
mini: 'src/mini/main.js'
|
||||
index: 'src/main.js'
|
||||
},
|
||||
pluginOptions: {
|
||||
electronBuilder: {
|
||||
|
||||
Reference in New Issue
Block a user