mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-05-10 06:32:45 +08:00
Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc585a3900 | ||
|
|
973f8529c2 | ||
|
|
1ff9dc50fd | ||
|
|
065c9053da | ||
|
|
6905be1bcd | ||
|
|
a550f9616c | ||
|
|
bcee3e5373 | ||
|
|
d377ced6b6 | ||
|
|
6e0ceb093c | ||
|
|
745f99e52e | ||
|
|
7197034eda | ||
|
|
264748652f | ||
|
|
48e214564a | ||
|
|
5424e7e02a | ||
|
|
0c9c70b067 | ||
|
|
0ff24f4b09 | ||
|
|
cfa75b7643 | ||
|
|
b72ad1d78d | ||
|
|
5d1f293606 | ||
|
|
2dc0eca4aa | ||
|
|
f5808c1c81 | ||
|
|
321037477f | ||
|
|
43589c66e9 | ||
|
|
435f299a8b | ||
|
|
083db80251 | ||
|
|
92bf520cf4 | ||
|
|
ab354f21c4 | ||
|
|
c7a2c045c7 | ||
|
|
d33c8942e4 | ||
|
|
5e630097b9 | ||
|
|
3b5d03c1c8 | ||
|
|
298ae2c354 | ||
|
|
d936b68597 | ||
|
|
41471b9fd6 | ||
|
|
cc071c0911 | ||
|
|
628164d2bd | ||
|
|
999af85262 | ||
|
|
07e075ad8b | ||
|
|
18098f8aef |
347
index.html
347
index.html
@@ -1,161 +1,214 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="initial-scale=1, viewport-fit=cover, width=device-width, user-scalable=no" />
|
||||
<title>MoviePilot</title>
|
||||
<meta name="Robots" content="noindex,nofollow,noarchive" />
|
||||
<meta name="referrer" content="origin" />
|
||||
<link rel="icon" type="image/png" href="/logo.png" />
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
||||
<link rel="apple-touch-startup-image" href="/splash/apple-splash.jpg" />
|
||||
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
|
||||
<link rel="manifest" href="manifest.json" crossorigin="use-credentials" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
<meta name="apple-mobile-web-app-title" content="MoviePilot" />
|
||||
<meta name="description" content="MoviePilot" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<meta name="referrer" content="never" />
|
||||
<meta name="msapplication-TileColor" content="#7D34FD" />
|
||||
<meta name="color-scheme" content="light dark" />
|
||||
<meta name="theme-color" content="#28243D" media="(prefers-color-scheme: dark)" />
|
||||
<meta name="theme-color" content="#F4F5FA" media="(prefers-color-scheme: light)" />
|
||||
<meta name="HandheldFriendly" content="True" />
|
||||
<meta name="MobileOptimized" content="320" />
|
||||
<link rel="stylesheet" type="text/css" href="/loader.css" />
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="initial-scale=1, viewport-fit=cover, width=device-width, user-scalable=no" />
|
||||
<title>MoviePilot</title>
|
||||
<meta name="Robots" content="noindex,nofollow,noarchive">
|
||||
<meta name="referrer" content="origin">
|
||||
<link rel="icon" type="image/png" href="/logo.png">
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
|
||||
<link rel="apple-touch-startup-image" href="/splash/apple-splash.jpg">
|
||||
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
|
||||
<link rel="manifest" href="manifest.json" crossorigin="use-credentials">
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||
<meta name="apple-mobile-web-app-title" content="MoviePilot">
|
||||
<meta name="description" content="MoviePilot">
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="referrer" content="never">
|
||||
<meta name="msapplication-TileColor" content="#7D34FD" />
|
||||
<meta name="color-scheme" content="light dark">
|
||||
<meta name="theme-color" content="#28243D" media="(prefers-color-scheme: dark)">
|
||||
<meta name="theme-color" content="#F4F5FA" media="(prefers-color-scheme: light)">
|
||||
<meta name="HandheldFriendly" content="True" />
|
||||
<meta name="MobileOptimized" content="320" />
|
||||
<link rel="stylesheet" type="text/css" href="/loader.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="loading-bg">
|
||||
<div class="loading-logo">
|
||||
<!-- Logo -->
|
||||
<svg width="100px" height="100px" viewBox="0 0 192 192" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(1,0,0,1,-2606,-236)">
|
||||
<g id="a2-c" transform="matrix(1,0,0,1,2606,236)">
|
||||
<rect x="0" y="0" width="192" height="192" style="fill:none;" />
|
||||
<g transform="matrix(-0.800798,0.462341,-0.769972,-1.33363,1869.11,-896.718)">
|
||||
<path
|
||||
d="M2241.27,-28.175C2238.86,-28.931 2236.64,-29.181 2234.48,-29.254L2159.78,-29.286L2165.01,-11.207C2167.16,-13.121 2169.64,-13.722 2172.26,-13.808L2222.12,-13.822C2223.52,-13.824 2225,-13.701 2226.78,-13.108L2241.27,-28.175Z"
|
||||
style="fill:url(#_Linear1);" />
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,-2157.67,-208.423)">
|
||||
<path
|
||||
d="M2205.67,331.428L2205.67,332.25L2205.67,352.835C2205.67,354.263 2204.91,355.583 2203.67,356.298C2202.43,357.012 2200.91,357.013 2199.67,356.3L2190.78,351.174C2189.73,350.595 2188.83,350.083 2188.03,349.59L2187.45,349.257C2186.66,348.725 2185.91,348.142 2185.21,347.461C2185.08,347.331 2184.95,347.198 2184.82,347.061C2184.26,346.457 2183.75,345.778 2183.3,344.995C2182.16,343.05 2181.69,341.024 2181.68,338.948L2181.67,268.923L2209.77,274.425C2207.5,275.639 2205.68,278.3 2205.67,281.429L2205.67,331.428Z"
|
||||
style="fill:url(#_Linear2);" />
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,-2157.67,-208.423)">
|
||||
<path
|
||||
d="M2295.93,363.064C2299.48,360.882 2301.46,357.55 2301.67,352.926L2301.67,277.879L2301.67,276.775L2301.67,252.515C2301.67,251.801 2302.05,251.14 2302.67,250.783C2303.29,250.426 2304.05,250.426 2304.67,250.784L2319.81,259.54C2321.59,260.617 2322.95,262.115 2324.04,263.875C2325.03,265.551 2325.56,267.37 2325.67,269.835L2325.67,339.91C2325.18,343.645 2323.51,346.705 2320.3,348.887L2295.93,363.064ZM2295.93,363.064C2295.73,363.184 2295.53,363.301 2295.32,363.414L2295.93,363.064Z"
|
||||
style="fill:rgb(141,81,249);" />
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,-2157.67,-208.423)">
|
||||
<path
|
||||
d="M2295.93,363.064C2299.48,360.882 2301.46,357.55 2301.67,352.926L2301.67,277.879L2301.67,276.775L2301.67,252.515C2301.67,251.801 2302.05,251.14 2302.67,250.783C2303.29,250.426 2304.05,250.426 2304.67,250.784L2319.81,259.54C2321.59,260.617 2322.95,262.115 2324.04,263.875C2325.03,265.551 2325.56,267.37 2325.67,269.835L2325.67,339.91C2325.18,343.645 2323.51,346.705 2320.3,348.887L2295.93,363.064ZM2299.79,360.238C2299.79,360.238 2320.03,348.464 2320.04,348.461C2323.1,346.372 2324.69,343.444 2325.17,339.877C2325.17,339.877 2325.17,269.846 2325.17,269.839C2325.06,267.482 2324.56,265.739 2323.61,264.133C2322.56,262.445 2321.26,261.005 2319.55,259.97L2304.42,251.217C2303.96,250.949 2303.39,250.948 2302.92,251.216C2302.46,251.484 2302.17,251.979 2302.17,252.515L2302.17,276.775L2302.17,277.879L2302.17,352.926C2302.17,352.933 2302.17,352.941 2302.17,352.948C2302.04,355.861 2301.23,358.279 2299.79,360.238Z"
|
||||
style="fill:url(#_Linear3);" />
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,-2157.67,-208.423)">
|
||||
<path
|
||||
d="M2253.67,223.256C2255.26,223.245 2257.02,223.56 2259.11,224.557L2275.67,234.102C2276.91,234.816 2277.67,236.138 2277.67,237.568L2277.67,259.508C2277.67,260.222 2277.29,260.882 2276.67,261.239C2276.05,261.597 2275.29,261.597 2274.67,261.24L2257.52,251.353C2256.38,250.731 2255.12,250.341 2253.67,250.347C2252.26,250.339 2250.99,250.721 2249.82,251.353L2187.87,287.04C2184.23,289.147 2181.96,292.478 2181.67,297.57L2181.68,269.865C2181.85,265.167 2183.93,261.653 2187.92,259.322L2248.23,224.557C2249.69,223.796 2251.5,223.29 2253.67,223.256Z"
|
||||
style="fill:rgb(165,118,255);" />
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,-2157.67,-208.423)">
|
||||
<path
|
||||
d="M2253.67,223.256C2255.26,223.245 2257.02,223.56 2259.11,224.557L2275.67,234.102C2276.91,234.816 2277.67,236.138 2277.67,237.568L2277.67,259.508C2277.67,260.222 2277.29,260.882 2276.67,261.239C2276.05,261.597 2275.29,261.597 2274.67,261.24L2257.52,251.353C2256.38,250.731 2255.12,250.341 2253.67,250.347C2252.26,250.339 2250.99,250.721 2249.82,251.353L2187.87,287.04C2184.23,289.147 2181.96,292.478 2181.67,297.57L2181.68,269.865C2181.85,265.167 2183.93,261.653 2187.92,259.322L2248.23,224.557C2249.69,223.796 2251.5,223.29 2253.67,223.256ZM2253.68,223.756C2251.6,223.789 2249.87,224.269 2248.47,224.996L2188.17,259.754C2184.35,261.992 2182.35,265.367 2182.18,269.874C2182.18,269.874 2182.17,292.759 2182.17,292.757C2183.25,290.047 2185.13,288.051 2187.62,286.607L2249.57,250.919C2249.58,250.917 2249.58,250.915 2249.59,250.913C2250.83,250.243 2252.17,249.839 2253.67,249.847C2255.21,249.841 2256.54,250.253 2257.76,250.914C2257.76,250.916 2257.76,250.917 2257.76,250.919L2274.92,260.807C2275.38,261.075 2275.95,261.074 2276.42,260.806C2276.88,260.538 2277.17,260.043 2277.17,259.508L2277.17,237.568C2277.17,236.317 2276.5,235.16 2275.42,234.535C2275.42,234.535 2258.88,225 2258.87,224.996C2256.87,224.049 2255.2,223.746 2253.68,223.756Z"
|
||||
style="fill:url(#_Linear4);" />
|
||||
</g>
|
||||
<g transform="matrix(0.800798,0.462341,0.769972,-1.33363,-1677.22,-896.858)">
|
||||
<path
|
||||
d="M2241.55,-28.184C2239.1,-28.989 2236.83,-29.204 2234.68,-29.295C2234.68,-29.295 2220.82,-29.3 2215.03,-29.303C2213.48,-29.303 2212.05,-28.808 2211.28,-28.004C2208.65,-25.275 2202.56,-18.936 2199.45,-15.709C2199.07,-15.306 2199.07,-14.809 2199.46,-14.406C2199.85,-14.004 2200.57,-13.758 2201.34,-13.761C2208.36,-13.788 2222.72,-13.845 2222.72,-13.845C2223.98,-13.851 2225.44,-13.657 2227.06,-13.117L2241.55,-28.184Z"
|
||||
style="fill:rgb(141,81,249);" />
|
||||
</g>
|
||||
<g transform="matrix(-4.32309,0,0,12.4454,9610.35,-1450.35)">
|
||||
<path
|
||||
d="M2205.31,121.966C2205.31,121.88 2205.18,121.8 2204.96,121.757C2204.74,121.714 2204.48,121.714 2204.27,121.757C2201.75,122.263 2195.36,123.547 2192.85,124.052C2192.63,124.095 2192.5,124.174 2192.5,124.261C2192.5,124.347 2192.63,124.426 2192.85,124.469C2195.36,124.974 2201.75,126.255 2204.27,126.759C2204.48,126.802 2204.74,126.802 2204.96,126.759C2205.18,126.716 2205.31,126.636 2205.31,126.55C2205.31,125.541 2205.31,122.976 2205.31,121.966Z"
|
||||
style="fill:rgb(104,0,197);" />
|
||||
<clipPath id="_clip5">
|
||||
<path
|
||||
d="M2205.31,121.966C2205.31,121.88 2205.18,121.8 2204.96,121.757C2204.74,121.714 2204.48,121.714 2204.27,121.757C2201.75,122.263 2195.36,123.547 2192.85,124.052C2192.63,124.095 2192.5,124.174 2192.5,124.261C2192.5,124.347 2192.63,124.426 2192.85,124.469C2195.36,124.974 2201.75,126.255 2204.27,126.759C2204.48,126.802 2204.74,126.802 2204.96,126.759C2205.18,126.716 2205.31,126.636 2205.31,126.55C2205.31,125.541 2205.31,122.976 2205.31,121.966Z" />
|
||||
</clipPath>
|
||||
<g clip-path="url(#_clip5)">
|
||||
<g transform="matrix(0.124502,0.074907,0.206623,-0.0414384,1997.62,-7.40235)">
|
||||
<body>
|
||||
<div id="loading-bg">
|
||||
<div class="loading-logo">
|
||||
<!-- Logo -->
|
||||
<svg
|
||||
width="100px"
|
||||
height="100px"
|
||||
viewBox="0 0 192 192"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
style="fill-rule: evenodd; clip-rule: evenodd; stroke-linejoin: round; stroke-miterlimit: 2"
|
||||
>
|
||||
<g transform="matrix(1,0,0,1,-2606,-236)">
|
||||
<g id="a2-c" transform="matrix(1,0,0,1,2606,236)">
|
||||
<rect x="0" y="0" width="192" height="192" style="fill: none" />
|
||||
<g transform="matrix(-0.800798,0.462341,-0.769972,-1.33363,1869.11,-896.718)">
|
||||
<path
|
||||
d="M1726.17,-64.249L1708.16,-72.303L1708.05,-23.514L1721.88,-32.386C1722.96,-33.241 1723.09,-33.944 1723.15,-34.636L1723.15,-54.373C1723.19,-56.238 1724.96,-57.594 1726.87,-56.686L1726.17,-64.249Z"
|
||||
style="fill:url(#_Linear6);" />
|
||||
d="M2241.27,-28.175C2238.86,-28.931 2236.64,-29.181 2234.48,-29.254L2159.78,-29.286L2165.01,-11.207C2167.16,-13.121 2169.64,-13.722 2172.26,-13.808L2222.12,-13.822C2223.52,-13.824 2225,-13.701 2226.78,-13.108L2241.27,-28.175Z"
|
||||
style="fill: url(#_Linear1)"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(-0.126036,0.0767377,0.569859,0.112933,2435.01,-3.09225)">
|
||||
<g transform="matrix(1,0,0,1,-2157.67,-208.423)">
|
||||
<path
|
||||
d="M1726.17,-45.661L1704.47,-40.254C1706.28,-40.527 1708.14,-40.212 1708.16,-39.416L1708.16,-18.976L1726.17,-18.976L1726.17,-45.661Z"
|
||||
style="fill:rgb(141,81,249);" />
|
||||
d="M2205.67,331.428L2205.67,332.25L2205.67,352.835C2205.67,354.263 2204.91,355.583 2203.67,356.298C2202.43,357.012 2200.91,357.013 2199.67,356.3L2190.78,351.174C2189.73,350.595 2188.83,350.083 2188.03,349.59L2187.45,349.257C2186.66,348.725 2185.91,348.142 2185.21,347.461C2185.08,347.331 2184.95,347.198 2184.82,347.061C2184.26,346.457 2183.75,345.778 2183.3,344.995C2182.16,343.05 2181.69,341.024 2181.68,338.948L2181.67,268.923L2209.77,274.425C2207.5,275.639 2205.68,278.3 2205.67,281.429L2205.67,331.428Z"
|
||||
style="fill: url(#_Linear2)"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(-0.126036,0.0767377,0.569859,0.112933,2435.01,-3.09225)">
|
||||
<g transform="matrix(1,0,0,1,-2157.67,-208.423)">
|
||||
<path
|
||||
d="M1726.17,-45.661L1726.17,-18.976L1708.16,-18.976L1708.16,-39.416C1707.79,-40.732 1704.5,-40.298 1702.68,-40.025L1726.17,-45.661ZM1705.49,-40.491C1706.2,-40.507 1706.87,-40.464 1707.4,-40.327C1708.01,-40.173 1708.48,-39.899 1708.62,-39.436C1708.62,-39.429 1708.62,-39.423 1708.62,-39.416L1708.62,-19.152C1708.62,-19.152 1725.72,-19.152 1725.72,-19.152L1725.72,-45.345L1705.49,-40.491Z"
|
||||
style="fill:url(#_Radial7);" />
|
||||
d="M2295.93,363.064C2299.48,360.882 2301.46,357.55 2301.67,352.926L2301.67,277.879L2301.67,276.775L2301.67,252.515C2301.67,251.801 2302.05,251.14 2302.67,250.783C2303.29,250.426 2304.05,250.426 2304.67,250.784L2319.81,259.54C2321.59,260.617 2322.95,262.115 2324.04,263.875C2325.03,265.551 2325.56,267.37 2325.67,269.835L2325.67,339.91C2325.18,343.645 2323.51,346.705 2320.3,348.887L2295.93,363.064ZM2295.93,363.064C2295.73,363.184 2295.53,363.301 2295.32,363.414L2295.93,363.064Z"
|
||||
style="fill: rgb(141, 81, 249)"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,-2157.67,-208.423)">
|
||||
<path
|
||||
d="M2295.93,363.064C2299.48,360.882 2301.46,357.55 2301.67,352.926L2301.67,277.879L2301.67,276.775L2301.67,252.515C2301.67,251.801 2302.05,251.14 2302.67,250.783C2303.29,250.426 2304.05,250.426 2304.67,250.784L2319.81,259.54C2321.59,260.617 2322.95,262.115 2324.04,263.875C2325.03,265.551 2325.56,267.37 2325.67,269.835L2325.67,339.91C2325.18,343.645 2323.51,346.705 2320.3,348.887L2295.93,363.064ZM2299.79,360.238C2299.79,360.238 2320.03,348.464 2320.04,348.461C2323.1,346.372 2324.69,343.444 2325.17,339.877C2325.17,339.877 2325.17,269.846 2325.17,269.839C2325.06,267.482 2324.56,265.739 2323.61,264.133C2322.56,262.445 2321.26,261.005 2319.55,259.97L2304.42,251.217C2303.96,250.949 2303.39,250.948 2302.92,251.216C2302.46,251.484 2302.17,251.979 2302.17,252.515L2302.17,276.775L2302.17,277.879L2302.17,352.926C2302.17,352.933 2302.17,352.941 2302.17,352.948C2302.04,355.861 2301.23,358.279 2299.79,360.238Z"
|
||||
style="fill: url(#_Linear3)"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,-2157.67,-208.423)">
|
||||
<path
|
||||
d="M2253.67,223.256C2255.26,223.245 2257.02,223.56 2259.11,224.557L2275.67,234.102C2276.91,234.816 2277.67,236.138 2277.67,237.568L2277.67,259.508C2277.67,260.222 2277.29,260.882 2276.67,261.239C2276.05,261.597 2275.29,261.597 2274.67,261.24L2257.52,251.353C2256.38,250.731 2255.12,250.341 2253.67,250.347C2252.26,250.339 2250.99,250.721 2249.82,251.353L2187.87,287.04C2184.23,289.147 2181.96,292.478 2181.67,297.57L2181.68,269.865C2181.85,265.167 2183.93,261.653 2187.92,259.322L2248.23,224.557C2249.69,223.796 2251.5,223.29 2253.67,223.256Z"
|
||||
style="fill: rgb(165, 118, 255)"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,-2157.67,-208.423)">
|
||||
<path
|
||||
d="M2253.67,223.256C2255.26,223.245 2257.02,223.56 2259.11,224.557L2275.67,234.102C2276.91,234.816 2277.67,236.138 2277.67,237.568L2277.67,259.508C2277.67,260.222 2277.29,260.882 2276.67,261.239C2276.05,261.597 2275.29,261.597 2274.67,261.24L2257.52,251.353C2256.38,250.731 2255.12,250.341 2253.67,250.347C2252.26,250.339 2250.99,250.721 2249.82,251.353L2187.87,287.04C2184.23,289.147 2181.96,292.478 2181.67,297.57L2181.68,269.865C2181.85,265.167 2183.93,261.653 2187.92,259.322L2248.23,224.557C2249.69,223.796 2251.5,223.29 2253.67,223.256ZM2253.68,223.756C2251.6,223.789 2249.87,224.269 2248.47,224.996L2188.17,259.754C2184.35,261.992 2182.35,265.367 2182.18,269.874C2182.18,269.874 2182.17,292.759 2182.17,292.757C2183.25,290.047 2185.13,288.051 2187.62,286.607L2249.57,250.919C2249.58,250.917 2249.58,250.915 2249.59,250.913C2250.83,250.243 2252.17,249.839 2253.67,249.847C2255.21,249.841 2256.54,250.253 2257.76,250.914C2257.76,250.916 2257.76,250.917 2257.76,250.919L2274.92,260.807C2275.38,261.075 2275.95,261.074 2276.42,260.806C2276.88,260.538 2277.17,260.043 2277.17,259.508L2277.17,237.568C2277.17,236.317 2276.5,235.16 2275.42,234.535C2275.42,234.535 2258.88,225 2258.87,224.996C2256.87,224.049 2255.2,223.746 2253.68,223.756Z"
|
||||
style="fill: url(#_Linear4)"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(0.800798,0.462341,0.769972,-1.33363,-1677.22,-896.858)">
|
||||
<path
|
||||
d="M2241.55,-28.184C2239.1,-28.989 2236.83,-29.204 2234.68,-29.295C2234.68,-29.295 2220.82,-29.3 2215.03,-29.303C2213.48,-29.303 2212.05,-28.808 2211.28,-28.004C2208.65,-25.275 2202.56,-18.936 2199.45,-15.709C2199.07,-15.306 2199.07,-14.809 2199.46,-14.406C2199.85,-14.004 2200.57,-13.758 2201.34,-13.761C2208.36,-13.788 2222.72,-13.845 2222.72,-13.845C2223.98,-13.851 2225.44,-13.657 2227.06,-13.117L2241.55,-28.184Z"
|
||||
style="fill: rgb(141, 81, 249)"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(-4.32309,0,0,12.4454,9610.35,-1450.35)">
|
||||
<path
|
||||
d="M2205.31,121.966C2205.31,121.88 2205.18,121.8 2204.96,121.757C2204.74,121.714 2204.48,121.714 2204.27,121.757C2201.75,122.263 2195.36,123.547 2192.85,124.052C2192.63,124.095 2192.5,124.174 2192.5,124.261C2192.5,124.347 2192.63,124.426 2192.85,124.469C2195.36,124.974 2201.75,126.255 2204.27,126.759C2204.48,126.802 2204.74,126.802 2204.96,126.759C2205.18,126.716 2205.31,126.636 2205.31,126.55C2205.31,125.541 2205.31,122.976 2205.31,121.966Z"
|
||||
style="fill: rgb(104, 0, 197)"
|
||||
/>
|
||||
<clipPath id="_clip5">
|
||||
<path
|
||||
d="M2205.31,121.966C2205.31,121.88 2205.18,121.8 2204.96,121.757C2204.74,121.714 2204.48,121.714 2204.27,121.757C2201.75,122.263 2195.36,123.547 2192.85,124.052C2192.63,124.095 2192.5,124.174 2192.5,124.261C2192.5,124.347 2192.63,124.426 2192.85,124.469C2195.36,124.974 2201.75,126.255 2204.27,126.759C2204.48,126.802 2204.74,126.802 2204.96,126.759C2205.18,126.716 2205.31,126.636 2205.31,126.55C2205.31,125.541 2205.31,122.976 2205.31,121.966Z"
|
||||
/>
|
||||
</clipPath>
|
||||
<g clip-path="url(#_clip5)">
|
||||
<g transform="matrix(0.124502,0.074907,0.206623,-0.0414384,1997.62,-7.40235)">
|
||||
<path
|
||||
d="M1726.17,-64.249L1708.16,-72.303L1708.05,-23.514L1721.88,-32.386C1722.96,-33.241 1723.09,-33.944 1723.15,-34.636L1723.15,-54.373C1723.19,-56.238 1724.96,-57.594 1726.87,-56.686L1726.17,-64.249Z"
|
||||
style="fill: url(#_Linear6)"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(-0.126036,0.0767377,0.569859,0.112933,2435.01,-3.09225)">
|
||||
<path
|
||||
d="M1726.17,-45.661L1704.47,-40.254C1706.28,-40.527 1708.14,-40.212 1708.16,-39.416L1708.16,-18.976L1726.17,-18.976L1726.17,-45.661Z"
|
||||
style="fill: rgb(141, 81, 249)"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(-0.126036,0.0767377,0.569859,0.112933,2435.01,-3.09225)">
|
||||
<path
|
||||
d="M1726.17,-45.661L1726.17,-18.976L1708.16,-18.976L1708.16,-39.416C1707.79,-40.732 1704.5,-40.298 1702.68,-40.025L1726.17,-45.661ZM1705.49,-40.491C1706.2,-40.507 1706.87,-40.464 1707.4,-40.327C1708.01,-40.173 1708.48,-39.899 1708.62,-39.436C1708.62,-39.429 1708.62,-39.423 1708.62,-39.416L1708.62,-19.152C1708.62,-19.152 1725.72,-19.152 1725.72,-19.152L1725.72,-45.345L1705.49,-40.491Z"
|
||||
style="fill: url(#_Radial7)"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(-70.0711,-0.927611,1.54482,-42.0752,2233.59,-20.1891)">
|
||||
<stop offset="0" style="stop-color:rgb(141,81,249);stop-opacity:1" />
|
||||
<stop offset="1" style="stop-color:rgb(116,50,223);stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient id="_Linear2" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(4.78193e-15,-78.0949,78.0949,4.78193e-15,2195.72,354.021)">
|
||||
<stop offset="0" style="stop-color:rgb(141,81,249);stop-opacity:1" />
|
||||
<stop offset="1" style="stop-color:rgb(116,50,223);stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient id="_Linear3" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(41.6089,41.5866,-41.5866,41.6089,2282.31,262.837)">
|
||||
<stop offset="0" style="stop-color:rgb(211,187,255);stop-opacity:1" />
|
||||
<stop offset="1" style="stop-color:rgb(211,187,255);stop-opacity:0" />
|
||||
</linearGradient>
|
||||
<linearGradient id="_Linear4" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(9.25616,16.7005,-16.7005,9.25616,2215,243.712)">
|
||||
<stop offset="0" style="stop-color:rgb(211,187,255);stop-opacity:1" />
|
||||
<stop offset="1" style="stop-color:rgb(211,187,255);stop-opacity:0" />
|
||||
</linearGradient>
|
||||
<linearGradient id="_Linear6" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(-0.130164,-61.9937,59.4003,-0.135847,1711.63,-25.7957)">
|
||||
<stop offset="0" style="stop-color:rgb(116,50,223);stop-opacity:1" />
|
||||
<stop offset="0.51" style="stop-color:rgb(110,38,217);stop-opacity:1" />
|
||||
<stop offset="1" style="stop-color:rgb(91,0,197);stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<radialGradient id="_Radial7" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(13.8659,4.71436,-12.1609,5.37534,1708.16,-32.287)">
|
||||
<stop offset="0" style="stop-color:rgb(211,187,255);stop-opacity:1" />
|
||||
<stop offset="1" style="stop-color:rgb(211,187,255);stop-opacity:0" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="_Linear1"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="0"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(-70.0711,-0.927611,1.54482,-42.0752,2233.59,-20.1891)"
|
||||
>
|
||||
<stop offset="0" style="stop-color: rgb(141, 81, 249); stop-opacity: 1" />
|
||||
<stop offset="1" style="stop-color: rgb(116, 50, 223); stop-opacity: 1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="_Linear2"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="0"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(4.78193e-15,-78.0949,78.0949,4.78193e-15,2195.72,354.021)"
|
||||
>
|
||||
<stop offset="0" style="stop-color: rgb(141, 81, 249); stop-opacity: 1" />
|
||||
<stop offset="1" style="stop-color: rgb(116, 50, 223); stop-opacity: 1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="_Linear3"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="0"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(41.6089,41.5866,-41.5866,41.6089,2282.31,262.837)"
|
||||
>
|
||||
<stop offset="0" style="stop-color: rgb(211, 187, 255); stop-opacity: 1" />
|
||||
<stop offset="1" style="stop-color: rgb(211, 187, 255); stop-opacity: 0" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="_Linear4"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="0"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(9.25616,16.7005,-16.7005,9.25616,2215,243.712)"
|
||||
>
|
||||
<stop offset="0" style="stop-color: rgb(211, 187, 255); stop-opacity: 1" />
|
||||
<stop offset="1" style="stop-color: rgb(211, 187, 255); stop-opacity: 0" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="_Linear6"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="0"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(-0.130164,-61.9937,59.4003,-0.135847,1711.63,-25.7957)"
|
||||
>
|
||||
<stop offset="0" style="stop-color: rgb(116, 50, 223); stop-opacity: 1" />
|
||||
<stop offset="0.51" style="stop-color: rgb(110, 38, 217); stop-opacity: 1" />
|
||||
<stop offset="1" style="stop-color: rgb(91, 0, 197); stop-opacity: 1" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
id="_Radial7"
|
||||
cx="0"
|
||||
cy="0"
|
||||
r="1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(13.8659,4.71436,-12.1609,5.37534,1708.16,-32.287)"
|
||||
>
|
||||
<stop offset="0" style="stop-color: rgb(211, 187, 255); stop-opacity: 1" />
|
||||
<stop offset="1" style="stop-color: rgb(211, 187, 255); stop-opacity: 0" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="loading">
|
||||
<div class="effect-1 effects"></div>
|
||||
<div class="effect-2 effects"></div>
|
||||
<div class="effect-3 effects"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
<script>
|
||||
const loaderColor = localStorage.getItem('materio-initial-loader-bg') || '#FFFFFF'
|
||||
const primaryColor = localStorage.getItem('materio-initial-loader-color') || '#9155FD'
|
||||
|
||||
</div>
|
||||
<div class="loading">
|
||||
<div class="effect-1 effects"></div>
|
||||
<div class="effect-2 effects"></div>
|
||||
<div class="effect-3 effects"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app">
|
||||
</div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
<script>
|
||||
const loaderColor = localStorage.getItem('materio-initial-loader-bg') || '#FFFFFF'
|
||||
const primaryColor = localStorage.getItem('materio-initial-loader-color') || '#9155FD'
|
||||
|
||||
if (loaderColor)
|
||||
document.documentElement.style.setProperty('--initial-loader-bg', loaderColor)
|
||||
|
||||
if (primaryColor)
|
||||
document.documentElement.style.setProperty('--initial-loader-color', primaryColor)
|
||||
</script>
|
||||
</body>
|
||||
if (loaderColor) document.documentElement.style.setProperty('--initial-loader-bg', loaderColor)
|
||||
|
||||
if (primaryColor) document.documentElement.style.setProperty('--initial-loader-color', primaryColor)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "moviepilot",
|
||||
"version": "1.2.3",
|
||||
"version": "1.2.7",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite --host",
|
||||
|
||||
BIN
public/plugin/clean.png
Normal file
BIN
public/plugin/clean.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.2 KiB |
BIN
public/plugin/downloadmsg.png
Normal file
BIN
public/plugin/downloadmsg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
@@ -832,6 +832,7 @@ export interface NotificationSwitch {
|
||||
wechat: boolean
|
||||
telegram: boolean
|
||||
slack: boolean
|
||||
synologychat: boolean
|
||||
}
|
||||
|
||||
// 环境设置
|
||||
|
||||
@@ -2,19 +2,30 @@
|
||||
// 输入参数
|
||||
const props = defineProps({
|
||||
pri: String,
|
||||
maxpri: String,
|
||||
rules: Array as PropType<string[]>,
|
||||
width: String,
|
||||
height: String,
|
||||
})
|
||||
|
||||
// 定义触发的自定义事件
|
||||
const emit = defineEmits(['close', 'changed'])
|
||||
const emit = defineEmits(['close', 'changed', 'levelup', 'leveldown'])
|
||||
|
||||
// 按钮点击
|
||||
function onClose() {
|
||||
emit('close')
|
||||
}
|
||||
|
||||
// 上升优先级
|
||||
function onLevelUp() {
|
||||
emit('levelup', props.pri)
|
||||
}
|
||||
|
||||
// 下降优先级
|
||||
function onLevelDown() {
|
||||
emit('leveldown', props.pri)
|
||||
}
|
||||
|
||||
// 选项变化
|
||||
function filtersChanged(value: string[]) {
|
||||
emit('changed', props.pri, value)
|
||||
@@ -54,6 +65,20 @@ const selectFilterOptions = ref<{ [key: string]: string }[]>([
|
||||
|
||||
<template>
|
||||
<VCard variant="tonal" :width="props.width" :height="props.height">
|
||||
<span class="absolute top-3 right-14">
|
||||
<IconBtn
|
||||
v-if="props.pri !== '1'"
|
||||
@click.stop="onLevelUp"
|
||||
>
|
||||
<VIcon icon="mdi-arrow-up" />
|
||||
</IconBtn>
|
||||
<IconBtn
|
||||
v-if="props.pri !== props.maxpri"
|
||||
@click.stop="onLevelDown"
|
||||
>
|
||||
<VIcon icon="mdi-arrow-down" />
|
||||
</IconBtn>
|
||||
</span>
|
||||
<DialogCloseBtn @click="onClose" />
|
||||
<VCardItem>
|
||||
<VCardTitle>优先级 {{ props.pri }}</VCardTitle>
|
||||
|
||||
@@ -112,7 +112,7 @@ async function addSubscribe(season = 0) {
|
||||
// 全部存在时洗版
|
||||
best_version = !seasonsNotExisted.value[season] ? 1 : 0
|
||||
// 请求API
|
||||
const result: { [key: string]: any } = await api.post('subscribe', {
|
||||
const result: { [key: string]: any } = await api.post('subscribe/', {
|
||||
name: props.media?.title,
|
||||
type: props.media?.type,
|
||||
year: props.media?.year,
|
||||
@@ -360,14 +360,6 @@ onBeforeMount(() => {
|
||||
handleCheckExists()
|
||||
})
|
||||
|
||||
// 订阅季表头
|
||||
const seasonsHeaders = [
|
||||
{ title: '季', key: 'title', sortable: false },
|
||||
{ title: '集数', key: 'episodes', sortable: false },
|
||||
{ title: '评分', key: 'vote', sortable: false },
|
||||
{ title: '状态', key: 'status', sortable: false },
|
||||
]
|
||||
|
||||
// 计算图片地址
|
||||
const getImgUrl: Ref<string> = computed(() => {
|
||||
if (imageLoadError.value)
|
||||
@@ -379,6 +371,28 @@ const getImgUrl: Ref<string> = computed(() => {
|
||||
|
||||
return url
|
||||
})
|
||||
|
||||
// 拼装季图片地址
|
||||
function getSeasonPoster(posterPath: string) {
|
||||
if (!posterPath)
|
||||
return ''
|
||||
return `https://image.tmdb.org/t/p/w500${posterPath}`
|
||||
}
|
||||
|
||||
// 将yyyy-mm-dd转换为yyyy年mm月dd日
|
||||
function formatAirDate(airDate: string) {
|
||||
if (!airDate)
|
||||
return ''
|
||||
const date = new Date(airDate)
|
||||
return `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日`
|
||||
}
|
||||
// 从yyyy-mm-dd中提取年份
|
||||
function getYear(airDate: string) {
|
||||
if (!airDate)
|
||||
return ''
|
||||
const date = new Date(airDate)
|
||||
return date.getFullYear()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -460,72 +474,89 @@ const getImgUrl: Ref<string> = computed(() => {
|
||||
</VCard>
|
||||
</template>
|
||||
</VHover>
|
||||
<VDialog
|
||||
<!-- 订阅季弹窗 -->
|
||||
<VBottomSheet
|
||||
v-model="subscribeSeasonDialog"
|
||||
max-width="50rem"
|
||||
content-class="whitespace-nowrap"
|
||||
inset
|
||||
scrollable
|
||||
>
|
||||
<!-- Dialog Content -->
|
||||
<VCard title="选择订阅季">
|
||||
<VCardText style="padding: 0;">
|
||||
<VDataTable
|
||||
v-model="seasonsSelected"
|
||||
:headers="seasonsHeaders"
|
||||
:items="seasonInfos"
|
||||
item-value="season_number"
|
||||
return-object
|
||||
fixed-header
|
||||
show-select
|
||||
:items-per-page="100"
|
||||
density="compact"
|
||||
height="auto"
|
||||
<VCard>
|
||||
<DialogCloseBtn @click="subscribeSeasonDialog = false" />
|
||||
<VCardTitle class="pe-10">
|
||||
订阅 - {{ props.media?.title }}
|
||||
</VCardTitle>
|
||||
<VCardText>
|
||||
<VList
|
||||
v-model:selected="seasonsSelected"
|
||||
lines="three"
|
||||
select-strategy="classic"
|
||||
>
|
||||
<template #item.title="{ item }">
|
||||
<span class="d-block whitespace-nowrap">第 {{ item.raw.season_number }} 季
|
||||
</span>
|
||||
</template>
|
||||
<template #item.episodes="{ item }">
|
||||
<VChip
|
||||
variant="outlined"
|
||||
size="small"
|
||||
>
|
||||
{{ item.raw.episode_count }}
|
||||
</VChip>
|
||||
</template>
|
||||
<template #item.vote="{ item }">
|
||||
{{ item.raw.vote_average }}
|
||||
</template>
|
||||
<template #item.status="{ item }">
|
||||
<VChip
|
||||
v-if="seasonsNotExisted"
|
||||
:color="getExistColor(item.raw.season_number)"
|
||||
flat
|
||||
size="small"
|
||||
>
|
||||
{{ getExistText(item.raw.season_number) }}
|
||||
</VChip>
|
||||
</template>
|
||||
<template #no-data>
|
||||
没有数据
|
||||
</template>
|
||||
<template #bottom />
|
||||
</VDataTable>
|
||||
<VListItem
|
||||
v-for="(item, i) in seasonInfos" :key="i"
|
||||
:value="item"
|
||||
>
|
||||
<template #prepend>
|
||||
<VImg
|
||||
height="90"
|
||||
width="60"
|
||||
:src="getSeasonPoster(item.poster_path || '')"
|
||||
aspect-ratio="2/3"
|
||||
class="object-cover rounded shadow ring-gray-500 me-3"
|
||||
cover
|
||||
>
|
||||
<template #placeholder>
|
||||
<div class="w-full h-full">
|
||||
<VSkeletonLoader class="object-cover aspect-w-2 aspect-h-3" />
|
||||
</div>
|
||||
</template>
|
||||
</VImg>
|
||||
</template>
|
||||
<VListItemTitle>
|
||||
第 {{ item.season_number }} 季
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle class="mt-1 me-2">
|
||||
<VChip
|
||||
v-if="item.vote_average"
|
||||
color="primary"
|
||||
size="small"
|
||||
class="mb-1"
|
||||
>
|
||||
<VIcon icon="mdi-star" /> {{ item.vote_average }}
|
||||
</VChip>
|
||||
{{ getYear(item.air_date || '') }} • {{ item.episode_count }} 集
|
||||
</VListItemSubtitle>
|
||||
<VListItemSubtitle>
|
||||
《{{ media?.title }}》第 {{ item.season_number }} 季于 {{ formatAirDate(item.air_date || '') }} 首播。
|
||||
</VListItemSubtitle>
|
||||
<VListItemSubtitle>
|
||||
<VChip
|
||||
v-if="seasonsNotExisted"
|
||||
class="mt-2"
|
||||
size="small"
|
||||
:color="getExistColor(item.season_number || 0)"
|
||||
>
|
||||
{{ getExistText(item.season_number || 0) }}
|
||||
</VChip>
|
||||
</VListItemSubtitle>
|
||||
<template #append="{ isSelected }">
|
||||
<VListItemAction start>
|
||||
<VSwitch :model-value="isSelected" />
|
||||
</VListItemAction>
|
||||
</template>
|
||||
</VListItem>
|
||||
</VList>
|
||||
</VCardText>
|
||||
<VCardActions>
|
||||
<VBtn @click="subscribeSeasonDialog = false">
|
||||
取消
|
||||
</VBtn>
|
||||
<VSpacer />
|
||||
<div class="my-2 text-center">
|
||||
<VBtn
|
||||
:disabled="seasonsSelected.length === 0"
|
||||
width="30%"
|
||||
@click="subscribeSeasons"
|
||||
@keydown.enter="subscribeSeasons"
|
||||
>
|
||||
确定
|
||||
{{ seasonsSelected.length === 0 ? '请选择订阅季' : '提交订阅' }}
|
||||
</VBtn>
|
||||
</VCardActions>
|
||||
</div>
|
||||
</VCard>
|
||||
</VDialog>
|
||||
</VBottomSheet>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
@@ -212,7 +212,7 @@ async function updateSiteInfo() {
|
||||
// 更新按钮状态
|
||||
siteInfoDialog.value = false
|
||||
|
||||
const result: { [key: string]: any } = await api.put('site', siteForm)
|
||||
const result: { [key: string]: any } = await api.put('site/', siteForm)
|
||||
if (result.success) {
|
||||
$toast.success(`${cardProps.site?.name} 更新成功!`)
|
||||
emit('update')
|
||||
@@ -647,6 +647,7 @@ onMounted(() => {
|
||||
<VListItemTitle>查看详情</VListItemTitle>
|
||||
</VListItem>
|
||||
<VListItem
|
||||
v-if="item.raw.enclosure?.startsWith('http')"
|
||||
variant="plain"
|
||||
@click="downloadTorrentFile(item.raw.enclosure)"
|
||||
>
|
||||
|
||||
@@ -118,7 +118,7 @@ async function searchSubscribe() {
|
||||
async function updateSubscribeInfo() {
|
||||
subscribeInfoDialog.value = false
|
||||
try {
|
||||
const result: { [key: string]: any } = await api.put('subscribe', subscribeForm)
|
||||
const result: { [key: string]: any } = await api.put('subscribe/', subscribeForm)
|
||||
|
||||
// 提示
|
||||
if (result.success) {
|
||||
|
||||
@@ -20,6 +20,9 @@ const keyword = ref('')
|
||||
// 加载中
|
||||
const loading = ref(false)
|
||||
|
||||
// ref
|
||||
const tmdbKeyword = ref<HTMLElement | null>(null)
|
||||
|
||||
// 选中条目
|
||||
function selectMedia(item: TmdbItem) {
|
||||
console.log(item)
|
||||
@@ -68,6 +71,14 @@ async function searchMedias() {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
// 加载时聚焦搜索框
|
||||
onMounted(() => {
|
||||
// 500ms后聚焦
|
||||
setTimeout(() => {
|
||||
tmdbKeyword.value?.focus()
|
||||
}, 500)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -75,16 +86,17 @@ async function searchMedias() {
|
||||
class="mx-auto"
|
||||
width="100%"
|
||||
>
|
||||
<VToolbar flat dense>
|
||||
<VToolbar flat class="p-0">
|
||||
<VTextField
|
||||
ref="tmdbKeyword"
|
||||
v-model="keyword"
|
||||
density="compact"
|
||||
label="输入名称搜索"
|
||||
single-line
|
||||
hide-details
|
||||
flat
|
||||
class="mx-3"
|
||||
placeholder="电影或电视剧名称"
|
||||
variant="solo"
|
||||
append-inner-icon="mdi-magnify"
|
||||
flat
|
||||
class="mx-1"
|
||||
:loading="loading"
|
||||
@click:append-inner="searchMedias"
|
||||
@keydown.enter="searchMedias"
|
||||
@@ -97,7 +109,6 @@ async function searchMedias() {
|
||||
>
|
||||
<template v-for="(item, i) in items" :key="i">
|
||||
<VListItem
|
||||
density="compact"
|
||||
@click="selectMedia(item)"
|
||||
>
|
||||
<template #prepend>
|
||||
@@ -119,7 +130,7 @@ async function searchMedias() {
|
||||
<VListItemTitle>
|
||||
{{ item.title }}
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle v-html="item.overview" />
|
||||
<VListItemSubtitle class="mt-2" v-html="item.overview" />
|
||||
</VListItem>
|
||||
<VDivider v-if="i < items.length - 1" class="mt-1" inset />
|
||||
</template>
|
||||
|
||||
@@ -76,7 +76,7 @@ async function handleAddDownload(_site: any = undefined,
|
||||
async function addDownload(_media: any, _torrent: any) {
|
||||
startNProgress()
|
||||
try {
|
||||
const result: { [key: string]: any } = await api.post('download', {
|
||||
const result: { [key: string]: any } = await api.post('download/', {
|
||||
media_in: _media,
|
||||
torrent_in: _torrent,
|
||||
})
|
||||
@@ -122,26 +122,6 @@ function getVolumeFactorClass(downloadVolume: number, uploadVolume: number) {
|
||||
onMounted(() => {
|
||||
getSiteIcon()
|
||||
})
|
||||
|
||||
// 弹出菜单
|
||||
const dropdownItems = ref([
|
||||
{
|
||||
title: '查看详情',
|
||||
value: 1,
|
||||
props: {
|
||||
prependIcon: 'mdi-information',
|
||||
click: openTorrentDetail,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '下载种子',
|
||||
value: 2,
|
||||
props: {
|
||||
prependIcon: 'mdi-download',
|
||||
click: downloadTorrentFile,
|
||||
},
|
||||
},
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -180,15 +160,23 @@ const dropdownItems = ref([
|
||||
>
|
||||
<VList>
|
||||
<VListItem
|
||||
v-for="(item, i) in dropdownItems"
|
||||
:key="i"
|
||||
variant="plain"
|
||||
@click="item.props.click"
|
||||
@click="openTorrentDetail()"
|
||||
>
|
||||
<template #prepend>
|
||||
<VIcon :icon="item.props.prependIcon" />
|
||||
<VIcon icon="mdi-information" />
|
||||
</template>
|
||||
<VListItemTitle v-text="item.title" />
|
||||
<VListItemTitle>查看详情</VListItemTitle>
|
||||
</VListItem>
|
||||
<VListItem
|
||||
v-if="props.torrent?.torrent_info?.enclosure?.startsWith('http')"
|
||||
variant="plain"
|
||||
@click="downloadTorrentFile()"
|
||||
>
|
||||
<template #prepend>
|
||||
<VIcon icon="mdi-download" />
|
||||
</template>
|
||||
<VListItemTitle>下载种子</VListItemTitle>
|
||||
</VListItem>
|
||||
</VList>
|
||||
</VMenu>
|
||||
|
||||
@@ -632,6 +632,7 @@ onMounted(() => {
|
||||
<VTextField
|
||||
v-model="transferForm.target"
|
||||
label="目的路径"
|
||||
placeholder="留空自动"
|
||||
/>
|
||||
</VCol>
|
||||
<VCol
|
||||
|
||||
@@ -5,6 +5,7 @@ import { type PropType, ref } from 'vue'
|
||||
interface RenderProps {
|
||||
component: string
|
||||
text: string
|
||||
html: string
|
||||
content?: any
|
||||
props?: any
|
||||
}
|
||||
@@ -16,9 +17,10 @@ const elementProps = defineProps({
|
||||
})
|
||||
|
||||
// 配置元素
|
||||
const formItem = ref<RenderProps>(elementProps.config || {
|
||||
const formItem = ref<RenderProps>(elementProps.config ?? {
|
||||
component: 'div',
|
||||
text: '',
|
||||
html: '',
|
||||
props: {},
|
||||
content: [],
|
||||
})
|
||||
@@ -30,6 +32,7 @@ const formData = ref<any>(elementProps.form || {})
|
||||
<template>
|
||||
<Component
|
||||
:is="formItem.component"
|
||||
v-if="!formItem.html"
|
||||
v-bind="formItem.props"
|
||||
v-model="formData[formItem.props?.model || '']"
|
||||
>
|
||||
@@ -42,4 +45,10 @@ const formData = ref<any>(elementProps.form || {})
|
||||
:form="formData"
|
||||
/>
|
||||
</Component>
|
||||
<Component
|
||||
:is="formItem.component"
|
||||
v-if="formItem.html"
|
||||
v-bind="formItem.props"
|
||||
v-html="formItem.html"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -13,11 +13,10 @@ interface RenderProps {
|
||||
// 输入参数
|
||||
const elementProps = defineProps({
|
||||
config: Object as PropType<RenderProps>,
|
||||
handler: Boolean,
|
||||
})
|
||||
|
||||
// 配置元素
|
||||
const formItem = ref<RenderProps>(elementProps.config || {
|
||||
const formItem = ref<RenderProps>(elementProps.config ?? {
|
||||
component: 'div',
|
||||
text: '',
|
||||
html: '',
|
||||
|
||||
@@ -28,9 +28,4 @@ app
|
||||
})
|
||||
.use(VuetifyUseDialog)
|
||||
.mount('#app')
|
||||
|
||||
// 小屏幕下1s后移除loading
|
||||
if (window.innerWidth < 1024)
|
||||
setTimeout(() => removeEl('#loading-bg'), 1000)
|
||||
else
|
||||
removeEl('#loading-bg')
|
||||
.$nextTick(() => removeEl('#loading-bg'))
|
||||
|
||||
@@ -8,6 +8,7 @@ import AccountSettingWords from '@/views/setting/AccountSettingWords.vue'
|
||||
import AccountSettingAbout from '@/views/setting/AccountSettingAbout.vue'
|
||||
import AccountSettingSearch from '@/views/setting/AccountSettingSearch.vue'
|
||||
import AccountSettingSubscribe from '@/views/setting/AccountSettingSubscribe.vue'
|
||||
import AccountSettingService from '@/views/setting/AccountSettingService.vue'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
@@ -35,6 +36,11 @@ const tabs = [
|
||||
icon: 'mdi-rss',
|
||||
tab: 'subscribe',
|
||||
},
|
||||
{
|
||||
title: '服务',
|
||||
icon: 'mdi-list-box',
|
||||
tab: 'service',
|
||||
},
|
||||
{
|
||||
title: '规则',
|
||||
icon: 'mdi-filter-cog',
|
||||
@@ -60,7 +66,10 @@ const tabs = [
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<VTabs v-model="activeTab" show-arrows>
|
||||
<VTabs
|
||||
v-model="activeTab"
|
||||
show-arrows
|
||||
>
|
||||
<VTab v-for="item in tabs" :key="item.icon" :value="item.tab">
|
||||
<VIcon size="20" start :icon="item.icon" />
|
||||
{{ item.title }}
|
||||
@@ -68,15 +77,19 @@ const tabs = [
|
||||
</VTabs>
|
||||
<VDivider />
|
||||
|
||||
<VWindow v-model="activeTab" class="mt-5 disable-tab-transition">
|
||||
<!-- Account -->
|
||||
<VWindow
|
||||
v-model="activeTab"
|
||||
class="mt-5 disable-tab-transition"
|
||||
:touch="false"
|
||||
>
|
||||
<!-- 用户 -->
|
||||
<VWindowItem value="account">
|
||||
<transition name="fade-slide" appear>
|
||||
<AccountSettingAccount />
|
||||
</transition>
|
||||
</VWindowItem>
|
||||
|
||||
<!-- 用户 -->
|
||||
<!-- 站点 -->
|
||||
<VWindowItem value="site">
|
||||
<transition name="fade-slide" appear>
|
||||
<AccountSettingSite />
|
||||
@@ -97,7 +110,14 @@ const tabs = [
|
||||
</transition>
|
||||
</VWindowItem>
|
||||
|
||||
<!-- Notification -->
|
||||
<!-- 服务 -->
|
||||
<VWindowItem value="service">
|
||||
<transition name="fade-slide" appear>
|
||||
<AccountSettingService />
|
||||
</transition>
|
||||
</VWindowItem>
|
||||
|
||||
<!-- 规则 -->
|
||||
<VWindowItem value="filter">
|
||||
<transition name="fade-slide" appear>
|
||||
<AccountSettingRule />
|
||||
|
||||
@@ -185,7 +185,7 @@ async function addSubscribe(season = 0) {
|
||||
// 全部存在时洗版
|
||||
best_version = !seasonsNotExisted.value[season] ? 1 : 0
|
||||
// 请求API
|
||||
const result: { [key: string]: any } = await api.post('subscribe', {
|
||||
const result: { [key: string]: any } = await api.post('subscribe/', {
|
||||
name: mediaDetail.value?.title,
|
||||
type: mediaDetail.value?.type,
|
||||
year: mediaDetail.value?.year,
|
||||
|
||||
@@ -38,7 +38,7 @@ function pluginInstalled() {
|
||||
// 获取插件列表数据
|
||||
async function fetchData() {
|
||||
try {
|
||||
dataList.value = await api.get('plugin')
|
||||
dataList.value = await api.get('plugin/')
|
||||
isRefreshed.value = true
|
||||
}
|
||||
catch (error) {
|
||||
|
||||
@@ -17,7 +17,7 @@ const isRefreshed = ref(false)
|
||||
// 获取订阅列表数据
|
||||
async function fetchData() {
|
||||
try {
|
||||
dataList.value = await api.get('download')
|
||||
dataList.value = await api.get('download/')
|
||||
isRefreshed.value = true
|
||||
}
|
||||
catch (error) {
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { useToast } from 'vue-toast-notification'
|
||||
import { useConfirm } from 'vuetify-use-dialog'
|
||||
import { numberValidator, requiredValidator } from '@/@validators'
|
||||
import { numberValidator } from '@/@validators'
|
||||
import api from '@/api'
|
||||
import type { TransferHistory } from '@/api/types'
|
||||
import TmdbSelectorCard from '@/components/cards/TmdbSelectorCard.vue'
|
||||
|
||||
// 确认框
|
||||
const createConfirm = useConfirm()
|
||||
|
||||
// 提示框
|
||||
const $toast = useToast()
|
||||
|
||||
@@ -24,6 +20,7 @@ const redoType = ref('电影')
|
||||
|
||||
// 类型下拉框:电影、电视剧
|
||||
const redoTypeItems = ref([
|
||||
{ title: '自动', value: '' },
|
||||
{ title: '电影', value: '电影' },
|
||||
{ title: '电视剧', value: '电视剧' },
|
||||
])
|
||||
@@ -75,6 +72,12 @@ const progressValue = ref(0)
|
||||
// TMDB选择对话框
|
||||
const tmdbSelectorDialog = ref(false)
|
||||
|
||||
// 删除确认对话框
|
||||
const deleteConfirmDialog = ref(false)
|
||||
|
||||
// 确认框标题
|
||||
const confirmTitle = ref('')
|
||||
|
||||
// 获取订阅列表数据
|
||||
async function fetchData({
|
||||
page,
|
||||
@@ -129,74 +132,50 @@ const TransferDict: { [key: string]: string } = {
|
||||
|
||||
// 删除历史记录
|
||||
async function removeHistory(item: TransferHistory) {
|
||||
const isConfirmed = await createConfirm({
|
||||
title: '确认',
|
||||
content: `同步删除 ${item.title} 对应的媒体库文件 ?`,
|
||||
confirmationText: '同步删除文件',
|
||||
cancellationText: '仅删除历史记录',
|
||||
dialogProps: {
|
||||
maxWidth: '50rem',
|
||||
},
|
||||
confirmationButtonProps: {
|
||||
color: 'error',
|
||||
},
|
||||
})
|
||||
if (isConfirmed === undefined)
|
||||
return
|
||||
|
||||
// 执行删除
|
||||
remove(item, isConfirmed || false)
|
||||
// 清空选中项
|
||||
selected.value = []
|
||||
currentHistory.value = item
|
||||
confirmTitle.value = `确认删除 ${item.title} ${item.seasons}${item.episodes} ?`
|
||||
deleteConfirmDialog.value = true
|
||||
}
|
||||
|
||||
// 调用API删除记录
|
||||
async function remove(item: TransferHistory, deleteFile: boolean) {
|
||||
async function remove(item: TransferHistory, deleteSrc: boolean, deleteDest: boolean) {
|
||||
try {
|
||||
// 调用删除API
|
||||
const result: { [key: string]: any } = await api.delete(`history/transfer?delete_file=${deleteFile}`, {
|
||||
const result: { [key: string]: any } = await api.delete(`history/transfer?deletesrc=${deleteSrc}&deletedest=${deleteDest}`, {
|
||||
data: item,
|
||||
})
|
||||
|
||||
if (result.success) {
|
||||
fetchData({
|
||||
page: currentPage.value,
|
||||
itemsPerPage: itemsPerPage.value,
|
||||
})
|
||||
}
|
||||
else {
|
||||
if (!result.success)
|
||||
$toast.error(`删除失败: ${result.msg}`)
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
// 批量删除历史记录
|
||||
async function removeHistoryBatch() {
|
||||
if (selected.value.length === 0)
|
||||
// 删除单条记录
|
||||
async function removeSingle(deleteSrc: boolean, deleteDest: boolean) {
|
||||
// 关闭弹窗
|
||||
deleteConfirmDialog.value = false
|
||||
if (!currentHistory.value)
|
||||
return
|
||||
// 确认
|
||||
const isConfirmed = await createConfirm({
|
||||
title: '确认',
|
||||
content: `同步删除 ${selected.value.length} 条记录对应的媒体库文件 ?`,
|
||||
confirmationText: '同步删除文件',
|
||||
cancellationText: '仅删除历史记录',
|
||||
dialogProps: {
|
||||
maxWidth: '50rem',
|
||||
},
|
||||
confirmationButtonProps: {
|
||||
color: 'error',
|
||||
},
|
||||
// 删除
|
||||
await remove(currentHistory.value, deleteSrc, deleteDest)
|
||||
// 刷新
|
||||
fetchData({
|
||||
page: currentPage.value,
|
||||
itemsPerPage: itemsPerPage.value,
|
||||
})
|
||||
if (isConfirmed === undefined)
|
||||
return
|
||||
|
||||
console.log(selected.value)
|
||||
}
|
||||
|
||||
// 批量删除记录
|
||||
async function removeBatch(deleteSrc: boolean, deleteDest: boolean) {
|
||||
// 关闭弹窗
|
||||
deleteConfirmDialog.value = false
|
||||
// 总条数
|
||||
const total = selected.value.length
|
||||
if (total === 0)
|
||||
return
|
||||
// 已处理条数
|
||||
let handled = 0
|
||||
// 显示进度条
|
||||
@@ -205,7 +184,7 @@ async function removeHistoryBatch() {
|
||||
for (const item of selected.value) {
|
||||
// 开始删除
|
||||
progressText.value = `正在删除 ${item.title} ${item.seasons}${item.episodes} ...`
|
||||
await remove(item, isConfirmed || false)
|
||||
await remove(item, deleteSrc, deleteDest)
|
||||
// 删除完成
|
||||
handled++
|
||||
progressValue.value = handled / total * 100
|
||||
@@ -221,27 +200,46 @@ async function removeHistoryBatch() {
|
||||
})
|
||||
}
|
||||
|
||||
// 重新整理
|
||||
async function rehandleHistory() {
|
||||
// 响应删除操作
|
||||
async function deleteConfirmHandler(deleteSrc: boolean, deleteDest: boolean) {
|
||||
if (currentHistory.value)
|
||||
await removeSingle(deleteSrc, deleteDest)
|
||||
else
|
||||
await removeBatch(deleteSrc, deleteDest)
|
||||
}
|
||||
|
||||
// 批量删除历史记录
|
||||
async function removeHistoryBatch() {
|
||||
if (selected.value.length === 0)
|
||||
return
|
||||
// 清空当前操作记录
|
||||
currentHistory.value = undefined
|
||||
confirmTitle.value = `确认删除 ${selected.value.length} 条记录 ?`
|
||||
// 打开确认弹窗
|
||||
deleteConfirmDialog.value = true
|
||||
}
|
||||
|
||||
// 批量重新整理
|
||||
async function retransferBatch() {
|
||||
if (selected.value.length === 0)
|
||||
return
|
||||
// 清空当前操作记录
|
||||
currentHistory.value = undefined
|
||||
// 打开识别弹窗
|
||||
redoType.value = ''
|
||||
redoDialog.value = true
|
||||
}
|
||||
|
||||
// 调API重新整理
|
||||
async function retransfer(item: TransferHistory, redoType = '', redoTmdbId = 0) {
|
||||
try {
|
||||
if (!redoTmdbId.value || !redoType.value)
|
||||
return
|
||||
|
||||
redoDialog.value = false
|
||||
$toast.info(`正在重新整理 ${currentHistory.value?.title} ...`)
|
||||
|
||||
// 调用API接口重新转移
|
||||
const requestData = {
|
||||
...currentHistory.value,
|
||||
}
|
||||
|
||||
const result: { [key: string]: any } = await api.post(
|
||||
'history/transfer',
|
||||
requestData,
|
||||
item,
|
||||
{
|
||||
params: {
|
||||
mtype: redoType.value,
|
||||
new_tmdbid: parseInt(redoTmdbId.value),
|
||||
mtype: redoType,
|
||||
new_tmdbid: redoTmdbId,
|
||||
},
|
||||
},
|
||||
)
|
||||
@@ -261,6 +259,50 @@ async function rehandleHistory() {
|
||||
}
|
||||
}
|
||||
|
||||
// 重新整理
|
||||
async function rehandleHistory() {
|
||||
try {
|
||||
// 关闭弹窗
|
||||
redoDialog.value = false
|
||||
|
||||
let tmdbid = 0
|
||||
|
||||
if (redoTmdbId.value)
|
||||
tmdbid = parseInt(redoTmdbId.value)
|
||||
|
||||
// 转移当前选中记录
|
||||
if (currentHistory.value) {
|
||||
$toast.info(`正在重新整理 ${currentHistory.value?.title} ...`)
|
||||
await retransfer(currentHistory.value, redoType.value, tmdbid)
|
||||
}
|
||||
else if (selected.value.length > 0) {
|
||||
// 总条数
|
||||
const total = selected.value.length
|
||||
if (total === 0)
|
||||
return
|
||||
// 已处理条数
|
||||
let handled = 0
|
||||
// 显示进度条
|
||||
progressDialog.value = true
|
||||
for (const item of selected.value) {
|
||||
progressText.value = `正在重新整理 ${item.src} ...`
|
||||
await retransfer(item, redoType.value, tmdbid)
|
||||
handled++
|
||||
progressValue.value = handled / total * 100
|
||||
}
|
||||
// 清空选中项
|
||||
selected.value = []
|
||||
// 隐藏进度条
|
||||
progressDialog.value = false
|
||||
}
|
||||
// 批量转移
|
||||
else { $toast.error('没有选中任何记录!') }
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
|
||||
// 弹出菜单
|
||||
const dropdownItems = ref([
|
||||
{
|
||||
@@ -269,6 +311,8 @@ const dropdownItems = ref([
|
||||
props: {
|
||||
prependIcon: 'mdi-redo-variant',
|
||||
click: (item: TransferHistory) => {
|
||||
redoTmdbId.value = ''
|
||||
redoType.value = ''
|
||||
redoDialog.value = true
|
||||
currentHistory.value = item
|
||||
},
|
||||
@@ -280,7 +324,9 @@ const dropdownItems = ref([
|
||||
props: {
|
||||
prependIcon: 'mdi-trash-can-outline',
|
||||
color: 'error',
|
||||
click: removeHistory,
|
||||
click: (item: TransferHistory) => {
|
||||
removeHistory(item)
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
@@ -407,7 +453,6 @@ const dropdownItems = ref([
|
||||
<VSelect
|
||||
v-model="redoType"
|
||||
label="类型"
|
||||
:rules="[requiredValidator]"
|
||||
:items="redoTypeItems"
|
||||
/>
|
||||
</VCol>
|
||||
@@ -415,9 +460,10 @@ const dropdownItems = ref([
|
||||
<VTextField
|
||||
v-model="redoTmdbId"
|
||||
label="TMDB编号"
|
||||
:rules="[requiredValidator, numberValidator]"
|
||||
placeholder="留空自动识别"
|
||||
:rules="[numberValidator]"
|
||||
append-inner-icon="mdi-magnify"
|
||||
@click:append-inner="tmdbSelectorDialog = true"
|
||||
@click:append-inner.stop="tmdbSelectorDialog = true"
|
||||
/>
|
||||
</VCol>
|
||||
</VRow>
|
||||
@@ -435,6 +481,13 @@ const dropdownItems = ref([
|
||||
</VCard>
|
||||
</VDialog>
|
||||
<span v-if="selected.length > 0" class="fixed right-5 bottom-5">
|
||||
<VBtn
|
||||
icon="mdi-redo-variant"
|
||||
class="me-2"
|
||||
color="primary"
|
||||
size="x-large"
|
||||
@click="retransferBatch"
|
||||
/>
|
||||
<VBtn
|
||||
icon="mdi-trash-can-outline"
|
||||
color="error"
|
||||
@@ -472,6 +525,45 @@ const dropdownItems = ref([
|
||||
@close="tmdbSelectorDialog = false"
|
||||
/>
|
||||
</vDialog>
|
||||
<!-- 底部弹窗 -->
|
||||
<VBottomSheet v-model="deleteConfirmDialog" inset>
|
||||
<VCard class="text-center">
|
||||
<DialogCloseBtn @click="deleteConfirmDialog = false" />
|
||||
<VCardTitle class="pe-10">
|
||||
{{ confirmTitle }}
|
||||
</VCardTitle>
|
||||
<div class="d-flex flex-column flex-lg-row justify-center my-3">
|
||||
<VBtn
|
||||
color="primary"
|
||||
class="mb-2 mx-2"
|
||||
@click="deleteConfirmHandler(false, false)"
|
||||
>
|
||||
仅删除历史记录
|
||||
</VBtn>
|
||||
<VBtn
|
||||
color="warning"
|
||||
class="mb-2 mx-2"
|
||||
@click="deleteConfirmHandler(true, false)"
|
||||
>
|
||||
删除历史记录和源文件
|
||||
</VBtn>
|
||||
<VBtn
|
||||
color="info"
|
||||
class="mb-2 mx-2"
|
||||
@click="deleteConfirmHandler(false, true)"
|
||||
>
|
||||
删除历史记录和媒体库文件
|
||||
</VBtn>
|
||||
<VBtn
|
||||
color="error"
|
||||
class="mb-2 mx-2"
|
||||
@click="deleteConfirmHandler(true, true)"
|
||||
>
|
||||
删除历史记录、源文件和媒体库文件
|
||||
</VBtn>
|
||||
</div>
|
||||
</VCard>
|
||||
</VBottomSheet>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
@@ -86,7 +86,7 @@ async function saveAccountInfo() {
|
||||
accountInfo.value.password = newPassword.value
|
||||
}
|
||||
try {
|
||||
const result: { [key: string]: any } = await api.put('user', accountInfo.value)
|
||||
const result: { [key: string]: any } = await api.put('user/', accountInfo.value)
|
||||
if (result.success)
|
||||
$toast.success('用户信息保存成功!')
|
||||
else
|
||||
@@ -100,7 +100,7 @@ async function saveAccountInfo() {
|
||||
// 调用API,查询所有用户
|
||||
async function loadAllUsers() {
|
||||
try {
|
||||
const result: User[] = await api.get('/user')
|
||||
const result: User[] = await api.get('/user/')
|
||||
|
||||
allUsers.value = result
|
||||
}
|
||||
@@ -131,7 +131,7 @@ async function deactivateUser(user: User) {
|
||||
try {
|
||||
user.is_active = !user.is_active
|
||||
|
||||
const result: { [key: string]: any } = await api.put('user', user)
|
||||
const result: { [key: string]: any } = await api.put('user/', user)
|
||||
if (result.success) {
|
||||
$toast.success('用户冻结成功!')
|
||||
loadAllUsers()
|
||||
|
||||
@@ -47,7 +47,7 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<VCard title="消息通知">
|
||||
<VCardText> 对应消息类型只会发送给选中的消息渠道 </VCardText>
|
||||
<VCardText> 对应消息类型只会发送给选中的消息渠道。 </VCardText>
|
||||
|
||||
<VTable class="text-no-wrap">
|
||||
<thead>
|
||||
@@ -64,6 +64,9 @@ onMounted(() => {
|
||||
<th scope="col">
|
||||
Slack
|
||||
</th>
|
||||
<th scope="col">
|
||||
SynologyChat
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -83,6 +86,9 @@ onMounted(() => {
|
||||
<td>
|
||||
<VCheckbox v-model="message.slack" />
|
||||
</td>
|
||||
<td>
|
||||
<VCheckbox v-model="message.synologychat" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="messagemTypes.length === 0">
|
||||
<td
|
||||
|
||||
@@ -15,7 +15,7 @@ const TorrentPriorityItems = [
|
||||
]
|
||||
|
||||
// 包含与排除规则
|
||||
const defaultIncludeExcludeFilter = ref({
|
||||
const defaultFilterRules = ref({
|
||||
include: '',
|
||||
exclude: '',
|
||||
})
|
||||
@@ -35,13 +35,13 @@ async function queryTorrentPriority() {
|
||||
}
|
||||
|
||||
// 查询包含与排除规则
|
||||
async function queryIncludeExcludeFilter() {
|
||||
async function queryDefaultFilter() {
|
||||
try {
|
||||
const result: { [key: string]: any } = await api.get(
|
||||
'system/setting/DefaultIncludeExcludeFilter',
|
||||
'system/setting/DefaultFilterRules',
|
||||
)
|
||||
if (result.data?.value)
|
||||
defaultIncludeExcludeFilter.value = result.data?.value
|
||||
defaultFilterRules.value = result.data?.value
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error)
|
||||
@@ -68,11 +68,11 @@ async function saveTorrentPriority() {
|
||||
}
|
||||
|
||||
// 保存包含与排除规则
|
||||
async function saveIncludeExcludeFilter() {
|
||||
async function saveDefaultFilter() {
|
||||
try {
|
||||
const result: { [key: string]: any } = await api.post(
|
||||
'system/setting/DefaultIncludeExcludeFilter',
|
||||
defaultIncludeExcludeFilter.value,
|
||||
'system/setting/DefaultFilterRules',
|
||||
defaultFilterRules.value,
|
||||
)
|
||||
if (result.success)
|
||||
$toast.success('默认包含/排除规则保存成功')
|
||||
@@ -86,7 +86,7 @@ async function saveIncludeExcludeFilter() {
|
||||
|
||||
onMounted(() => {
|
||||
queryTorrentPriority()
|
||||
queryIncludeExcludeFilter()
|
||||
queryDefaultFilter()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -127,14 +127,14 @@ onMounted(() => {
|
||||
<VRow>
|
||||
<VCol cols="12" md="6">
|
||||
<VTextField
|
||||
v-model="defaultIncludeExcludeFilter.include"
|
||||
v-model="defaultFilterRules.include"
|
||||
type="text"
|
||||
label="包含(关键字、正则式)"
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
<VTextField
|
||||
v-model="defaultIncludeExcludeFilter.exclude"
|
||||
v-model="defaultFilterRules.exclude"
|
||||
type="text"
|
||||
label="排除(关键字、正则式)"
|
||||
/>
|
||||
@@ -145,7 +145,7 @@ onMounted(() => {
|
||||
<VCardItem>
|
||||
<VBtn
|
||||
type="submit"
|
||||
@click="saveIncludeExcludeFilter"
|
||||
@click="saveDefaultFilter"
|
||||
>
|
||||
保存
|
||||
</VBtn>
|
||||
|
||||
@@ -109,7 +109,7 @@ function addFilterCard() {
|
||||
// 查询所有站点
|
||||
async function querySites() {
|
||||
try {
|
||||
const data: Site[] = await api.get('site')
|
||||
const data: Site[] = await api.get('site/')
|
||||
|
||||
// 过滤站点,只有启用的站点才显示
|
||||
allSites.value = data.filter(item => item.is_active)
|
||||
@@ -148,6 +148,48 @@ async function saveSelectedSites() {
|
||||
}
|
||||
}
|
||||
|
||||
// 上调优先级
|
||||
function onLevelUp(pri: string) {
|
||||
// 找到当前卡片
|
||||
const card = filterCards.value.find(card => card.pri === pri)
|
||||
if (!card)
|
||||
return
|
||||
|
||||
// 找到当前卡片的上一张卡片
|
||||
const prevCard = filterCards.value.find(card => card.pri === (parseInt(pri) - 1).toString())
|
||||
if (!prevCard)
|
||||
return
|
||||
|
||||
// 交换两张卡片的优先级
|
||||
const temp = card.pri
|
||||
card.pri = prevCard.pri
|
||||
prevCard.pri = temp
|
||||
|
||||
// 卡片重新按优先级排序
|
||||
filterCards.value.sort((a, b) => parseInt(a.pri) - parseInt(b.pri))
|
||||
}
|
||||
|
||||
// 下调优先级
|
||||
function onLevelDown(pri: string) {
|
||||
// 找到当前卡片
|
||||
const card = filterCards.value.find(card => card.pri === pri)
|
||||
if (!card)
|
||||
return
|
||||
|
||||
// 找到当前卡片的下一张卡片
|
||||
const nextCard = filterCards.value.find(card => card.pri === (parseInt(pri) + 1).toString())
|
||||
if (!nextCard)
|
||||
return
|
||||
|
||||
// 交换两张卡片的优先级
|
||||
const temp = card.pri
|
||||
card.pri = nextCard.pri
|
||||
nextCard.pri = temp
|
||||
|
||||
// 卡片重新按优先级排序
|
||||
filterCards.value.sort((a, b) => parseInt(a.pri) - parseInt(b.pri))
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
queryCustomFilters()
|
||||
querySites()
|
||||
@@ -191,9 +233,12 @@ onMounted(() => {
|
||||
v-for="(card, index) in filterCards"
|
||||
:key="index"
|
||||
:pri="card.pri"
|
||||
:maxpri="filterCards.length.toString()"
|
||||
:rules="card.rules"
|
||||
@changed="updateFilterCardValue"
|
||||
@close="filterCardClose(card.pri)"
|
||||
@leveldown="onLevelDown"
|
||||
@levelup="onLevelUp"
|
||||
/>
|
||||
</div>
|
||||
</VCardItem>
|
||||
|
||||
138
src/views/setting/AccountSettingService.vue
Normal file
138
src/views/setting/AccountSettingService.vue
Normal file
@@ -0,0 +1,138 @@
|
||||
<script lang="ts" setup>
|
||||
import { useToast } from 'vue-toast-notification'
|
||||
import api from '@/api'
|
||||
import type { ScheduleInfo } from '@/api/types'
|
||||
|
||||
// 提示框
|
||||
const $toast = useToast()
|
||||
|
||||
// 定时服务列表
|
||||
const schedulerList = ref<ScheduleInfo[]>([])
|
||||
|
||||
// 定时器
|
||||
let refreshTimer: NodeJS.Timer | null = null
|
||||
|
||||
// 调用API加载定时服务列表
|
||||
async function loadSchedulerList() {
|
||||
try {
|
||||
const res: ScheduleInfo[] = await api.get('dashboard/schedule')
|
||||
|
||||
schedulerList.value = res
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
|
||||
// 任务状态颜色
|
||||
function getSchedulerColor(status: string) {
|
||||
switch (status) {
|
||||
case '正在运行':
|
||||
return 'success'
|
||||
case '已停止':
|
||||
return 'error'
|
||||
case '等待':
|
||||
return ''
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
// 执行命令
|
||||
function runCommand(id: string) {
|
||||
try {
|
||||
// 异步提交
|
||||
api.get('system/runscheduler', {
|
||||
params: {
|
||||
jobid: id,
|
||||
},
|
||||
})
|
||||
$toast.success('定时作业执行请求提交成功!')
|
||||
// 1秒后刷新数据
|
||||
setTimeout(() => {
|
||||
loadSchedulerList()
|
||||
}, 1000)
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadSchedulerList()
|
||||
|
||||
// 启动定时器
|
||||
refreshTimer = setInterval(() => {
|
||||
loadSchedulerList()
|
||||
}, 5000)
|
||||
})
|
||||
|
||||
// 组件卸载时停止定时器
|
||||
onUnmounted(() => {
|
||||
if (refreshTimer) {
|
||||
clearInterval(refreshTimer)
|
||||
refreshTimer = null
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard title="定时作业">
|
||||
<VCardText> 手动执行不会影响作业正常的时间表。 </VCardText>
|
||||
|
||||
<VTable class="text-no-wrap">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">
|
||||
任务名称
|
||||
</th>
|
||||
<th scope="col">
|
||||
任务状态
|
||||
</th>
|
||||
<th scope="col">
|
||||
下一次执行时间
|
||||
</th>
|
||||
<th scope="col" />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="scheduler in schedulerList"
|
||||
:key="scheduler.id"
|
||||
>
|
||||
<td>
|
||||
{{ scheduler.name }}
|
||||
</td>
|
||||
<td>
|
||||
<VChip :color="getSchedulerColor(scheduler.status)">
|
||||
{{ scheduler.status }}
|
||||
</VChip>
|
||||
</td>
|
||||
<td>
|
||||
{{ scheduler.next_run }}
|
||||
</td>
|
||||
<td>
|
||||
<VBtn
|
||||
size="small"
|
||||
:disabled="scheduler.status === '正在运行'"
|
||||
@click="runCommand(scheduler.id)"
|
||||
>
|
||||
<template #prepend>
|
||||
<VIcon>mdi-play</VIcon>
|
||||
</template>
|
||||
执行
|
||||
</VBtn>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="schedulerList.length === 0">
|
||||
<td
|
||||
colspan="4"
|
||||
class="text-center"
|
||||
>
|
||||
没有后台服务
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
</VCard>
|
||||
</template>
|
||||
@@ -42,7 +42,7 @@ async function resetSites() {
|
||||
<VCard title="站点重置">
|
||||
<VCardText>
|
||||
<div>
|
||||
<VCheckbox v-model="isConfirmResetSites" label="确认删除所有站点数据并重新同步" />
|
||||
<VCheckbox v-model="isConfirmResetSites" label="确认删除所有站点数据并重新同步。" />
|
||||
</div>
|
||||
|
||||
<VBtn :disabled="!isConfirmResetSites || resetSitesDisabled" color="error" class="mt-3" @click="resetSites">
|
||||
|
||||
@@ -57,7 +57,7 @@ async function saveSelectedRssSites() {
|
||||
// 查询所有站点
|
||||
async function querySites() {
|
||||
try {
|
||||
const data: Site[] = await api.get('site')
|
||||
const data: Site[] = await api.get('site/')
|
||||
|
||||
// 过滤站点,只有启用的站点才显示
|
||||
allSites.value = data.filter(item => item.is_active)
|
||||
@@ -165,6 +165,48 @@ function addFilterCard(ruleType: string) {
|
||||
cards.value.push(newCard)
|
||||
}
|
||||
|
||||
// 上调优先级
|
||||
function onLevelUp(filterCards: FilterCard[], pri: string) {
|
||||
// 找到当前卡片
|
||||
const card = filterCards.find(card => card.pri === pri)
|
||||
if (!card)
|
||||
return
|
||||
|
||||
// 找到当前卡片的上一张卡片
|
||||
const prevCard = filterCards.find(card => card.pri === (parseInt(pri) - 1).toString())
|
||||
if (!prevCard)
|
||||
return
|
||||
|
||||
// 交换两张卡片的优先级
|
||||
const temp = card.pri
|
||||
card.pri = prevCard.pri
|
||||
prevCard.pri = temp
|
||||
|
||||
// 卡片重新按优先级排序
|
||||
filterCards.sort((a, b) => parseInt(a.pri) - parseInt(b.pri))
|
||||
}
|
||||
|
||||
// 下调优先级
|
||||
function onLevelDown(filterCards: FilterCard[], pri: string) {
|
||||
// 找到当前卡片
|
||||
const card = filterCards.find(card => card.pri === pri)
|
||||
if (!card)
|
||||
return
|
||||
|
||||
// 找到当前卡片的下一张卡片
|
||||
const nextCard = filterCards.find(card => card.pri === (parseInt(pri) + 1).toString())
|
||||
if (!nextCard)
|
||||
return
|
||||
|
||||
// 交换两张卡片的优先级
|
||||
const temp = card.pri
|
||||
card.pri = nextCard.pri
|
||||
nextCard.pri = temp
|
||||
|
||||
// 卡片重新按优先级排序
|
||||
filterCards.sort((a, b) => parseInt(a.pri) - parseInt(b.pri))
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
querySites()
|
||||
queryCustomFilters('SubscribeFilterRules')
|
||||
@@ -209,9 +251,12 @@ onMounted(() => {
|
||||
v-for="(card, index) in subscribeFilterCards"
|
||||
:key="index"
|
||||
:pri="card.pri"
|
||||
:maxpri="subscribeFilterCards.length.toString()"
|
||||
:rules="card.rules"
|
||||
@changed="updateFilterCardValue"
|
||||
@close="filterCardClose('SubscribeFilterRules', card.pri)"
|
||||
@leveldown="onLevelDown(subscribeFilterCards, card.pri)"
|
||||
@levelup="onLevelUp(subscribeFilterCards, card.pri)"
|
||||
/>
|
||||
</div>
|
||||
</VCardItem>
|
||||
@@ -242,9 +287,12 @@ onMounted(() => {
|
||||
v-for="(card, index) in bestVersionFilterCards"
|
||||
:key="index"
|
||||
:pri="card.pri"
|
||||
:maxpri="bestVersionFilterCards.length.toString()"
|
||||
:rules="card.rules"
|
||||
@changed="updateFilterCardValue2"
|
||||
@close="filterCardClose('BestVersionFilterRules', card.pri)"
|
||||
@leveldown="onLevelDown(bestVersionFilterCards, card.pri)"
|
||||
@levelup="onLevelUp(bestVersionFilterCards, card.pri)"
|
||||
/>
|
||||
</div>
|
||||
</VCardItem>
|
||||
|
||||
@@ -124,7 +124,7 @@ onMounted(() => {
|
||||
<VRow>
|
||||
<VCol cols="12">
|
||||
<VCard title="自定义识别词">
|
||||
<VCardSubtitle> 添加规则对种子名或者文件名进行预处理以校正识别 </VCardSubtitle>
|
||||
<VCardSubtitle> 添加规则对种子名或者文件名进行预处理以校正识别。 </VCardSubtitle>
|
||||
<VCardItem>
|
||||
<VTextarea
|
||||
v-model="customIdentifiers"
|
||||
@@ -148,7 +148,7 @@ onMounted(() => {
|
||||
</VCol>
|
||||
<VCol cols="12">
|
||||
<VCard title="自定义制作组/字幕组">
|
||||
<VCardSubtitle> 添加无法识别的制作组/字幕组 </VCardSubtitle>
|
||||
<VCardSubtitle> 添加无法识别的制作组/字幕组。 </VCardSubtitle>
|
||||
<VCardItem>
|
||||
<VTextarea
|
||||
v-model="customReleaseGroups"
|
||||
@@ -168,7 +168,7 @@ onMounted(() => {
|
||||
</VCol>
|
||||
<VCol cols="12">
|
||||
<VCard title="文件整理屏蔽词">
|
||||
<VCardSubtitle> 目录名或文件名中包含屏蔽词时不进行整理 </VCardSubtitle>
|
||||
<VCardSubtitle> 目录名或文件名中包含屏蔽词时不进行整理。 </VCardSubtitle>
|
||||
<VCardItem>
|
||||
<VTextarea
|
||||
v-model="transferExcludeWords"
|
||||
|
||||
@@ -58,7 +58,7 @@ const siteForm = reactive<Site>({
|
||||
// 获取站点列表数据
|
||||
async function fetchData() {
|
||||
try {
|
||||
dataList.value = await api.get('site')
|
||||
dataList.value = await api.get('site/')
|
||||
isRefreshed.value = true
|
||||
}
|
||||
catch (error) {
|
||||
@@ -77,7 +77,7 @@ async function addSite() {
|
||||
addBtnState.value = true
|
||||
|
||||
try {
|
||||
const result: { [key: string]: string } = await api.post('site', siteForm)
|
||||
const result: { [key: string]: string } = await api.post('site/', siteForm)
|
||||
if (result.success) {
|
||||
$toast.success('新增站点成功')
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ async function eventsHander(subscribe: Subscribe | Rss) {
|
||||
async function getSubscribes() {
|
||||
try {
|
||||
// 订阅
|
||||
const subscribes: Subscribe[] = await api.get('subscribe')
|
||||
const subscribes: Subscribe[] = await api.get('subscribe/')
|
||||
|
||||
const subEvents = await Promise.all(
|
||||
subscribes.map(async sub => eventsHander(sub)),
|
||||
|
||||
@@ -19,7 +19,7 @@ const dataList = ref<Subscribe[]>([])
|
||||
// 获取订阅列表数据
|
||||
async function fetchData() {
|
||||
try {
|
||||
dataList.value = await api.get('subscribe')
|
||||
dataList.value = await api.get('subscribe/')
|
||||
isRefreshed.value = true
|
||||
}
|
||||
catch (error) {
|
||||
|
||||
@@ -43,6 +43,7 @@ export default defineConfig({
|
||||
},
|
||||
build: {
|
||||
chunkSizeWarningLimit: 5000,
|
||||
cssCodeSplit: false,
|
||||
},
|
||||
optimizeDeps: {
|
||||
exclude: ['vuetify'],
|
||||
|
||||
Reference in New Issue
Block a user