Compare commits
1144 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1019fecc9e | ||
![]() |
1855f93c1c | ||
![]() |
52e6a44aa4 | ||
![]() |
0b77808af6 | ||
![]() |
9233ed5c53 | ||
![]() |
ee68c0f622 | ||
![]() |
366823cee9 | ||
![]() |
40e1eb9a49 | ||
![]() |
1af419a860 | ||
![]() |
397f18c435 | ||
![]() |
2e5dd05a6c | ||
![]() |
a9fb8ddfb8 | ||
![]() |
562c726787 | ||
![]() |
5f82c1dc17 | ||
![]() |
222800bdb6 | ||
![]() |
5dd3636571 | ||
![]() |
2296a9fbb3 | ||
![]() |
63b5a7c036 | ||
![]() |
b74ca2670e | ||
![]() |
393f4e0e58 | ||
![]() |
3a9ca29e99 | ||
![]() |
32995fef24 | ||
![]() |
a73c99fc64 | ||
![]() |
a5834470ba | ||
![]() |
da3bc127dc | ||
![]() |
0dddc4d58f | ||
![]() |
a4d5d9157b | ||
![]() |
c70d5d4398 | ||
![]() |
7c08b07ef5 | ||
![]() |
e426b5dd35 | ||
![]() |
2fdf619582 | ||
![]() |
d9eed14b7a | ||
![]() |
8230ffb8a4 | ||
![]() |
7098930b19 | ||
![]() |
56244245a4 | ||
![]() |
dd2f12fa8e | ||
![]() |
9598247a0d | ||
![]() |
230ee90b1c | ||
![]() |
e705bedc91 | ||
![]() |
b5ebe7590c | ||
![]() |
6d0831ceaa | ||
![]() |
19e00ee2f2 | ||
![]() |
80723d224e | ||
![]() |
0c82bb023a | ||
![]() |
0a86f24095 | ||
![]() |
b41249cfa8 | ||
![]() |
6659802689 | ||
![]() |
964c503223 | ||
![]() |
15568bf20a | ||
![]() |
d10cd324bb | ||
![]() |
2a22ab8c33 | ||
![]() |
ca736cdae2 | ||
![]() |
d589c57dd2 | ||
![]() |
9b0caf2a47 | ||
![]() |
f8b00bbd67 | ||
![]() |
91a8c0e7a0 | ||
![]() |
2089172384 | ||
![]() |
1ab87e5334 | ||
![]() |
b5e6861032 | ||
![]() |
189930918a | ||
![]() |
ff1bd0a4b8 | ||
![]() |
e544d0dd07 | ||
![]() |
3e0b240154 | ||
![]() |
199119cafb | ||
![]() |
89ab665923 | ||
![]() |
dfb60de6d2 | ||
![]() |
da8d41868d | ||
![]() |
e9db43ebf6 | ||
![]() |
c0453eae47 | ||
![]() |
a8863a5aeb | ||
![]() |
a8adad7dbb | ||
![]() |
4cfa5ac10b | ||
![]() |
55090ddeaa | ||
![]() |
14346b0e69 | ||
![]() |
ac24acf9ce | ||
![]() |
4cde62fde9 | ||
![]() |
7489bc8d98 | ||
![]() |
cde9287d85 | ||
![]() |
558023e18e | ||
![]() |
8157ee7811 | ||
![]() |
d746d2913f | ||
![]() |
0136fc6436 | ||
![]() |
7ce280cb92 | ||
![]() |
0209fa87aa | ||
![]() |
62cc2f769f | ||
![]() |
a49d44c880 | ||
![]() |
dab288380a | ||
![]() |
2ac5c35065 | ||
![]() |
ec9e2fe0f0 | ||
![]() |
ecbe79b5b9 | ||
![]() |
c4ac03738b | ||
![]() |
352dbd9bc8 | ||
![]() |
393b395df0 | ||
![]() |
1a96da04a1 | ||
![]() |
615b98955a | ||
![]() |
11b2b67f9d | ||
![]() |
0e44255e6a | ||
![]() |
a649d2ec12 | ||
![]() |
8a953e789c | ||
![]() |
317d32eb0c | ||
![]() |
b2ddedc0ae | ||
![]() |
620d2cf730 | ||
![]() |
2578592cc7 | ||
![]() |
44c643d7da | ||
![]() |
39d6edd581 | ||
![]() |
5a14b5bc35 | ||
![]() |
82d9719eee | ||
![]() |
401b75a76b | ||
![]() |
ab75628cf7 | ||
![]() |
57d08e231c | ||
![]() |
f6b800c372 | ||
![]() |
26773ac67f | ||
![]() |
5b63cb38ae | ||
![]() |
30b655a32a | ||
![]() |
f3fa9601c0 | ||
![]() |
034ad05383 | ||
![]() |
7b936fd664 | ||
![]() |
a120f52e0d | ||
![]() |
58f2d22ef4 | ||
![]() |
962777284a | ||
![]() |
d4c8066209 | ||
![]() |
9a9db88efd | ||
![]() |
f5ad9cfe14 | ||
![]() |
d268a7aa23 | ||
![]() |
1896239bd3 | ||
![]() |
07c71750d5 | ||
![]() |
d5171109f5 | ||
![]() |
36aa795c52 | ||
![]() |
7914f56ec3 | ||
![]() |
a39c6c1047 | ||
![]() |
270e07341a | ||
![]() |
da7c66f414 | ||
![]() |
d97b87d9cc | ||
![]() |
bee3361ace | ||
![]() |
276ea4dd98 | ||
![]() |
dd45b47032 | ||
![]() |
1fd4ec3ca3 | ||
![]() |
1e807af2d4 | ||
![]() |
88a5db05b7 | ||
![]() |
e6c8bd0c13 | ||
![]() |
3be9c84f2b | ||
![]() |
881f37f731 | ||
![]() |
4d37f2bab2 | ||
![]() |
3217c2da0b | ||
![]() |
280ae04b3d | ||
![]() |
d5705a52e9 | ||
![]() |
43ab2f22a8 | ||
![]() |
8bb40036bc | ||
![]() |
8ee934404f | ||
![]() |
aa9dbafa28 | ||
![]() |
2b8fea8bf8 | ||
![]() |
985f4293b3 | ||
![]() |
22b162b3c4 | ||
![]() |
7f3d8cfb8d | ||
![]() |
9a7627e35e | ||
![]() |
f141c67ceb | ||
![]() |
e4372644e1 | ||
![]() |
8552b00be4 | ||
![]() |
978fea5dde | ||
![]() |
b3eeaeeda5 | ||
![]() |
0f2ac5104e | ||
![]() |
f7766fff14 | ||
![]() |
b7c2e42190 | ||
![]() |
56472f8dd5 | ||
![]() |
969934b8c0 | ||
![]() |
62f153acd2 | ||
![]() |
b53f16645c | ||
![]() |
6c2786dd78 | ||
![]() |
64a9b0e622 | ||
![]() |
3d05a74ef4 | ||
![]() |
3a1c92944f | ||
![]() |
6b34b82f52 | ||
![]() |
322c090d8a | ||
![]() |
4bb49f9836 | ||
![]() |
20566168a1 | ||
![]() |
03bf4a9ef8 | ||
![]() |
842a76aae1 | ||
![]() |
e3214946a3 | ||
![]() |
36f877c7ff | ||
![]() |
6e41b7ef3d | ||
![]() |
1fc9a9bcea | ||
![]() |
3a439cb81c | ||
![]() |
e8b0de0320 | ||
![]() |
4d033bb379 | ||
![]() |
fffd1ffda3 | ||
![]() |
151f23fd92 | ||
![]() |
25572d6a5b | ||
![]() |
e27efb3946 | ||
![]() |
ca69293d8b | ||
![]() |
f7fa773ec7 | ||
![]() |
f84c4ca73c | ||
![]() |
f9d828ea67 | ||
![]() |
739c977cd7 | ||
![]() |
14b98a32e0 | ||
![]() |
34c9ede9c9 | ||
![]() |
be9f06795d | ||
![]() |
ea9904bd56 | ||
![]() |
501f08dd5e | ||
![]() |
a985cec9c2 | ||
![]() |
c8b0ff22f6 | ||
![]() |
3cc8c1f8c5 | ||
![]() |
5e8b946571 | ||
![]() |
dd4c0d24b7 | ||
![]() |
fc39f1521d | ||
![]() |
60cadb1e11 | ||
![]() |
28c745c19c | ||
![]() |
900b524672 | ||
![]() |
627129dd95 | ||
![]() |
8d18e98ca7 | ||
![]() |
0ba755e463 | ||
![]() |
72215a9f44 | ||
![]() |
2803a6095b | ||
![]() |
d1172f4975 | ||
![]() |
478c4540b1 | ||
![]() |
cc1076e122 | ||
![]() |
15e928ecf2 | ||
![]() |
2c360b6472 | ||
![]() |
f5c99f712a | ||
![]() |
f151bb1451 | ||
![]() |
1061c334ae | ||
![]() |
c5ea50d480 | ||
![]() |
84207effab | ||
![]() |
b568af0a90 | ||
![]() |
11f2f8ff81 | ||
![]() |
454235dd9a | ||
![]() |
ad8dee3c47 | ||
![]() |
5dc0d5536d | ||
![]() |
86699ece8e | ||
![]() |
e3eca5af46 | ||
![]() |
e9f464e34d | ||
![]() |
97775e2a3b | ||
![]() |
54433c43e6 | ||
![]() |
3376908710 | ||
![]() |
284f77b9ae | ||
![]() |
2fe49f316f | ||
![]() |
1428a2485f | ||
![]() |
3a1b4e34aa | ||
![]() |
26fb9a6803 | ||
![]() |
31e6f4282d | ||
![]() |
6bc7de7a6d | ||
![]() |
d9ece291b7 | ||
![]() |
0203a1d4dc | ||
![]() |
221d6e136a | ||
![]() |
ad6e314343 | ||
![]() |
9fc4dbc6d6 | ||
![]() |
5dade92221 | ||
![]() |
4e29960238 | ||
![]() |
3973c57020 | ||
![]() |
dd1dc00430 | ||
![]() |
9a7d6ea7d7 | ||
![]() |
02d4a3b9fe | ||
![]() |
0a60d5f2b2 | ||
![]() |
13ff8f3a84 | ||
![]() |
3efee000ce | ||
![]() |
5915937975 | ||
![]() |
c7621a9e36 | ||
![]() |
28e2463c4f | ||
![]() |
7016d3feea | ||
![]() |
44b4c10bf9 | ||
![]() |
be82c8f6d9 | ||
![]() |
acebf96d2f | ||
![]() |
27c5061d17 | ||
![]() |
fcd034da00 | ||
![]() |
4ee9dbab41 | ||
![]() |
112811190e | ||
![]() |
746295aa16 | ||
![]() |
693c0ba658 | ||
![]() |
e9f37d578e | ||
![]() |
8f4da14611 | ||
![]() |
063b7ce7cc | ||
![]() |
b7243271f3 | ||
![]() |
395ab97191 | ||
![]() |
76da200794 | ||
![]() |
47695debdd | ||
![]() |
a5a2ba9d85 | ||
![]() |
3fa601db3e | ||
![]() |
b60dcb2a23 | ||
![]() |
1e173c6eeb | ||
![]() |
adb11db317 | ||
![]() |
068cb51635 | ||
![]() |
b1eab8bb0d | ||
![]() |
2a4b48d0fa | ||
![]() |
a8e0502b41 | ||
![]() |
ccf0e0dae7 | ||
![]() |
bfa4d3dfec | ||
![]() |
93997c11dc | ||
![]() |
7ce92d5f17 | ||
![]() |
9740010368 | ||
![]() |
e4e0b765b6 | ||
![]() |
51d1dccb42 | ||
![]() |
6f362ee2ad | ||
![]() |
f77bbda5ac | ||
![]() |
dceeaa77c5 | ||
![]() |
d7c96d46e0 | ||
![]() |
b9f5251188 | ||
![]() |
75cdc2c5e8 | ||
![]() |
7eedb14834 | ||
![]() |
ca06154805 | ||
![]() |
35cdef1340 | ||
![]() |
d609c0daeb | ||
![]() |
db0b157d43 | ||
![]() |
906aedd2f1 | ||
![]() |
07a9bdbde3 | ||
![]() |
588b1b1bc3 | ||
![]() |
eb63f89b1f | ||
![]() |
fb81d1b6f3 | ||
![]() |
b897212050 | ||
![]() |
3f6612fe9a | ||
![]() |
bf1a59c5c0 | ||
![]() |
6fb3a3a3c8 | ||
![]() |
ed454b2a4a | ||
![]() |
27f828e619 | ||
![]() |
bde0ce20d8 | ||
![]() |
28c6163a31 | ||
![]() |
14bb377794 | ||
![]() |
61c692ad4e | ||
![]() |
42856e5ac8 | ||
![]() |
e82ad09a8d | ||
![]() |
40fbc55ab3 | ||
![]() |
a27a5b023b | ||
![]() |
a7eb563c2e | ||
![]() |
43fefcf748 | ||
![]() |
621fb95227 | ||
![]() |
d3704fcee6 | ||
![]() |
55100dfb7a | ||
![]() |
010fefcbbc | ||
![]() |
7627f025ed | ||
![]() |
e256d2080d | ||
![]() |
58292067f0 | ||
![]() |
d5e91801d6 | ||
![]() |
91d545f480 | ||
![]() |
9c2599acbe | ||
![]() |
06341ee632 | ||
![]() |
bcc693e4c7 | ||
![]() |
8b8afacaea | ||
![]() |
deb49d7ff9 | ||
![]() |
6334ffa197 | ||
![]() |
b872cce2a4 | ||
![]() |
de2e2ee962 | ||
![]() |
5468676811 | ||
![]() |
c102020698 | ||
![]() |
0ff363b6ee | ||
![]() |
c324cf69ed | ||
![]() |
721cf5c930 | ||
![]() |
f07bcca96a | ||
![]() |
056d0d81ac | ||
![]() |
38ccd37867 | ||
![]() |
21799116c5 | ||
![]() |
60bdf1d1ce | ||
![]() |
02658759ea | ||
![]() |
68946ceede | ||
![]() |
9184ae4608 | ||
![]() |
de64b5ddfa | ||
![]() |
b3ffbbf3ea | ||
![]() |
aa80fdf738 | ||
![]() |
9ad95f51d4 | ||
![]() |
0902a61341 | ||
![]() |
55ffd54e5b | ||
![]() |
e014bfa63e | ||
![]() |
687672e9c1 | ||
![]() |
137889dc9c | ||
![]() |
f24f4a4250 | ||
![]() |
95fc108d57 | ||
![]() |
95f48ba9f6 | ||
![]() |
d80cf232c8 | ||
![]() |
ab3ec875a3 | ||
![]() |
668c9e6045 | ||
![]() |
67b452a461 | ||
![]() |
81ee44b60f | ||
![]() |
9b3bfd14db | ||
![]() |
e00c8fb186 | ||
![]() |
a0919e246d | ||
![]() |
003f684f8a | ||
![]() |
69d55c60c3 | ||
![]() |
560094dcf6 | ||
![]() |
4edd6ce911 | ||
![]() |
f76bd2af8e | ||
![]() |
7747503fee | ||
![]() |
1e1a8ddfb0 | ||
![]() |
9bcd18f1b6 | ||
![]() |
50b6f9a8f2 | ||
![]() |
b4ba88b3e5 | ||
![]() |
ba9acd6e23 | ||
![]() |
dd9513313b | ||
![]() |
288a1c86ab | ||
![]() |
8e28cb10fa | ||
![]() |
3d35a525d3 | ||
![]() |
f7153d0f3b | ||
![]() |
4285b55c15 | ||
![]() |
b54576f08f | ||
![]() |
6b4db681ff | ||
![]() |
f582f781f3 | ||
![]() |
9baecb0a41 | ||
![]() |
91a18e1a92 | ||
![]() |
acfbb0e96d | ||
![]() |
c52292962d | ||
![]() |
6e53743716 | ||
![]() |
873194b402 | ||
![]() |
21dec5feb3 | ||
![]() |
bee4106af0 | ||
![]() |
bbb6e46515 | ||
![]() |
570ebb4f73 | ||
![]() |
d93204af4e | ||
![]() |
702f116db9 | ||
![]() |
0c8607b3ec | ||
![]() |
3a2cc6efc7 | ||
![]() |
1b37ff1655 | ||
![]() |
769934c8a5 | ||
![]() |
7f1a4ec34a | ||
![]() |
27438f7915 | ||
![]() |
8651bef9c1 | ||
![]() |
36324d10dc | ||
![]() |
0272c35047 | ||
![]() |
70c0f912e2 | ||
![]() |
59a6acc088 | ||
![]() |
10b0726727 | ||
![]() |
8f1360d7c2 | ||
![]() |
e0e5ac9ecc | ||
![]() |
c814f219a2 | ||
![]() |
9095fc0c7a | ||
![]() |
a675202537 | ||
![]() |
b52ab4885b | ||
![]() |
43e26c9b56 | ||
![]() |
703a7feed2 | ||
![]() |
7b69ed4cec | ||
![]() |
fcca7f969e | ||
![]() |
ec34ea2116 | ||
![]() |
3dc36c3b92 | ||
![]() |
f0d4fd5523 | ||
![]() |
7fe6c72fe2 | ||
![]() |
d216d0f27f | ||
![]() |
43a7758acd | ||
![]() |
3043956dec | ||
![]() |
06665fdd06 | ||
![]() |
beff5caaac | ||
![]() |
3859412b2c | ||
![]() |
f7ec476fc0 | ||
![]() |
b97d32671d | ||
![]() |
01c56ef280 | ||
![]() |
b9422312f3 | ||
![]() |
9a0f83c3e7 | ||
![]() |
fbfedb2e62 | ||
![]() |
4f8a462041 | ||
![]() |
141d043a6a | ||
![]() |
c1266fed12 | ||
![]() |
4a4be9798d | ||
![]() |
172692ccca | ||
![]() |
50e7c0469f | ||
![]() |
44f74e3590 | ||
![]() |
63656b73c2 | ||
![]() |
40ecf56904 | ||
![]() |
b4a10adec2 | ||
![]() |
1698622d63 | ||
![]() |
fa27271647 | ||
![]() |
d837811c68 | ||
![]() |
ad195f0969 | ||
![]() |
4a8748e322 | ||
![]() |
0f016c83ea | ||
![]() |
061ae44da4 | ||
![]() |
a8b90bf100 | ||
![]() |
eb3cd49bc4 | ||
![]() |
416d869288 | ||
![]() |
a116c26c25 | ||
![]() |
cc4ec53dac | ||
![]() |
63164c7ff5 | ||
![]() |
9815c014e8 | ||
![]() |
69675151bf | ||
![]() |
99e395ddfa | ||
![]() |
7fe1e542df | ||
![]() |
938134081b | ||
![]() |
3fd2234a92 | ||
![]() |
41843dc573 | ||
![]() |
cc6bd528a5 | ||
![]() |
2625ef5fb9 | ||
![]() |
dbd2d28877 | ||
![]() |
f70f814c70 | ||
![]() |
6710e42134 | ||
![]() |
78c5b45e43 | ||
![]() |
e562ec96fa | ||
![]() |
9b5e01c319 | ||
![]() |
0097532f4a | ||
![]() |
91935c9018 | ||
![]() |
83df807f7e | ||
![]() |
eb3db20340 | ||
![]() |
6dab6194ea | ||
![]() |
356f64cac0 | ||
![]() |
f77f289125 | ||
![]() |
280257477a | ||
![]() |
660141cb16 | ||
![]() |
cd8a899521 | ||
![]() |
cb577c51b8 | ||
![]() |
1c395ab10c | ||
![]() |
07d7170e49 | ||
![]() |
88e23627fd | ||
![]() |
48f846da40 | ||
![]() |
ff887d9948 | ||
![]() |
617b0d6fd9 | ||
![]() |
805d45bd33 | ||
![]() |
fef428202f | ||
![]() |
40fd82febd | ||
![]() |
45f0001da5 | ||
![]() |
c7a3e1e3bf | ||
![]() |
9dd8cc9e49 | ||
![]() |
d252d4cd2d | ||
![]() |
bc1328040c | ||
![]() |
82919d3c1d | ||
![]() |
7c801c2f5e | ||
![]() |
9a932aea12 | ||
![]() |
5696e75abe | ||
![]() |
efb3f748c2 | ||
![]() |
450b3865a8 | ||
![]() |
970667adca | ||
![]() |
89307dad01 | ||
![]() |
451feda86b | ||
![]() |
4d241fac48 | ||
![]() |
4390f5cbc8 | ||
![]() |
7f9d46eac3 | ||
![]() |
d0f28883aa | ||
![]() |
48203e64a9 | ||
![]() |
42b17ca495 | ||
![]() |
d8080fe506 | ||
![]() |
be910e24f7 | ||
![]() |
ce6d70f6fd | ||
![]() |
827e05e4d7 | ||
![]() |
43e40e99f1 | ||
![]() |
d95afa990d | ||
![]() |
e14457da58 | ||
![]() |
9613934ae5 | ||
![]() |
07a48c04d7 | ||
![]() |
fbcf59abf0 | ||
![]() |
2ef40a6a1c | ||
![]() |
5b5c4d1a8b | ||
![]() |
5f2a74893a | ||
![]() |
0741b4021c | ||
![]() |
f2323b0dff | ||
![]() |
0462121f69 | ||
![]() |
fe4ddaeb52 | ||
![]() |
bdbfafabbd | ||
![]() |
42c6340c06 | ||
![]() |
39e1caec0f | ||
![]() |
ef72832e5a | ||
![]() |
39eb657012 | ||
![]() |
b8f8d45807 | ||
![]() |
b01fefc235 | ||
![]() |
09f6eb8e19 | ||
![]() |
e5d4969917 | ||
![]() |
53aa740305 | ||
![]() |
9a00350ffc | ||
![]() |
98ffa3735b | ||
![]() |
9073568c0f | ||
![]() |
17a01d65aa | ||
![]() |
5089575aac | ||
![]() |
7f178e0913 | ||
![]() |
dcad3017d3 | ||
![]() |
ae88489e55 | ||
![]() |
b57065d6ee | ||
![]() |
71551d3f6d | ||
![]() |
cbcad30a6c | ||
![]() |
e2c2f66e97 | ||
![]() |
eeff665680 | ||
![]() |
6ef9d187ba | ||
![]() |
6d23ef9105 | ||
![]() |
6c8b425fb3 | ||
![]() |
d4b46a5721 | ||
![]() |
9d2be4b939 | ||
![]() |
bc017fb010 | ||
![]() |
bfabbe3cdb | ||
![]() |
8a8d47f8e7 | ||
![]() |
b01fac9641 | ||
![]() |
25c850e243 | ||
![]() |
8c7476a670 | ||
![]() |
12effd643f | ||
![]() |
209008e50d | ||
![]() |
b336f07ff9 | ||
![]() |
73f6012507 | ||
![]() |
b73564d2e0 | ||
![]() |
00adb45086 | ||
![]() |
d604d40e91 | ||
![]() |
ba3f6935db | ||
![]() |
980c4f7618 | ||
![]() |
a869859491 | ||
![]() |
15a638b86e | ||
![]() |
e999000102 | ||
![]() |
95bdc000ca | ||
![]() |
1d46efe037 | ||
![]() |
5499e89058 | ||
![]() |
a5653e365e | ||
![]() |
35a0242037 | ||
![]() |
e698bcb375 | ||
![]() |
33d5aca6d4 | ||
![]() |
058bd32329 | ||
![]() |
52d38883dc | ||
![]() |
c1d98ab901 | ||
![]() |
e555b7e456 | ||
![]() |
031bef8c02 | ||
![]() |
3bf138e2ad | ||
![]() |
4e0563bbf9 | ||
![]() |
e2e7063a29 | ||
![]() |
03035d0eac | ||
![]() |
7ce9283421 | ||
![]() |
a8783ac351 | ||
![]() |
fb51894fad | ||
![]() |
25d65e8d65 | ||
![]() |
3e10e0e511 | ||
![]() |
c3245c1f03 | ||
![]() |
5b022599b4 | ||
![]() |
d5d219d46f | ||
![]() |
e546689e01 | ||
![]() |
cac9e0b164 | ||
![]() |
4bb5920c04 | ||
![]() |
3ea257f8f3 | ||
![]() |
347db6b770 | ||
![]() |
fafe28a6d6 | ||
![]() |
eb6cb60ee3 | ||
![]() |
8226a14b00 | ||
![]() |
c6bd1b06f2 | ||
![]() |
be38028244 | ||
![]() |
b8ea04f5a4 | ||
![]() |
cd5ed1d748 | ||
![]() |
00c9fc79f9 | ||
![]() |
d5373c3992 | ||
![]() |
3001ff8c53 | ||
![]() |
0571a091f7 | ||
![]() |
1bca410bcb | ||
![]() |
463ed2f46a | ||
![]() |
f8f0717913 | ||
![]() |
53cd759422 | ||
![]() |
7047ac8007 | ||
![]() |
2efd81dc6a | ||
![]() |
773ee8664c | ||
![]() |
d779e72bcd | ||
![]() |
2e101dcf7d | ||
![]() |
e6befab6bb | ||
![]() |
9ee2c1f7a6 | ||
![]() |
5b82a86fa8 | ||
![]() |
922bb2760c | ||
![]() |
315be9f3eb | ||
![]() |
7bb9c6c915 | ||
![]() |
4b5f880ccb | ||
![]() |
5db309d142 | ||
![]() |
5d8a7d80eb | ||
![]() |
1394339df6 | ||
![]() |
801510c61e | ||
![]() |
6c8d6ed2ca | ||
![]() |
d8f223327e | ||
![]() |
fc2faa247a | ||
![]() |
9b11fd4f18 | ||
![]() |
ccac7d1bd4 | ||
![]() |
5494d1e7bf | ||
![]() |
1ab407eb38 | ||
![]() |
82ab732144 | ||
![]() |
0343d47a9d | ||
![]() |
2162210393 | ||
![]() |
54a7839421 | ||
![]() |
576ac88a6a | ||
![]() |
426fc09b17 | ||
![]() |
22bc0b3f9a | ||
![]() |
4ece976dc8 | ||
![]() |
3ff0b4a256 | ||
![]() |
ecfc3ed74f | ||
![]() |
976154ed6c | ||
![]() |
e527a88a2e | ||
![]() |
d6b619934a | ||
![]() |
c108765857 | ||
![]() |
96438e1e15 | ||
![]() |
0afd77fb2f | ||
![]() |
a6cd512ebf | ||
![]() |
fb5d97a627 | ||
![]() |
231d439ef8 | ||
![]() |
28e48e6b2f | ||
![]() |
89c1ec8d21 | ||
![]() |
3270a60bd7 | ||
![]() |
6ccf801ee6 | ||
![]() |
79cd2ca9b9 | ||
![]() |
063271aabb | ||
![]() |
e6c2133bf5 | ||
![]() |
63e056987a | ||
![]() |
93f070f0ac | ||
![]() |
df35689c35 | ||
![]() |
b66e845c6e | ||
![]() |
3ca4351aeb | ||
![]() |
6d5c320701 | ||
![]() |
400a189455 | ||
![]() |
b7d03a4f31 | ||
![]() |
523e6421be | ||
![]() |
0ed4b69b8f | ||
![]() |
94f929743c | ||
![]() |
e0cd6f7071 | ||
![]() |
38db0b7a70 | ||
![]() |
f39ecd89a7 | ||
![]() |
f7f76d82b6 | ||
![]() |
9097e79e4f | ||
![]() |
88711e7601 | ||
![]() |
d0fa83bb8c | ||
![]() |
1271458f83 | ||
![]() |
2ae09a07e6 | ||
![]() |
9e9ad72dc2 | ||
![]() |
422a89c26c | ||
![]() |
798c17706c | ||
![]() |
33d860384c | ||
![]() |
a4eda99a4a | ||
![]() |
752c7badd2 | ||
![]() |
6399c90642 | ||
![]() |
97089846e9 | ||
![]() |
4de7884e39 | ||
![]() |
440adfb914 | ||
![]() |
5f26d0085d | ||
![]() |
f484604c69 | ||
![]() |
899d2fbf9d | ||
![]() |
6a87dc9c40 | ||
![]() |
104e2929df | ||
![]() |
faac6b11c2 | ||
![]() |
377a23478e | ||
![]() |
c979e78802 | ||
![]() |
38f64c7d85 | ||
![]() |
1091a64863 | ||
![]() |
23de9616f1 | ||
![]() |
198e7767dc | ||
![]() |
aa31bf1a19 | ||
![]() |
f366304c50 | ||
![]() |
ce289995ff | ||
![]() |
ca2b4085c9 | ||
![]() |
1d08069162 | ||
![]() |
bcbfaae630 | ||
![]() |
0886d133a8 | ||
![]() |
ae9df92d28 | ||
![]() |
435230711e | ||
![]() |
d75744bb4a | ||
![]() |
47610323b0 | ||
![]() |
d1f1763919 | ||
![]() |
1326ad8708 | ||
![]() |
86d737dcf6 | ||
![]() |
9e0153e962 | ||
![]() |
fb395fc2e9 | ||
![]() |
6e09e509bd | ||
![]() |
e8d0557852 | ||
![]() |
aac705f465 | ||
![]() |
009971901b | ||
![]() |
573ff3f2a6 | ||
![]() |
b9f614c66f | ||
![]() |
e26182c96e | ||
![]() |
f4eff8a8c5 | ||
![]() |
1ffd6c0ea1 | ||
![]() |
b3f8341e0c | ||
![]() |
50ce29cc64 | ||
![]() |
47db4e0559 | ||
![]() |
b8179678c6 | ||
![]() |
c1a7b3753c | ||
![]() |
e4ec24be26 | ||
![]() |
04765288d7 | ||
![]() |
8fdd0ba0d9 | ||
![]() |
8b312c8d2d | ||
![]() |
ab36041fef | ||
![]() |
3f87996bfc | ||
![]() |
4edd2001b3 | ||
![]() |
155b98bb0c | ||
![]() |
16ffbd9940 | ||
![]() |
f72d93216c | ||
![]() |
c6cf293b12 | ||
![]() |
0f13329ddd | ||
![]() |
fa61302954 | ||
![]() |
1dfbef89ff | ||
![]() |
c55c00a19e | ||
![]() |
2fa62f71e1 | ||
![]() |
846a8cac98 | ||
![]() |
9ee7918e59 | ||
![]() |
763e5f583a | ||
![]() |
faf5cb0f8d | ||
![]() |
bde6309277 | ||
![]() |
cc05552685 | ||
![]() |
465f50666f | ||
![]() |
e6d0212604 | ||
![]() |
2eebacc3a6 | ||
![]() |
f362880eb6 | ||
![]() |
68a06d1bbc | ||
![]() |
82c09570c4 | ||
![]() |
58eb426eea | ||
![]() |
1c932057b8 | ||
![]() |
4564623884 | ||
![]() |
843a400b2d | ||
![]() |
5b067bd17d | ||
![]() |
ed07bd374c | ||
![]() |
078685a2a3 | ||
![]() |
2ce5194156 | ||
![]() |
fa97d3f88d | ||
![]() |
08c8ee0774 | ||
![]() |
395fc49087 | ||
![]() |
9725c82187 | ||
![]() |
24277f1e3c | ||
![]() |
b58fb1da33 | ||
![]() |
d54794e85f | ||
![]() |
bed1cd8fb5 | ||
![]() |
d5917f89f0 | ||
![]() |
c2d17c285a | ||
![]() |
42262b0bb6 | ||
![]() |
510dddf724 | ||
![]() |
702b2fe167 | ||
![]() |
f24c2a8b77 | ||
![]() |
a675c2c4f2 | ||
![]() |
2984629b39 | ||
![]() |
1003aa2df5 | ||
![]() |
1c56d9c513 | ||
![]() |
e06210f21c | ||
![]() |
ad112e0a44 | ||
![]() |
2b0e7daf7c | ||
![]() |
060dff0162 | ||
![]() |
4ae09774f7 | ||
![]() |
033a364699 | ||
![]() |
56a66976e6 | ||
![]() |
0f02fab259 | ||
![]() |
2917b609c3 | ||
![]() |
b9a80d06e4 | ||
![]() |
af46a02146 | ||
![]() |
19d8c1be5a | ||
![]() |
6205af1a9a | ||
![]() |
d8b1db536c | ||
![]() |
699357ca21 | ||
![]() |
50398049f5 | ||
![]() |
1f83afc2f4 | ||
![]() |
90374bb46f | ||
![]() |
ccdd410eda | ||
![]() |
77bb806a01 | ||
![]() |
a952352e1f | ||
![]() |
b733ce969a | ||
![]() |
f4351df302 | ||
![]() |
76893100fc | ||
![]() |
96e8b808da | ||
![]() |
595bff94b4 | ||
![]() |
5661c00497 | ||
![]() |
a98d7bd4eb | ||
![]() |
097203162d | ||
![]() |
823c9b3159 | ||
![]() |
35965a6a1b | ||
![]() |
8d67cc4c5a | ||
![]() |
42e33a0468 | ||
![]() |
b2529db026 | ||
![]() |
e99c4aec4a | ||
![]() |
2d0a97f259 | ||
![]() |
fabb52763b | ||
![]() |
03dd1a6974 | ||
![]() |
ecee50a5e4 | ||
![]() |
cbab7c4cbf | ||
![]() |
257ea14c59 | ||
![]() |
11299291b0 | ||
![]() |
f63c1c2f7f | ||
![]() |
533b8076e4 | ||
![]() |
b0383b4813 | ||
![]() |
5045e406a1 | ||
![]() |
8d5bc88fd9 | ||
![]() |
96500f75b0 | ||
![]() |
2a3bd3413f | ||
![]() |
8ec136a0ca | ||
![]() |
2bead0fc29 | ||
![]() |
359776d48a | ||
![]() |
05a16bb199 | ||
![]() |
f457704105 | ||
![]() |
5aa59b93b0 | ||
![]() |
47d51f92c7 | ||
![]() |
068cf17d0a | ||
![]() |
3c1b849a5d | ||
![]() |
8384ec7f15 | ||
![]() |
0e7a3962bb | ||
![]() |
3d1bb9975c | ||
![]() |
eed473be15 | ||
![]() |
e23d9bca22 | ||
![]() |
85a952a5c9 | ||
![]() |
5cc36310ba | ||
![]() |
8690d2ced5 | ||
![]() |
f572943a7b | ||
![]() |
89248ad46a | ||
![]() |
517db71916 | ||
![]() |
ad82de010d | ||
![]() |
02fd9edbbf | ||
![]() |
6c84dd7be8 | ||
![]() |
9edbe6af37 | ||
![]() |
37d09e9bad | ||
![]() |
0d0595e9a0 | ||
![]() |
17477455cb | ||
![]() |
43f594709d | ||
![]() |
8885b3e7e0 | ||
![]() |
c060638539 | ||
![]() |
2144d4d7ed | ||
![]() |
4f2e09d733 | ||
![]() |
9d13c29bf6 | ||
![]() |
60d577f95e | ||
![]() |
1dd1c6f67f | ||
![]() |
bcd0691b33 | ||
![]() |
24a2559ab5 | ||
![]() |
22a6bae4cf | ||
![]() |
2c45de1fe5 | ||
![]() |
0ab93d7a7f | ||
![]() |
c8831efb28 | ||
![]() |
0cbde5a2f5 | ||
![]() |
7de82d87f7 | ||
![]() |
751b97a39c | ||
![]() |
7b58bcc279 | ||
![]() |
820a2e688c | ||
![]() |
10a7f540ad | ||
![]() |
31a6c627af | ||
![]() |
aba4cbf9e4 | ||
![]() |
a5624e86e4 | ||
![]() |
5480d09a0b | ||
![]() |
5fad0a1d97 | ||
![]() |
4a7b5bab54 | ||
![]() |
fe0557dcc1 | ||
![]() |
e4b6d61098 | ||
![]() |
73e01ebaaf | ||
![]() |
d752d46676 | ||
![]() |
3932409fb4 | ||
![]() |
f69d4f1c42 | ||
![]() |
96699fc3b0 | ||
![]() |
97ec8f6828 | ||
![]() |
df851e67f9 | ||
![]() |
5d1bc3cf9b | ||
![]() |
81ab9b006d | ||
![]() |
1699fc09cf | ||
![]() |
f8b6a9f1e8 | ||
![]() |
ba465a0d15 | ||
![]() |
af521b4058 | ||
![]() |
27b512611f | ||
![]() |
b79f165a27 | ||
![]() |
716f76baed | ||
![]() |
18c57a4fc6 | ||
![]() |
c26483b4b8 | ||
![]() |
441e39d776 | ||
![]() |
7ecc075c7e | ||
![]() |
2e42663832 | ||
![]() |
075f9f8cbd | ||
![]() |
f3d42e7b53 | ||
![]() |
fa0b547b32 | ||
![]() |
8f19cdccfd | ||
![]() |
5c207aeee6 | ||
![]() |
d48273ef98 | ||
![]() |
a7803dcad7 | ||
![]() |
4fc9b6fdb4 | ||
![]() |
73f8f83658 | ||
![]() |
66a0f953b3 | ||
![]() |
f189eea32b | ||
![]() |
be29d879a7 | ||
![]() |
e3e906c9e5 | ||
![]() |
6fce31e1b9 | ||
![]() |
db1cb3d658 | ||
![]() |
c0d7c5ddff | ||
![]() |
d0cd2672dd | ||
![]() |
ca55900d40 | ||
![]() |
3d65ffc6d3 | ||
![]() |
f94b796c2b | ||
![]() |
66c1fd6593 | ||
![]() |
13a45facf9 | ||
![]() |
26f10b2c3d | ||
![]() |
9aea4c85b0 | ||
![]() |
ee1b0eeeff | ||
![]() |
c6cfb4a020 | ||
![]() |
91da41ff86 | ||
![]() |
a811edb236 | ||
![]() |
66de806b02 | ||
![]() |
c825176563 | ||
![]() |
7ae87fe0e7 | ||
![]() |
99f826c236 | ||
![]() |
f88d673e87 | ||
![]() |
bc2f73d686 | ||
![]() |
645c2ecef6 | ||
![]() |
4d4a8ca3b2 | ||
![]() |
a98bc45c10 | ||
![]() |
aa5affe366 | ||
![]() |
b39ac866f2 | ||
![]() |
b9d5e49a71 | ||
![]() |
e90390be67 | ||
![]() |
8ef671c9cb | ||
![]() |
8829516cae | ||
![]() |
4c211342a2 | ||
![]() |
6b7cd38d71 | ||
![]() |
d8e8dfbd45 | ||
![]() |
485609fbb9 | ||
![]() |
0b6d9a4890 | ||
![]() |
55ffd68023 | ||
![]() |
6380de3e6c | ||
![]() |
d6220a921a | ||
![]() |
10e421b9d4 | ||
![]() |
90056bcce2 | ||
![]() |
4740d0fbf3 | ||
![]() |
13374c9ded | ||
![]() |
2a03be1905 | ||
![]() |
c8f132a750 | ||
![]() |
4d0c4bf4f4 | ||
![]() |
e321c5b197 | ||
![]() |
badbfdc4c1 | ||
![]() |
7d71086a41 | ||
![]() |
0e1764755a | ||
![]() |
c31d3ffd6c | ||
![]() |
0cba3988aa | ||
![]() |
a7a9ed8628 | ||
![]() |
6af96332fa | ||
![]() |
e334a0fc8b | ||
![]() |
54bbbb36a6 | ||
![]() |
b8ef56574a | ||
![]() |
bc491628d4 | ||
![]() |
629800c239 | ||
![]() |
8bf876f88c | ||
![]() |
a81ad6d73e | ||
![]() |
02220209e3 | ||
![]() |
9450a1434d | ||
![]() |
c358693fb2 | ||
![]() |
e7b3d768ce | ||
![]() |
ee91da2ff1 | ||
![]() |
0428df8e3f | ||
![]() |
d4fee1d701 | ||
![]() |
3b44a3afd2 | ||
![]() |
7ee1c51810 | ||
![]() |
f958de2de6 | ||
![]() |
b83eb2e763 | ||
![]() |
41c9369b43 | ||
![]() |
554be92c39 | ||
![]() |
a44709a43d | ||
![]() |
65e9e2b680 | ||
![]() |
d84dc23b46 | ||
![]() |
7486a50c33 | ||
![]() |
e333940826 | ||
![]() |
70f7fd2de9 | ||
![]() |
411d88d798 | ||
![]() |
1e777b1a1b | ||
![]() |
b7bb159630 | ||
![]() |
dce8248eb8 | ||
![]() |
3b8234ce67 | ||
![]() |
ac63d3c3ce | ||
![]() |
197c3a327b | ||
![]() |
6e0a0d51b5 | ||
![]() |
55aad4e6ee | ||
![]() |
d1e401cb0c | ||
![]() |
0bb97fee31 | ||
![]() |
1bdf6bbb66 | ||
![]() |
077dfe7164 | ||
![]() |
169f83ac4a | ||
![]() |
121dad588e | ||
![]() |
018479fae9 | ||
![]() |
bb3a11ad00 | ||
![]() |
64d3bd9c4f | ||
![]() |
e6be03a770 | ||
![]() |
5f722570d2 | ||
![]() |
dcbeca5f7f | ||
![]() |
16742d4705 | ||
![]() |
d21a03905d | ||
![]() |
0608b2a1df | ||
![]() |
5f237c7c71 | ||
![]() |
4c98b0a43d | ||
![]() |
05afa0859c | ||
![]() |
597cc9fe29 | ||
![]() |
ab6196589b | ||
![]() |
221be380ee | ||
![]() |
a68e5f6519 | ||
![]() |
bc81f19715 | ||
![]() |
ceeeea94ba | ||
![]() |
31ab5daa91 | ||
![]() |
8f6639028f | ||
![]() |
a2b686f6df | ||
![]() |
2dcc74d82d | ||
![]() |
d460263b97 | ||
![]() |
b8cfa343ae | ||
![]() |
8d391f125c | ||
![]() |
1532bb731a | ||
![]() |
357ba9ec59 | ||
![]() |
183c810c76 | ||
![]() |
f2d7beec90 | ||
![]() |
84ce4758d1 | ||
![]() |
4d6279a626 | ||
![]() |
f28e741ad7 | ||
![]() |
23c4e5b09d | ||
![]() |
cd6057e1ca | ||
![]() |
1771674b53 | ||
![]() |
2a9d0ea7d2 | ||
![]() |
e19938b05e | ||
![]() |
244a3e5be3 | ||
![]() |
e5a3d534b2 | ||
![]() |
c279057f91 | ||
![]() |
1c18e72539 | ||
![]() |
779e710045 | ||
![]() |
089a981f6e | ||
![]() |
3b24bbee5f | ||
![]() |
f9a597bed9 | ||
![]() |
a637b3bb24 | ||
![]() |
3e520820d8 | ||
![]() |
3a71929821 | ||
![]() |
a08629c503 | ||
![]() |
cfc30c1234 | ||
![]() |
ddbd486500 | ||
![]() |
f5794a5bae | ||
![]() |
bb1bf87fe2 | ||
![]() |
acc59523e0 | ||
![]() |
38d7ea16b4 | ||
![]() |
6e3147c5f5 | ||
![]() |
1b09f225ff | ||
![]() |
3cf8c4f8a8 | ||
![]() |
30be4b473f | ||
![]() |
6908034a86 | ||
![]() |
cba43f675a | ||
![]() |
6ff826bc3a | ||
![]() |
c7afd10ec0 | ||
![]() |
b39d5174f9 | ||
![]() |
501bc0ab3f | ||
![]() |
688d28b5ea | ||
![]() |
27d2c7b078 | ||
![]() |
2fb12ccf65 | ||
![]() |
cb92d159c1 | ||
![]() |
64bdf4237c | ||
![]() |
fd7b4ec7e3 | ||
![]() |
57eb57d4d7 | ||
![]() |
7974e9505b | ||
![]() |
7498fb37b5 | ||
![]() |
2cc3e88e6c | ||
![]() |
5fd8cfeb80 | ||
![]() |
b295566a4e | ||
![]() |
e0943a2d55 | ||
![]() |
3015740c3e | ||
![]() |
ec9ff2f803 | ||
![]() |
ec8aae9122 | ||
![]() |
52e608cc43 | ||
![]() |
8213f270e5 | ||
![]() |
7085042b0d | ||
![]() |
6a411d2458 | ||
![]() |
38e2fbabb8 | ||
![]() |
85709f754a | ||
![]() |
623a1e8a91 | ||
![]() |
de69945ebe | ||
![]() |
7095fa6ac6 | ||
![]() |
a59e8298fd | ||
![]() |
2737d52279 | ||
![]() |
0ac1ad4386 | ||
![]() |
2db328ac31 | ||
![]() |
b6de4ad054 | ||
![]() |
cfea7164b7 | ||
![]() |
7e7e5a6be4 | ||
![]() |
df57f4c009 | ||
![]() |
c2185c4ce5 | ||
![]() |
08714436c3 | ||
![]() |
f65f5d07c0 | ||
![]() |
a9b10c4560 | ||
![]() |
589fbd3158 | ||
![]() |
0ffc8c5d19 | ||
![]() |
7498617b74 | ||
![]() |
f21d505ab8 | ||
![]() |
7b16af0585 | ||
![]() |
a83108282a | ||
![]() |
1c4d01d6ec | ||
![]() |
22e6d4067d |
11
.dockerignore
Normal file
@@ -0,0 +1,11 @@
|
||||
.git
|
||||
.github
|
||||
.gitignore
|
||||
contrib
|
||||
init-scripts
|
||||
package
|
||||
pylintrc
|
||||
snap
|
||||
*.md
|
||||
!CHANGELOG*.md
|
||||
start.bat
|
3
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
github: JonnyWong16
|
||||
patreon: Tautulli
|
||||
custom: ["https://bit.ly/2InPp15"]
|
20
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
## Description
|
||||
|
||||
Please include a summary of the change and which issue is fixed.
|
||||
|
||||
Fixes Tautulli/Tautulli-Issues#(issue)
|
||||
|
||||
## Type of change
|
||||
|
||||
Please delete options that are not relevant.
|
||||
|
||||
- [ ] Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
|
||||
## Checklist:
|
||||
|
||||
- [ ] My code follows the style guidelines of this project
|
||||
- [ ] I have performed a self-review of my own code
|
||||
- [ ] I have commented my code, particularly in hard-to-understand areas
|
||||
- [ ] I have added or updated the docstring for new or existing methods
|
115
.github/workflows/publish-docker.yml
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
name: Publish Docker
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master, beta, nightly]
|
||||
tags: [v*]
|
||||
pull_request: ~
|
||||
|
||||
jobs:
|
||||
build-docker:
|
||||
name: Build Docker Image
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Prepare
|
||||
id: prepare
|
||||
run: |
|
||||
if [[ $GITHUB_REF == refs/tags/* ]]; then
|
||||
echo ::set-output name=tag::${GITHUB_REF#refs/tags/}
|
||||
elif [[ $GITHUB_REF == refs/heads/master ]]; then
|
||||
echo ::set-output name=tag::latest
|
||||
else
|
||||
echo ::set-output name=tag::${GITHUB_REF#refs/heads/}
|
||||
fi
|
||||
if [[ $GITHUB_REF == refs/tags/*-beta ]]; then
|
||||
echo ::set-output name=branch::beta
|
||||
elif [[ $GITHUB_REF == refs/tags/* ]]; then
|
||||
echo ::set-output name=branch::master
|
||||
else
|
||||
echo ::set-output name=branch::${GITHUB_REF#refs/heads/}
|
||||
fi
|
||||
echo ::set-output name=commit::${GITHUB_SHA}
|
||||
echo ::set-output name=build_date::$(date -u +'%Y-%m-%dT%H:%M:%SZ')
|
||||
echo ::set-output name=docker_platforms::linux/amd64,linux/arm64/v8,linux/arm/v7,linux/arm/v6
|
||||
echo ::set-output name=docker_image::${{ secrets.DOCKER_REPO }}/tautulli
|
||||
|
||||
- name: Set Up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
id: buildx
|
||||
with:
|
||||
version: latest
|
||||
|
||||
- name: Cache Docker Layers
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
if: success() && github.event_name != 'pull_request'
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v1
|
||||
if: success() && github.event_name != 'pull_request'
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.GHCR_TOKEN }}
|
||||
|
||||
- name: Docker Build and Push
|
||||
uses: docker/build-push-action@v2
|
||||
if: success()
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
platforms: ${{ steps.prepare.outputs.docker_platforms }}
|
||||
build-args: |
|
||||
TAG=${{ steps.prepare.outputs.tag }}
|
||||
BRANCH=${{ steps.prepare.outputs.branch }}
|
||||
COMMIT=${{ steps.prepare.outputs.commit }}
|
||||
BUILD_DATE=${{ steps.prepare.outputs.build_date }}
|
||||
tags: |
|
||||
${{ steps.prepare.outputs.docker_image }}:${{ steps.prepare.outputs.tag }}
|
||||
ghcr.io/${{ steps.prepare.outputs.docker_image }}:${{ steps.prepare.outputs.tag }}
|
||||
cache-from: type=local,src=/tmp/.buildx-cache
|
||||
cache-to: type=local,dest=/tmp/.buildx-cache
|
||||
|
||||
discord:
|
||||
name: Discord Notification
|
||||
needs: build-docker
|
||||
if: always() && github.event_name != 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Get Build Job Status
|
||||
uses: technote-space/workflow-conclusion-action@v1
|
||||
|
||||
- name: Combine Job Status
|
||||
id: status
|
||||
run: |
|
||||
failures=(neutral, skipped, timed_out, action_required)
|
||||
if [[ ${array[@]} =~ $WORKFLOW_CONCLUSION ]]; then
|
||||
echo ::set-output name=status::failure
|
||||
else
|
||||
echo ::set-output name=status::$WORKFLOW_CONCLUSION
|
||||
fi
|
||||
|
||||
- name: Post Status to Discord
|
||||
uses: sarisia/actions-status-discord@v1
|
||||
with:
|
||||
webhook: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
status: ${{ steps.status.outputs.status }}
|
||||
title: ${{ github.workflow }}
|
||||
nofail: true
|
183
.github/workflows/publish-installers.yml
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
name: Publish Installers
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master, beta, nightly]
|
||||
tags: [v*]
|
||||
pull_request: ~
|
||||
|
||||
jobs:
|
||||
build-installer:
|
||||
name: Build ${{ matrix.os_upper }} Installer
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: 'windows'
|
||||
os_upper: 'Windows'
|
||||
ext: 'exe'
|
||||
- os: 'macos'
|
||||
os_upper: 'MacOS'
|
||||
ext: 'pkg'
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set Release Version
|
||||
id: get_version
|
||||
shell: bash
|
||||
run: |
|
||||
if [[ $GITHUB_REF == refs/tags/* ]]; then
|
||||
echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
|
||||
VERSION_NSIS=${GITHUB_REF#refs/tags/v}.1
|
||||
echo ::set-output name=VERSION_NSIS::${VERSION_NSIS/%-beta.1/.0}
|
||||
echo ::set-output name=VERSION::${GITHUB_REF#refs/tags/v}
|
||||
echo ::set-output name=RELEASE_VERSION::${GITHUB_REF#refs/tags/}
|
||||
else
|
||||
echo "VERSION=0.0.0" >> $GITHUB_ENV
|
||||
echo ::set-output name=VERSION_NSIS::0.0.0.0
|
||||
echo ::set-output name=VERSION::0.0.0
|
||||
echo ::set-output name=RELEASE_VERSION::${GITHUB_SHA::7}
|
||||
fi
|
||||
echo $GITHUB_SHA > version.txt
|
||||
|
||||
- name: Set Up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
|
||||
- name: Cache Dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~\AppData\Local\pip\Cache
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles(format('package/requirements-{0}.txt', matrix.os)) }}
|
||||
restore-keys: ${{ runner.os }}-pip-
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r package/requirements-${{ matrix.os }}.txt
|
||||
|
||||
- name: Build Package
|
||||
run: |
|
||||
pyinstaller -y ./package/Tautulli-${{ matrix.os }}.spec
|
||||
|
||||
- name: Create Windows Installer
|
||||
uses: joncloud/makensis-action@v1.2
|
||||
if: matrix.os == 'windows'
|
||||
with:
|
||||
script-file: ./package/Tautulli.nsi
|
||||
arguments: >
|
||||
/DVERSION=${{ steps.get_version.outputs.VERSION_NSIS }}
|
||||
/DINSTALLER_NAME=..\Tautulli-windows-${{ steps.get_version.outputs.RELEASE_VERSION }}-x64.exe
|
||||
include-more-plugins: true
|
||||
include-custom-plugins-path: package/nsis-plugins
|
||||
|
||||
- name: Create MacOS Installer
|
||||
if: matrix.os == 'macos'
|
||||
run: |
|
||||
sudo pkgbuild \
|
||||
--install-location /Applications \
|
||||
--version ${{ steps.get_version.outputs.VERSION }} \
|
||||
--component ./dist/Tautulli.app \
|
||||
--scripts ./package/macos-scripts \
|
||||
Tautulli-macos-${{ steps.get_version.outputs.RELEASE_VERSION }}-x64.pkg
|
||||
|
||||
- name: Upload Installer
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Tautulli-${{ matrix.os }}-installer
|
||||
path: Tautulli-${{ matrix.os }}-${{ steps.get_version.outputs.RELEASE_VERSION }}-x64.${{ matrix.ext }}
|
||||
|
||||
release:
|
||||
name: Release Installers
|
||||
needs: build-installer
|
||||
if: always() && startsWith(github.ref, 'refs/tags/') && github.event_name != 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Get Build Job Status
|
||||
uses: technote-space/workflow-conclusion-action@v1
|
||||
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set Release Version
|
||||
id: get_version
|
||||
run: |
|
||||
echo ::set-output name=RELEASE_VERSION::${GITHUB_REF#refs/tags/}
|
||||
|
||||
- name: Download Installers
|
||||
if: env.WORKFLOW_CONCLUSION == 'success'
|
||||
uses: actions/download-artifact@v2
|
||||
|
||||
- name: Get Changelog
|
||||
id: get_changelog
|
||||
run: |
|
||||
echo ::set-output name=CHANGELOG::"$( sed -n '/^## /{p; :loop n; p; /^## /q; b loop}' CHANGELOG.md \
|
||||
| sed '$d' | sed '$d' | sed '$d' | sed ':a;N;$!ba;s/\n/%0A/g' )"
|
||||
|
||||
- name: Create Release
|
||||
uses: actions/create-release@v1
|
||||
id: create_release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ steps.get_version.outputs.RELEASE_VERSION }}
|
||||
release_name: Tautulli ${{ steps.get_version.outputs.RELEASE_VERSION }}
|
||||
body: |
|
||||
## Changelog
|
||||
|
||||
##${{ steps.get_changelog.outputs.CHANGELOG }}
|
||||
draft: false
|
||||
prerelease: ${{ endsWith(steps.get_version.outputs.RELEASE_VERSION, '-beta') }}
|
||||
|
||||
- name: Upload Windows Installer
|
||||
uses: actions/upload-release-asset@v1
|
||||
if: env.WORKFLOW_CONCLUSION == 'success'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: Tautulli-windows-installer/Tautulli-windows-${{ steps.get_version.outputs.RELEASE_VERSION }}-x64.exe
|
||||
asset_name: Tautulli-windows-${{ steps.get_version.outputs.RELEASE_VERSION }}-x64.exe
|
||||
asset_content_type: application/vnd.microsoft.portable-executable
|
||||
|
||||
- name: Upload MacOS Installer
|
||||
uses: actions/upload-release-asset@v1
|
||||
if: env.WORKFLOW_CONCLUSION == 'success'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: Tautulli-macos-installer/Tautulli-macos-${{ steps.get_version.outputs.RELEASE_VERSION }}-x64.pkg
|
||||
asset_name: Tautulli-macos-${{ steps.get_version.outputs.RELEASE_VERSION }}-x64.pkg
|
||||
asset_content_type: application/vnd.apple.installer+xml
|
||||
|
||||
discord:
|
||||
name: Discord Notification
|
||||
needs: [build-installer, release]
|
||||
if: always() && github.event_name != 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Get Build Job Status
|
||||
uses: technote-space/workflow-conclusion-action@v1
|
||||
|
||||
- name: Combine Job Status
|
||||
id: status
|
||||
run: |
|
||||
failures=(neutral, skipped, timed_out, action_required)
|
||||
if [[ ${array[@]} =~ $WORKFLOW_CONCLUSION ]]; then
|
||||
echo ::set-output name=status::failure
|
||||
else
|
||||
echo ::set-output name=status::$WORKFLOW_CONCLUSION
|
||||
fi
|
||||
|
||||
- name: Post Status to Discord
|
||||
uses: sarisia/actions-status-discord@v1
|
||||
with:
|
||||
webhook: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
status: ${{ steps.status.outputs.status }}
|
||||
title: ${{ github.workflow }}
|
||||
nofail: true
|
94
.github/workflows/publish-snap.yml
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
name: Publish Snap
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master, beta, nightly]
|
||||
tags: [v*]
|
||||
pull_request: ~
|
||||
|
||||
jobs:
|
||||
build-snap:
|
||||
name: Build Snap Package (${{ matrix.architecture }})
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
architecture:
|
||||
- i386
|
||||
- amd64
|
||||
- arm64
|
||||
- armhf
|
||||
- ppc64el
|
||||
#- s390x # broken at the moment
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Prepare
|
||||
id: prepare
|
||||
run: |
|
||||
git fetch --prune --unshallow --tags
|
||||
if [[ $GITHUB_REF == refs/tags/*-beta || $GITHUB_REF == refs/heads/beta ]]; then
|
||||
echo ::set-output name=RELEASE::beta
|
||||
elif [[ $GITHUB_REF == refs/tags/* || $GITHUB_REF == refs/heads/master ]]; then
|
||||
echo ::set-output name=RELEASE::stable
|
||||
else
|
||||
echo ::set-output name=RELEASE::edge
|
||||
fi
|
||||
|
||||
- name: Set Up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
|
||||
- name: Build Snap Package
|
||||
uses: diddlesnaps/snapcraft-multiarch-action@v1
|
||||
id: build
|
||||
with:
|
||||
architecture: ${{ matrix.architecture }}
|
||||
|
||||
- name: Upload Snap Package
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Tautulli-snap-package-${{ matrix.architecture }}
|
||||
path: ${{ steps.build.outputs.snap }}
|
||||
|
||||
- name: Review Snap Package
|
||||
uses: diddlesnaps/snapcraft-review-tools-action@v1
|
||||
with:
|
||||
snap: ${{ steps.build.outputs.snap }}
|
||||
|
||||
- name: Publish Snap Package
|
||||
uses: snapcore/action-publish@v1
|
||||
if: >
|
||||
github.event_name != 'pull_request' &&
|
||||
(startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/nightly')
|
||||
with:
|
||||
store_login: ${{ secrets.SNAP_LOGIN }}
|
||||
snap: ${{ steps.build.outputs.snap }}
|
||||
release: ${{ steps.prepare.outputs.RELEASE }}
|
||||
|
||||
discord:
|
||||
name: Discord Notification
|
||||
needs: build-snap
|
||||
if: always() && github.event_name != 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Get Build Job Status
|
||||
uses: technote-space/workflow-conclusion-action@v1
|
||||
|
||||
- name: Combine Job Status
|
||||
id: status
|
||||
run: |
|
||||
failures=(neutral, skipped, timed_out, action_required)
|
||||
if [[ ${array[@]} =~ $WORKFLOW_CONCLUSION ]]; then
|
||||
echo ::set-output name=status::failure
|
||||
else
|
||||
echo ::set-output name=status::$WORKFLOW_CONCLUSION
|
||||
fi
|
||||
|
||||
- name: Post Status to Discord
|
||||
uses: sarisia/actions-status-discord@v1
|
||||
with:
|
||||
webhook: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
status: ${{ steps.status.outputs.status }}
|
||||
title: ${{ github.workflow }}
|
||||
nofail: true
|
20
.gitignore
vendored
@@ -17,8 +17,11 @@ version.lock
|
||||
logs/*
|
||||
backups/*
|
||||
cache/*
|
||||
exports/*
|
||||
newsletters/*
|
||||
*.mmdb
|
||||
version.txt
|
||||
branch.txt
|
||||
|
||||
# HTTPS Cert/Key #
|
||||
##################
|
||||
@@ -74,3 +77,20 @@ _ReSharper*/
|
||||
/logs
|
||||
.project
|
||||
.pydevproject
|
||||
|
||||
#Ignore files generated by pyinstaller
|
||||
/build
|
||||
/dist
|
||||
|
||||
#snapcraft specifics
|
||||
/parts/
|
||||
/stage/
|
||||
/prime/
|
||||
|
||||
*.snap
|
||||
|
||||
.snapcraft
|
||||
__pycache__
|
||||
*.pyc
|
||||
*_source.tar.bz2
|
||||
snap/.snapcraft
|
426
CHANGELOG.md
@@ -1,5 +1,431 @@
|
||||
# Changelog
|
||||
|
||||
## v2.6.4 (2020-12-20)
|
||||
|
||||
* Other:
|
||||
* Fix: Restore Snap data folder from previous installs.
|
||||
|
||||
|
||||
## v2.6.3 (2020-12-19)
|
||||
|
||||
* Announcements:
|
||||
* This is the last Tautulli version to support Python 2. Python 3 will be required to continue receiving updates. You can check your Python version on the settings page.
|
||||
* Exporter:
|
||||
* Fix: Accessible and exists attributes were blank for media info export level 9.
|
||||
* UI:
|
||||
* Fix: Guest usernames were not masked on mouse hover.
|
||||
* Other:
|
||||
* Fix: macOS menu bar icon for light and dark mode.
|
||||
* New: Tautulli can officially be installed on Linux using a Snap package. See the installation wiki for details.
|
||||
|
||||
|
||||
## v2.6.2 (2020-12-05)
|
||||
|
||||
* Notifications:
|
||||
* Change: Send a notification of a user new device for the first time only. This can be toggled off in the settings.
|
||||
* Exporter:
|
||||
* Fix: Allow exporting child fields only without requiring the parent fields as well.
|
||||
* Fix: Exporting individual collection would fail.
|
||||
* Change: Remove accessible and exists fields from the default media info export levels. This prevents the Plex server from reading the media files unnecessarily.
|
||||
* Other:
|
||||
* Fix: Enable high resolution for the macOS system tray icon and menu.
|
||||
* New: Added rate limiting for failed login attempts.
|
||||
* Change: Use a white logo for the macOS system tray icon.
|
||||
* API:
|
||||
* New: Added machine_id to the get_history API response.
|
||||
|
||||
|
||||
## v2.6.1 (2020-11-03)
|
||||
|
||||
* Other:
|
||||
* Fix: High CPU/memory usage in some instances.
|
||||
* Fix: Logger error preventing Tautulli from starting.
|
||||
* Fix: Database issue with non-unique image hashes.
|
||||
|
||||
|
||||
## v2.6.0 (2020-10-31)
|
||||
|
||||
* Exporter:
|
||||
* New: New exporter feature that allows you to export the metadata and images for any library, collection, playlist, or media item to csv, json, xml, or m3u8. Refer to the Exporter Guide in the wiki for more details.
|
||||
* UI:
|
||||
* Fix: Margin on the homepage activity and statistic/library cards. (Thanks @dotsam)
|
||||
* Fix: Movie ratings not showing on the info page for the new Plex Movie agent.
|
||||
* New: Added ability to browse collections and playlists from the library and user pages.
|
||||
* Change: Updated platform brand logos and colours.
|
||||
* API:
|
||||
* New: Added export_metadata, download_export, and delete_export API commands.
|
||||
* New: Added get_collections_table, and get_playlists_table API commands.
|
||||
* New: Added min_version parameter to the register_device API command.
|
||||
* New: Added include_activity parameter to the get_history API command.
|
||||
* New: Added sync_id parameter to the get_metadata API command.
|
||||
* New: Added delete_synced_item API command.
|
||||
* New: Added a stat_id and stats_start parameters to the get_home_stats API command.
|
||||
* New: Allow deleting a mobile device using the registration device_id for the delete_mobile_device API command.
|
||||
* Change: Return Plex server info and Tautulli info from the register_device command.
|
||||
* Other:
|
||||
* New: The Docker container is now also built for the arm32v6 architecture.
|
||||
* New: The Docker container is also published to the GitHub Container Registry at ghcr.io/tautulli/tautulli.
|
||||
* Change: Tautulli is now using a forked version of plexapi 3.6.0. This is to support the exporter feature while still maintaining Python 2 compatibility.
|
||||
* Change: Updated systemd script to remove process forking. (Thanks @MichaIng)
|
||||
* Change: Cache GitHub update check on startup.
|
||||
|
||||
|
||||
## v2.5.6 (2020-10-02)
|
||||
|
||||
* Activity:
|
||||
* Change: Renamed container "Transcode" to "Converting" on activity cards.
|
||||
* Notifications:
|
||||
* New: Added a silent notification option for Telegram. (Thanks @JohnnyKing94)
|
||||
* New: Added container_decision notification parameter.
|
||||
* New: Added notification trigger for Playback Error.
|
||||
* New: Added remote access down notification threshold setting.
|
||||
* Newsletter:
|
||||
* Change: Stop flooring newsletter start date.
|
||||
* UI:
|
||||
* Fix: Unable to purge history from the library edit modal.
|
||||
* Fix: QR code not showing up for localhost address when trying to register a device.
|
||||
* New: Added library name to the fix metadata modal.
|
||||
* API:
|
||||
* New: Added default thumb and art to the Live TV library.
|
||||
* Other:
|
||||
* Fix: Synced items not loading for guest access.
|
||||
* New: Schedule some more automatic database optimizations.
|
||||
* Change: Added automatic uninstall before installing to the Windows installer.
|
||||
|
||||
|
||||
## v2.5.5 (2020-09-06)
|
||||
|
||||
* Activity:
|
||||
* Fix: Filter out TV show background theme music sessions.
|
||||
* Notifications:
|
||||
* New: Check Plex external guids for notification metadata provider links.
|
||||
* UI:
|
||||
* Fix: Incorrect sorting for user/library recently played items.
|
||||
* API:
|
||||
* Fix: get_synced_items API command returning error with empty result.
|
||||
* Fix: Download API commands not returning the file.
|
||||
* Fix: get_logs API command encoding error.
|
||||
* Fix: get_user_player_stats API command returning error instead of empty result.
|
||||
* New: Added get_server_info API command.
|
||||
* New: Added external guids to get_metadata API command.
|
||||
* New: Added support for multi-column sorting for datatable API commands.
|
||||
* Change: get_activity API command return thumbnail override for clips.
|
||||
* Change: get_libraries_table API command return custom library artwork.
|
||||
* Other:
|
||||
* Fix: Tautulli failed to run with a stale pid file.
|
||||
* New: Added scheduled task to optimize the Tautulli database.
|
||||
* Change: Update plexapi to 3.6.0.
|
||||
* Change: Update some libraries for Python 3 compatibility.
|
||||
|
||||
|
||||
## v2.5.4 (2020-07-31)
|
||||
|
||||
* Monitoring:
|
||||
* Change: Montitoring remote access changed to use websockets. Refer to Tautulli/Tautulli-Issues#251 for details.
|
||||
* Notifications:
|
||||
* Fix: Uploading images to Cloudinary failed for titles with non-ASCII characters on Python 2.
|
||||
* New: Added plex_id notification parameter.
|
||||
* Remove: Running .exe files directly using script notifications is no longer supported.
|
||||
* Remove: php, perl, and ruby prefix overrides for script notifications is no longer supported.
|
||||
* Change: Stricter checking of file extensions for script notifications.
|
||||
* Change: Fallback to The Movie Database lookup using title and year.
|
||||
* Change: Fallback to TVmaze lookup using title.
|
||||
* UI:
|
||||
* New: Added ability to import a previous Tautullli configuration file in the settings.
|
||||
* New: Added a browse button for settings which require a folder or file input.
|
||||
* New: Added first streamed column to user IP addresses table. (Thanks @dotsam)
|
||||
* New: Added The Movie Database rating image to media page.
|
||||
* Change: Different icon to represent direct stream in the history tables.
|
||||
* API:
|
||||
* New: Updated API docs for importing a database and configuration file.
|
||||
|
||||
|
||||
## v2.5.3 (2020-07-10)
|
||||
|
||||
* History:
|
||||
* Fix: Unable to delete more than 1000 history entries at the same time.
|
||||
* Notifications:
|
||||
* Change: Python script notifications to run using the same Python interpreter as Tautulli.
|
||||
* Newsletters:
|
||||
* Fix: Unable to view newsletters with special characters.
|
||||
* Other:
|
||||
* Fix: Tautulli failing to start after enabling HTTPS when installed using the Windows / macOS installers.
|
||||
* Fix: Startup script not working on macOS.
|
||||
* Fix: Unable to hide dock icon on macOS with the pkg install. Refer to the FAQ regarding the Python rocket dock icon.
|
||||
* Change: Added path to Python interpreter in system startup (daemon) scripts.
|
||||
* Change: Added Python version to Google analytics.
|
||||
|
||||
|
||||
## v2.5.2 (2020-07-01)
|
||||
|
||||
* Announcements:
|
||||
* Tautulli now supports Python 3!
|
||||
* Python 2 is still supported for the time being, but it is recommended to upgrade to Python 3.
|
||||
* Notifications:
|
||||
* Fix: Error uploading images to Cloudinary on Python 2.
|
||||
* Fix: Testing browser notifications alert not disappearing.
|
||||
* Change: Default recently added notification delay set to 300 seconds.
|
||||
* UI:
|
||||
* Fix: MacOS menu bar icon causing Tautulli to fail to start.
|
||||
* Fix: Unable to login to Tautulli on Python 2.
|
||||
* New: Windows and MacOS setting to enable Tautulli to start automatically when you login.
|
||||
* New: Added menu bar icon for MacOS.
|
||||
* New: Ability to import a Tautulli database in the settings.
|
||||
* New: Added Tautulli news area on the settings page.
|
||||
* New: Added platform icon for LG devices.
|
||||
* Remove: Ability to login to Tautulli using a Plex username and password has been removed. Login using a Plex.tv account is only supported via OAuth.
|
||||
* Mobile App:
|
||||
* Fix: Improved API security and validation when registering the Android app.
|
||||
* Docker:
|
||||
* Fix: Docker container not respecting the PUID and PGID environment variables.
|
||||
* Other:
|
||||
* Fix: Error creating self-signed certificates on Python 3.
|
||||
* Fix: Tautulli login session cookie not set on the HTTP root path.
|
||||
* New: Windows and MacOS app installers to install Tautulli without needing Python installed.
|
||||
|
||||
|
||||
## v2.2.4 (2020-05-16)
|
||||
|
||||
* Monitoring:
|
||||
* Fix: Show "None" as the subtitle source on the activity card for user selected subtitles.
|
||||
* UI:
|
||||
* Fix: Deleted libraries were showing up on the homepage library cards.
|
||||
* Fix: Libraries could get stuck as inactive in the database in some instances.
|
||||
* API:
|
||||
* Fix: Incorrect title was being returned for the get_history API command.
|
||||
* Other:
|
||||
* Fix: Plex remote access check was not being rescheduled after changing the settings.
|
||||
|
||||
|
||||
## v2.2.3 (2020-05-01)
|
||||
|
||||
* Notifications:
|
||||
* Fix: Notification grouping by season/album and show/artist not enabled by default.
|
||||
* Fix: The rating key notification parameter was being overwritten when 3rd party lookup was enabled.
|
||||
* Fix: Missing artist value for Musicbrainz lookup in certain situations.
|
||||
* New: Added notification trigger for Tautulli database corruption.
|
||||
* New: Added TAUTULLI_PYTHON_VERSION to script notification environment variables.
|
||||
* New: Added Plex Android / iOS App notification agent.
|
||||
* New: Added bandwidth notification parameters.
|
||||
* New: Added user thumb to notification parameters.
|
||||
* New: Added initial stream notification parameter and threshold setting to determine if a stream is the first stream of a continuous streaming session.
|
||||
* New: Added Plex remote access notification parameters.
|
||||
* Change: The file size notification parameter is now reported in SI units. (Thanks @aaronldunlap)
|
||||
* UI:
|
||||
* Fix: Delete lookup info from the media info page failing.
|
||||
* Fix: XBMC platform icon not being redirected to the Kodi platform icon.
|
||||
* Fix: History table was not being refreshed after deleting entries.
|
||||
* New: Added icon on the users table to indicate if the user is not on the Plex server.
|
||||
* New: Added icon on the libraries table to indicate if the library is not on the Plex server.
|
||||
* Change: Improved deleting libraries so libraries with the same section ID are not also deleted.
|
||||
* Mobile App:
|
||||
* Fix: Temporary device token was not being invalidated after cancelling device registration.
|
||||
* API:
|
||||
* Fix: Returning XML from the API failing due to unicode characters.
|
||||
* Fix: Grouping parameter for various API commands not falling back to default setting.
|
||||
* New: Added time_queries parameter to get_library_watch_time_stats and get_user_watch_time_stats API command. (Thanks @KaasKop97)
|
||||
* New: Added an "is_active" return value to the get_user, get_users, get_library, and get_libraries API commands which indicates if the user or library is on the Plex server.
|
||||
* New: Added delete_history API command.
|
||||
* Change: Added optional parameter for row_ids for delete_library, delete_user, delete_all_library_history, and delete_all_user_history API commands.
|
||||
* Other:
|
||||
* Fix: Update failing on CentOS due to an older git version.
|
||||
* Fix: Manifest file for creating a web app had incorrect info.
|
||||
* Fix: Auto-updater was not scheduled when enabling the setting unless Tautulli was restarted.
|
||||
* New: Docker images updated to support ARM platforms.
|
||||
* Change: Remove the unnecessary optional Plex logs volume from the Docker image.
|
||||
* Change: Use Plex.tv for GeoIP lookup instead of requiring the MaxMind GeoLite2 database.
|
||||
|
||||
|
||||
## v2.2.1 (2020-03-28)
|
||||
|
||||
* Notifications:
|
||||
* Fix: File size notification parameter incorrectly truncated to an integer.
|
||||
* Fix: Notification grouping by season/album not enabled by default.
|
||||
* New: Added transcode decision counts to notification parameters.
|
||||
* Change: Tags (<>) are no longer stripped from from Webhook notification text.
|
||||
* Newsletter:
|
||||
* New: Added favicon to newsletter template when viewing as a web page.
|
||||
* UI:
|
||||
* Fix: Username missing from the Synced Items table.
|
||||
* Fix: Windows system tray icon not enabled by default.
|
||||
* Fix: Saving a mobile device with a blank friendly name caused an error.
|
||||
* New: Added IMDb and Rotten Tomato Ratings to info pages.
|
||||
* New: Added button in settings to delete all 3rd party metadata lookup info in the database.
|
||||
* New: Added button in settings to flush recently added items in the database.
|
||||
* API:
|
||||
* New: Added delete_recenly_added API command to flush recently added items.
|
||||
* Change: Updated delete_lookup_info API command parameters to allow deleteing all 3rd party metadata lookup info.
|
||||
|
||||
|
||||
## v2.2.0 (2020-03-08)
|
||||
|
||||
* Important Note!
|
||||
* All Live TV changes requires Plex Media Server 1.18.7 or higher.
|
||||
* Monitoring:
|
||||
* Fix: Improved IPv6 display on the activity cards. (Thanks @felixbuenemann)
|
||||
* New: Added Live TV metadata and posters to the activity cards.
|
||||
* Change: Show bandwidth in Gbps when greater than 1000 Mbps.
|
||||
* History:
|
||||
* New: Added history logging for Live TV sessions.
|
||||
* New: Added a fake "Live TV" library to collect Live TV history.
|
||||
* Note: This library will show up the first time that Live TV is played.
|
||||
* New: Added the ability to filter history by Live TV.
|
||||
* Graphs:
|
||||
* New: Added Live TV series to the "Plays by Period" and "Play Totals" graphs.
|
||||
* Change: Media type series on the graphs are only shown if the corresponding library type is present.
|
||||
* Notifications:
|
||||
* Fix: Race condition causing stream count to be incorrect for playback stop notifications.
|
||||
* New: Added Live TV channel notification parameters.
|
||||
* New: Added Plex background art notification parameter.
|
||||
* Note: This is the Plex API endpoint to retrieve the background art, not the actual image.
|
||||
* New: Added poster images for clip notifications.
|
||||
* Change: Default Webhook notification method to POST.
|
||||
* UI:
|
||||
* Fix: Windows platform showing up twice on the Most Active Platforms statistics card.
|
||||
* New: Added option to change the background art for library sections when editing a library.
|
||||
* New: Added button to reset Tautulli git installation in settings to fix failed git updates.
|
||||
* API:
|
||||
* New: Added ability to filter history using a "live" media type and by guid for the get_history API command.
|
||||
* New: Added cutsom_art parameter to the edit_library API command.
|
||||
* Other:
|
||||
* Change: Add crossorigin use-credentials attribute to manifest tags. (Thanks @pkoenig10)
|
||||
* Change: Disable automatic updates for Docker containers. Updates are now handled by updating the Docker container.
|
||||
* Note: If you are using an old Docker container created before v2.2.0, then you may need to completely remove and recreate the container to update for the first time.
|
||||
* Note: Use the ":latest" Docker tag for the newest stable release, or the ":beta" or ":nightly" tags to access the beta or nightly branches.
|
||||
|
||||
|
||||
## v2.1.44 (2020-02-05)
|
||||
|
||||
* Monitoring:
|
||||
* Fix: SDR source video being identified as HDR stream video.
|
||||
* Notifications:
|
||||
* Fix: Unable to select condition operator for video color parameters.
|
||||
* UI:
|
||||
* Fix: Capitalization for platforms on history tables.
|
||||
|
||||
|
||||
## v2.1.43 (2020-02-03)
|
||||
|
||||
* Monitoring:
|
||||
* New: Added HDR indicator on activity card.
|
||||
* New: Added dynamic range to history steam info modal.
|
||||
* Notifications:
|
||||
* Fix: Webhook notification body sent as incorrect data type when Content-Type header is overridden.
|
||||
* Fix: Telegram notification character limit incorrect for unicode characters.
|
||||
* New: Added color and dynamic range notification parameters.
|
||||
* Newsletters:
|
||||
* Fix: Episodes and Albums plural spelling on recently added newsletter section headers.
|
||||
* UI:
|
||||
* Fix: Windows and macOS platform capitalization.
|
||||
* Fix: Season number 0 not shown for episodes on history tables.
|
||||
* Other:
|
||||
* Change: Mask email addresses in logs.
|
||||
* Change: Update deprecated GitHub access token URL parameter to Authorization header.
|
||||
|
||||
|
||||
## v2.1.42 (2020-01-04)
|
||||
|
||||
* Other:
|
||||
* Fix: SSL certificate error when installing GeoLite2 database.
|
||||
* Change: Verify MaxMind license key and GeoLite2 database path before installing.
|
||||
* Change: Disable GeoLite2 database uninstall button when it is not installed.
|
||||
|
||||
|
||||
## v2.1.41 (2019-12-30)
|
||||
|
||||
* Other:
|
||||
* Fix: Failing to extract the GeoLite2 database on Windows.
|
||||
|
||||
|
||||
## v2.1.40 (2019-12-30)
|
||||
|
||||
* UI:
|
||||
* Change: Moved 3rd Party API settings to new tab in the settings.
|
||||
* Graphs:
|
||||
* Change: Improve calculating month ranges for Play Totals graphs.
|
||||
* Other:
|
||||
* Fix: Failing to verify a Plex Media Server using a hostname.
|
||||
* Change: A license key is now required to install the MaxMind GeoLite2 database for IP geolocation. Please follow the guide in the wiki to reinstall the GeoLite2 database.
|
||||
* Change: The GeoLite2 database will now automatically update periodically if installed.
|
||||
|
||||
|
||||
## v2.1.39 (2019-12-08)
|
||||
|
||||
* UI:
|
||||
* New: Added creating admin username and password to setup wizard.
|
||||
* API:
|
||||
* Change: Remove default notification subject and body for notify API command.
|
||||
* Other:
|
||||
* Change: Check for database corruption when making backup.
|
||||
|
||||
|
||||
## v2.1.38 (2019-11-17)
|
||||
|
||||
* Notifications:
|
||||
* New: Added custom JSON headers to the webhook notification agent.
|
||||
* UI:
|
||||
* Fix: Homepage recently watched card not showing grouped history.
|
||||
* Other:
|
||||
* New: Added GitHub sponsor donation option.
|
||||
* Change: Improve resolving hostnames.
|
||||
|
||||
|
||||
## v2.1.37 (2019-10-11)
|
||||
|
||||
* Notifications:
|
||||
* Fix: Last.fm URLs linking to artist page instead of the album page.
|
||||
* New: Added option for MusicBrainz lookup for music notifications. Option must be enabled under 3rd Party APIs in the settings.
|
||||
* New: Added MusicBrainz ID and MusicBrainz URL notification parameters.
|
||||
* Change: Automatically truncate Discord description summary to 2048 characters.
|
||||
|
||||
|
||||
## v2.1.36-beta (2019-10-05)
|
||||
|
||||
* Monitoring:
|
||||
* Fix: Activity card title not updating after pre-rolls or auto-play.
|
||||
* History:
|
||||
* Fix: Display correct interlaced or progressive video scan type on stream data modal.
|
||||
* Graphs:
|
||||
* New: Separate interlaced and progressive video scan type on source and stream resolution graphs.
|
||||
* API:
|
||||
* New: Added parent_guid and grandparent_guid to get_activity and get_metadata commands.
|
||||
|
||||
|
||||
## v2.1.35-beta (2019-09-24)
|
||||
|
||||
* Monitoring:
|
||||
* Fix: Audio shown as blank on activity cards when changing audio tracks during direct play.
|
||||
* Fix: Display correct interlaced or progressive video scan type on activity cards.
|
||||
* New: Added flag for Nvidia hardware decoding on activity cards.
|
||||
* Notifications:
|
||||
* Fix: Notification parameter prefix and suffix were not substituted correctly.
|
||||
* Fix: Release Date notification parameter was incorrectly casted to an integer instead of a string.
|
||||
* New: Added video scan type and full resolution notification parameters.
|
||||
* UI:
|
||||
* Fix: Movies with the same title but different year being grouped on the homepage stats cards.
|
||||
* API:
|
||||
* New: Added video scan type and full resolution values to get_activity command.
|
||||
* Other:
|
||||
* Fix: Tautulli logging out every time after saving settings and restarting.
|
||||
|
||||
|
||||
## v2.1.34 (2019-09-03)
|
||||
|
||||
* History:
|
||||
* New: Added Product column to history tables.
|
||||
* Notifications:
|
||||
* Fix: IMDB/TMDb/TVDB/TVmaze ID notification parameters showing blank values after lookup.
|
||||
* UI:
|
||||
* Fix: Libraries and Users tables did not respect the group history setting.
|
||||
* API:
|
||||
* Fix: Title field was not searchable in get_library_media_info command.
|
||||
* New: Added grouping option to get_libraries_table and get_users_table commands.
|
||||
* New: Added product value to get_history command.
|
||||
* Other:
|
||||
* Fix: Could not verify Plex Media Server with unpublished hostnames.
|
||||
* Change: Automatically logout all Tautulli instances when changing the admin password.
|
||||
|
||||
|
||||
## v2.1.33 (2019-07-27)
|
||||
|
||||
* Notifications:
|
||||
|
@@ -9,7 +9,7 @@ All pull requests should be based on the `nightly` branch, to minimize cross mer
|
||||
### Python Code
|
||||
|
||||
#### Compatibility
|
||||
The code should work with Python 2.7. Note that Tautulli runs on many different platforms.
|
||||
The code should work with Python 2.7.17 or Python 3.6+. Note that Tautulli runs on many different platforms.
|
||||
|
||||
Re-use existing code. Do not hesitate to add logging in your code. You can the logger module `plexpy.logger.*` for this. Web requests are invoked via `plexpy.request.*` and derived ones. Use these methods to automatically add proper and meaningful error handling.
|
||||
|
||||
@@ -38,4 +38,4 @@ HTML5 compatible browsers are targeted.
|
||||
* 4 space indentation
|
||||
* `methodName`
|
||||
* `variableName`
|
||||
* `ClassName`
|
||||
* `ClassName`
|
||||
|
26
Dockerfile
Normal file
@@ -0,0 +1,26 @@
|
||||
FROM tautulli/tautulli-baseimage:python3
|
||||
|
||||
LABEL maintainer="Tautulli"
|
||||
|
||||
ARG BRANCH
|
||||
ARG COMMIT
|
||||
|
||||
ENV TAUTULLI_DOCKER=True
|
||||
ENV TZ=UTC
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN \
|
||||
groupadd -g 1000 tautulli && \
|
||||
useradd -u 1000 -g 1000 tautulli && \
|
||||
echo ${BRANCH} > /app/branch.txt && \
|
||||
echo ${COMMIT} > /app/version.txt
|
||||
|
||||
COPY . /app
|
||||
|
||||
CMD [ "python", "Tautulli.py", "--datadir", "/config" ]
|
||||
ENTRYPOINT [ "./start.sh" ]
|
||||
|
||||
VOLUME /config
|
||||
EXPOSE 8181
|
||||
HEALTHCHECK --start-period=90s CMD curl -ILfSs http://localhost:8181/status > /dev/null || curl -ILfkSs https://localhost:8181/status > /dev/null || exit 1
|
@@ -1,41 +0,0 @@
|
||||
<!---
|
||||
Reporting Issues:
|
||||
* To ensure that a developer has enough information to work with please include all of the information below.
|
||||
Please provide as much detail as possible. Screenshots can be very useful to see the problem.
|
||||
* Use proper markdown syntax to structure your post (i.e. code/log in code blocks).
|
||||
See: https://help.github.com/articles/basic-writing-and-formatting-syntax/
|
||||
* Include a link to your **FULL** log file that has the error(not just a few lines!).
|
||||
Please use [Gist](http://gist.github.com) or [Pastebin](http://pastebin.com/).
|
||||
|
||||
Feature Requests:
|
||||
* Feature requests are handled on FeatHub: http://feathub.com/Tautulli/Tautulli
|
||||
* Do not post them on the GitHub issues tracker.
|
||||
-->
|
||||
|
||||
**Version:**
|
||||
|
||||
**Branch:**
|
||||
|
||||
**Commit hash:**
|
||||
|
||||
**Operating system:**
|
||||
|
||||
**Python version:**
|
||||
|
||||
**What you did?**
|
||||
|
||||
**What happened?**
|
||||
|
||||
**What you expected?**
|
||||
|
||||
**How can we reproduce your issue?**
|
||||
<!-- Provide a detailed step-by-step. -->
|
||||
|
||||
**What are your (relevant) settings?**
|
||||
|
||||
**Link to logs:**
|
||||
|
||||
|
||||
<!--
|
||||
Close your issue when it's solved! If you found the solution yourself please comment so that others benefit from it.
|
||||
-->
|
@@ -1,8 +1,4 @@
|
||||
#!/bin/sh
|
||||
''''which python >/dev/null 2>&1 && exec python "$0" "$@" # '''
|
||||
''''which python2 >/dev/null 2>&1 && exec python2 "$0" "$@" # '''
|
||||
''''which python2.7 >/dev/null 2>&1 && exec python2.7 "$0" "$@" # '''
|
||||
''''exec echo "Error: Python not found!" # '''
|
||||
#!/usr/bin/env python
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
28
README.md
@@ -1,9 +1,5 @@
|
||||
# Tautulli
|
||||
|
||||
[](https://tautulli.com/discord)
|
||||
[](https://www.reddit.com/r/Tautulli/)
|
||||
[](https://forums.plex.tv/t/tautulli-monitor-your-plex-media-server/225242)
|
||||
|
||||
A python based web application for monitoring, analytics and notifications for [Plex Media Server](https://plex.tv).
|
||||
|
||||
This project is based on code from [Headphones](https://github.com/rembo10/headphones) and [PlexWatchWeb](https://github.com/ecleese/plexWatchWeb).
|
||||
@@ -31,7 +27,24 @@ This project is based on code from [Headphones](https://github.com/rembo10/headp
|
||||
|
||||

|
||||
|
||||
## Installation and Support
|
||||
## Installation & Support
|
||||
|
||||
[](https://python.org/downloads)
|
||||
[](https://hub.docker.com/r/tautulli/tautulli)
|
||||
[](https://hub.docker.com/r/tautulli/tautulli)
|
||||
[](https://github.com/Tautulli/Tautulli/releases/latest)
|
||||
|
||||
| Status | Branch: `master` | Branch: `beta` | Branch: `nightly` |
|
||||
| --- | --- | --- | --- |
|
||||
| Release | [](https://github.com/Tautulli/Tautulli/releases/latest) <br> [](https://github.com/Tautulli/Tautulli/releases/latest) | [](https://github.com/Tautulli/Tautulli/releases) <br> [](https://github.com/Tautulli/Tautulli/commits/beta) | [](https://github.com/Tautulli/Tautulli/commits/nightly) <br> [](https://github.com/Tautulli/Tautulli/commits/nightly) |
|
||||
| Docker | [](https://hub.docker.com/r/tautulli/tautulli) <br> [](https://github.com/Tautulli/Tautulli/actions?query=workflow%3A"Publish+Docker"+branch%3Amaster) | [](https://hub.docker.com/r/tautulli/tautulli) <br> [](https://github.com/Tautulli/Tautulli/actions?query=workflow%3A"Publish+Docker"+branch%3Abeta) | [](https://hub.docker.com/r/tautulli/tautulli) <br> [](https://github.com/Tautulli/Tautulli/actions?query=workflow%3A"Publish+Docker"+branch%3Anightly) |
|
||||
| Snap | [](https://snapcraft.io/tautulli) <br> [](https://github.com/Tautulli/Tautulli/actions?query=workflow%3A"Publish+Snap"+branch%3Amaster) | [](https://snapcraft.io/tautulli) <br> [](https://github.com/Tautulli/Tautulli/actions?query=workflow%3A"Publish+Snap"+branch%3Abeta) | [](https://snapcraft.io/tautulli) <br> [](https://github.com/Tautulli/Tautulli/actions?query=workflow%3A"Publish+Snap"+branch%3Anightly) |
|
||||
| Installer | [](https://github.com/Tautulli/Tautulli/releases/latest) <br> [](https://github.com/Tautulli/Tautulli/releases/latest) <br> [](https://github.com/Tautulli/Tautulli/actions?query=workflow%3A"Publish+Installers"+branch%3Amaster) | [](https://github.com/Tautulli/Tautulli/releases) <br> [](https://github.com/Tautulli/Tautulli/releases) <br> [](https://github.com/Tautulli/Tautulli/actions?query=workflow%3A"Publish+Installers"+branch%3Abeta) | [](https://github.com/Tautulli/Tautulli/actions?query=workflow%3A"Publish+Installers"+branch%3Anightly) |
|
||||
|
||||
[](https://github.com/Tautulli/Tautulli-Wiki/wiki)
|
||||
[](https://tautulli.com/discord)
|
||||
[](https://www.reddit.com/r/Tautulli/)
|
||||
[](https://forums.plex.tv/t/tautulli-monitor-your-plex-media-server/225242)
|
||||
|
||||
* Read the [Installation Guides](https://github.com/Tautulli/Tautulli-Wiki/wiki/Installation) for instructions to install Tautulli.
|
||||
* The [Frequently Asked Questions](https://github.com/Tautulli/Tautulli-Wiki/wiki/Frequently-Asked-Questions) in the wiki can help you with common problems.
|
||||
@@ -39,10 +52,15 @@ This project is based on code from [Headphones](https://github.com/rembo10/headp
|
||||
|
||||
## Issues & Feature Requests
|
||||
|
||||
[](https://github.com/Tautulli/Tautulli-Issues)
|
||||
[](https://feathub.com/Tautulli/Tautulli)
|
||||
|
||||
* Please see the [Issues Repository](https://github.com/Tautulli/Tautulli-Issues).
|
||||
|
||||
## License
|
||||
|
||||
[](https://github.com/Tautulli/Tautulli/blob/master/LICENSE)
|
||||
|
||||
This is free software under the GPL v3 open source license. Feel free to do with it what you wish, but any modification must be open sourced. A copy of the license is included.
|
||||
|
||||
This software includes Highsoft software libraries which you may freely distribute for non-commercial use. Commerical users must licence this software, for more information visit https://shop.highsoft.com/faq/non-commercial#non-commercial-redistribution.
|
107
Tautulli.py
@@ -1,8 +1,4 @@
|
||||
#!/bin/sh
|
||||
''''which python >/dev/null 2>&1 && exec python "$0" "$@" # '''
|
||||
''''which python2 >/dev/null 2>&1 && exec python2 "$0" "$@" # '''
|
||||
''''which python2.7 >/dev/null 2>&1 && exec python2.7 "$0" "$@" # '''
|
||||
''''exec echo "Error: Python not found!" # '''
|
||||
#!/usr/bin/env python
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
@@ -27,17 +23,24 @@ import sys
|
||||
# Ensure lib added to path, before any other imports
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'lib'))
|
||||
|
||||
from future.builtins import str
|
||||
|
||||
import appdirs
|
||||
import argparse
|
||||
import datetime
|
||||
import locale
|
||||
import pytz
|
||||
import signal
|
||||
import time
|
||||
import threading
|
||||
import tzlocal
|
||||
|
||||
import plexpy
|
||||
from plexpy import config, database, logger, webstart
|
||||
|
||||
from plexpy import common, config, database, helpers, logger, webstart
|
||||
if common.PLATFORM == 'Windows':
|
||||
from plexpy import windows
|
||||
elif common.PLATFORM == 'Darwin':
|
||||
from plexpy import macos
|
||||
|
||||
# Register signals, such as CTRL + C
|
||||
signal.signal(signal.SIGINT, plexpy.sig_handler)
|
||||
@@ -51,12 +54,14 @@ def main():
|
||||
"""
|
||||
|
||||
# Fixed paths to Tautulli
|
||||
if hasattr(sys, 'frozen'):
|
||||
if hasattr(sys, 'frozen') and hasattr(sys, '_MEIPASS'):
|
||||
plexpy.FROZEN = True
|
||||
plexpy.FULL_PATH = os.path.abspath(sys.executable)
|
||||
plexpy.PROG_DIR = sys._MEIPASS
|
||||
else:
|
||||
plexpy.FULL_PATH = os.path.abspath(__file__)
|
||||
plexpy.PROG_DIR = os.path.dirname(plexpy.FULL_PATH)
|
||||
|
||||
plexpy.PROG_DIR = os.path.dirname(plexpy.FULL_PATH)
|
||||
plexpy.ARGS = sys.argv[1:]
|
||||
|
||||
# From sickbeard
|
||||
@@ -106,8 +111,8 @@ def main():
|
||||
plexpy.QUIET = True
|
||||
|
||||
# Do an intial setup of the logger.
|
||||
logger.initLogger(console=not plexpy.QUIET, log_dir=False,
|
||||
verbose=plexpy.VERBOSE)
|
||||
# Require verbose for pre-initilization to see critical errors
|
||||
logger.initLogger(console=not plexpy.QUIET, log_dir=False, verbose=True)
|
||||
|
||||
try:
|
||||
plexpy.SYS_TIMEZONE = tzlocal.get_localzone()
|
||||
@@ -117,17 +122,18 @@ def main():
|
||||
|
||||
plexpy.SYS_UTC_OFFSET = datetime.datetime.now(plexpy.SYS_TIMEZONE).strftime('%z')
|
||||
|
||||
if os.getenv('TAUTULLI_DOCKER', False) == 'True':
|
||||
if helpers.bool_true(os.getenv('TAUTULLI_DOCKER', False)):
|
||||
plexpy.DOCKER = True
|
||||
if helpers.bool_true(os.getenv('TAUTULLI_SNAP', False)):
|
||||
plexpy.SNAP = True
|
||||
|
||||
if args.dev:
|
||||
plexpy.DEV = True
|
||||
logger.debug(u"Tautulli is running in the dev environment.")
|
||||
logger.debug("Tautulli is running in the dev environment.")
|
||||
|
||||
if args.daemon:
|
||||
if sys.platform == 'win32':
|
||||
sys.stderr.write(
|
||||
"Daemonizing not supported under Windows, starting normally\n")
|
||||
logger.warn("Daemonizing not supported under Windows, starting normally")
|
||||
else:
|
||||
plexpy.DAEMON = True
|
||||
plexpy.QUIET = True
|
||||
@@ -145,11 +151,13 @@ def main():
|
||||
try:
|
||||
with open(plexpy.PIDFILE, 'r') as fp:
|
||||
pid = int(fp.read())
|
||||
os.kill(pid, 0)
|
||||
except IOError as e:
|
||||
raise SystemExit("Unable to read PID file: %s", e)
|
||||
|
||||
try:
|
||||
os.kill(pid, 0)
|
||||
except OSError:
|
||||
logger.warn("PID file '%s' already exists, but PID %d is " \
|
||||
logger.warn("PID file '%s' already exists, but PID %d is "
|
||||
"not running. Ignoring PID file." %
|
||||
(plexpy.PIDFILE, pid))
|
||||
else:
|
||||
@@ -175,6 +183,8 @@ def main():
|
||||
# Determine which data directory and config file to use
|
||||
if args.datadir:
|
||||
plexpy.DATA_DIR = args.datadir
|
||||
elif plexpy.FROZEN:
|
||||
plexpy.DATA_DIR = appdirs.user_data_dir("Tautulli", False)
|
||||
else:
|
||||
plexpy.DATA_DIR = plexpy.PROG_DIR
|
||||
|
||||
@@ -229,37 +239,51 @@ def main():
|
||||
try:
|
||||
import OpenSSL
|
||||
except ImportError:
|
||||
logger.warn("The pyOpenSSL module is missing. Install this " \
|
||||
logger.warn("The pyOpenSSL module is missing. Install this "
|
||||
"module to enable HTTPS. HTTPS will be disabled.")
|
||||
plexpy.CONFIG.ENABLE_HTTPS = False
|
||||
|
||||
# Try to start the server. Will exit here is address is already in use.
|
||||
web_config = {
|
||||
'http_port': plexpy.HTTP_PORT,
|
||||
'http_host': plexpy.CONFIG.HTTP_HOST,
|
||||
'http_root': plexpy.CONFIG.HTTP_ROOT,
|
||||
'http_environment': plexpy.CONFIG.HTTP_ENVIRONMENT,
|
||||
'http_proxy': plexpy.CONFIG.HTTP_PROXY,
|
||||
'enable_https': plexpy.CONFIG.ENABLE_HTTPS,
|
||||
'https_cert': plexpy.CONFIG.HTTPS_CERT,
|
||||
'https_cert_chain': plexpy.CONFIG.HTTPS_CERT_CHAIN,
|
||||
'https_key': plexpy.CONFIG.HTTPS_KEY,
|
||||
'http_username': plexpy.CONFIG.HTTP_USERNAME,
|
||||
'http_password': plexpy.CONFIG.HTTP_PASSWORD,
|
||||
'http_basic_auth': plexpy.CONFIG.HTTP_BASIC_AUTH
|
||||
}
|
||||
webstart.initialize(web_config)
|
||||
webstart.start()
|
||||
|
||||
if common.PLATFORM == 'Windows':
|
||||
if plexpy.CONFIG.SYS_TRAY_ICON:
|
||||
plexpy.WIN_SYS_TRAY_ICON = windows.WindowsSystemTray()
|
||||
plexpy.WIN_SYS_TRAY_ICON.start()
|
||||
windows.set_startup()
|
||||
elif common.PLATFORM == 'Darwin':
|
||||
macos.set_startup()
|
||||
|
||||
# Open webbrowser
|
||||
if plexpy.CONFIG.LAUNCH_BROWSER and not args.nolaunch and not plexpy.DEV:
|
||||
plexpy.launch_browser(plexpy.CONFIG.HTTP_HOST, plexpy.HTTP_PORT,
|
||||
plexpy.HTTP_ROOT)
|
||||
|
||||
# Windows system tray icon
|
||||
if os.name == 'nt' and plexpy.CONFIG.WIN_SYS_TRAY:
|
||||
plexpy.win_system_tray()
|
||||
if common.PLATFORM == 'Darwin' and plexpy.CONFIG.SYS_TRAY_ICON:
|
||||
if not macos.HAS_PYOBJC:
|
||||
logger.warn("The pyobjc module is missing. Install this "
|
||||
"module to enable the MacOS menu bar icon.")
|
||||
plexpy.CONFIG.SYS_TRAY_ICON = False
|
||||
|
||||
# Wait endlessy for a signal to happen
|
||||
if plexpy.CONFIG.SYS_TRAY_ICON:
|
||||
# MacOS menu bar icon must be run on the main thread and is blocking
|
||||
# Start the rest of Tautulli on a new thread
|
||||
thread = threading.Thread(target=wait)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
|
||||
plexpy.MAC_SYS_TRAY_ICON = macos.MacOSSystemTray()
|
||||
plexpy.MAC_SYS_TRAY_ICON.start()
|
||||
else:
|
||||
wait()
|
||||
else:
|
||||
wait()
|
||||
|
||||
|
||||
def wait():
|
||||
logger.info("Tautulli is ready!")
|
||||
|
||||
# Wait endlessly for a signal to happen
|
||||
while True:
|
||||
if not plexpy.SIGNAL:
|
||||
try:
|
||||
@@ -275,11 +299,16 @@ def main():
|
||||
plexpy.shutdown(restart=True)
|
||||
elif plexpy.SIGNAL == 'checkout':
|
||||
plexpy.shutdown(restart=True, checkout=True)
|
||||
else:
|
||||
elif plexpy.SIGNAL == 'reset':
|
||||
plexpy.shutdown(restart=True, reset=True)
|
||||
elif plexpy.SIGNAL == 'update':
|
||||
plexpy.shutdown(restart=True, update=True)
|
||||
else:
|
||||
logger.error('Unknown signal. Shutting down...')
|
||||
plexpy.shutdown()
|
||||
|
||||
plexpy.SIGNAL = None
|
||||
|
||||
# Call main()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Display information
|
||||
echo "This script will remove *.pyc files. These files are generated by Python, but they can cause conflicts after an upgrade. It's safe to remove them, because they will be regenerated."
|
||||
|
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Parameter check
|
||||
if [ -z "$1" ]; then
|
||||
|
@@ -5,46 +5,105 @@
|
||||
<h4 class="modal-title">Import ${app} Database</h4>
|
||||
</div>
|
||||
<div class="modal-body" id="modal-text">
|
||||
<p class="help-block">
|
||||
<%
|
||||
v = ''
|
||||
if app == 'PlexWatch':
|
||||
v = '0.3.2'
|
||||
elif app == 'Plexivity':
|
||||
v = '0.9.8'
|
||||
%>
|
||||
<strong>Please ensure your ${app} database is at version ${v} or higher.</strong>
|
||||
</p>
|
||||
<div class="form-group">
|
||||
<label for="db_location">Database Location</label>
|
||||
<div class="row">
|
||||
<div class="col-xs-8">
|
||||
<input type="text" class="form-control" id="db_location" name="db_location" value="" required>
|
||||
<form id="import_database_form" enctype="multipart/form-data" method="post" name="import_database_form">
|
||||
<input type="hidden" id="import_app" name="import_app" value="${app.lower()}" />
|
||||
% if app in ('PlexWatch', 'Plexivity'):
|
||||
<p class="help-block">
|
||||
<%
|
||||
v = ''
|
||||
if app == 'PlexWatch':
|
||||
v = '0.3.2'
|
||||
elif app == 'Plexivity':
|
||||
v = '0.9.8'
|
||||
%>
|
||||
<strong>Please ensure your ${app} database is at version ${v} or higher.</strong>
|
||||
</p>
|
||||
% endif
|
||||
<div class="form-group">
|
||||
<label for="import_database_file">Option 1: Upload a Database File</label>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="input-group">
|
||||
<label for="import_database_file" class="input-group-btn">
|
||||
<span class="btn btn-form">Upload</span>
|
||||
<input type="file" style="display: none;" id="import_database_file" name="import_database_file" required>
|
||||
</label>
|
||||
<input id="import_database_file_name" type="text" class="form-control" placeholder="tautulli.db" disabled>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">Upload the ${app} database file you wish to import.</p>
|
||||
</div>
|
||||
<p class="help-block">Enter the path and file name for the ${app} database you wish to import.</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="table_name">Table Name</label>
|
||||
<div class="row">
|
||||
<div class="col-xs-4">
|
||||
<select id="table_name" class="form-control" name="table_name">
|
||||
<option value="processed">processed</option>
|
||||
<option value="grouped">grouped</option>
|
||||
</select>
|
||||
<div class="form-group">
|
||||
<label for="import_database_path">Option 2: Browse for a Database File</label>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="input-group">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-form" type="button" id="import_database_path_browse" data-toggle="browse" data-description="Database File" data-filter=".db" data-target="#import_database_path">Browse</button>
|
||||
</span>
|
||||
<input type="text" class="form-control" id="import_database_path" name="import_database_path" value="" placeholder="tautulli.db" required disabled>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">Browse for the ${app} database file you wish to import.</p>
|
||||
</div>
|
||||
<p class="help-block">The table name from which you wish to import. Only import one of these, importing both will result in duplicated data.</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="import_ignore_interval">Ignore Interval</label>
|
||||
<div class="row">
|
||||
<div class="col-xs-2">
|
||||
<input type="text" class="form-control" id="import_ignore_interval" name="import_ignore_interval" value="120" required>
|
||||
% if app == 'Tautulli':
|
||||
<div class="form-group">
|
||||
<label for="table_name">Import Method</label>
|
||||
<div class="row">
|
||||
<div class="col-xs-4">
|
||||
<select class="form-control" id="import_method" name="import_method">
|
||||
<option value="merge">Merge</option>
|
||||
<option value="overwrite">Overwrite</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">Select how you would like to import the Tautulli history.</p>
|
||||
<ul class="help-block" style="padding-inline-start: 15px;">
|
||||
<li><strong>Merge</strong> will add all history and remove any duplicates from the imported database into the current database.</li>
|
||||
<li><strong>Overwrite</strong> will replace all history in the current database with the imported database.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p class="help-block">Enter the minimum duration (in seconds) an item must have been active for. Set to 0 to import all.</p>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="import_backup_db" id="import_backup_db" value="1" checked> Backup Current Database
|
||||
</label>
|
||||
<p class="help-block">Automatically create a backup of the current database before importing.</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Import Notes</label>
|
||||
<p class="help-block">The following data will also be imported:</p>
|
||||
<ul class="help-block" style="padding-inline-start: 15px;">
|
||||
<li>Libraries and Users</li>
|
||||
<li>Notification / Newsletter Agents</li>
|
||||
<li>Registered Mobile Devices</li>
|
||||
</ul>
|
||||
</div>
|
||||
% else:
|
||||
<div class="form-group">
|
||||
<label for="import_table_name">Table Name</label>
|
||||
<div class="row">
|
||||
<div class="col-xs-4">
|
||||
<select class="form-control" id="import_table_name" name="import_table_name">
|
||||
<option value="processed">Processed</option>
|
||||
<option value="grouped">Grouped</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">Select the table name from which you wish to import. Only import one of these, importing both will result in duplicated data.</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="import_ignore_interval">Ignore Interval</label>
|
||||
<div class="row">
|
||||
<div class="col-xs-2">
|
||||
<input type="text" class="form-control" id="import_ignore_interval" name="import_ignore_interval" value="120" required>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">Enter the minimum duration (in seconds) an item must have been active for. Set to 0 to import all.</p>
|
||||
</div>
|
||||
% endif
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div>
|
||||
@@ -55,24 +114,87 @@
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// Send database path to import script
|
||||
$("#import_database_file").change(function() {
|
||||
if ($(this)[0].files[0]) {
|
||||
$("#import_database_file_name").val($(this)[0].files[0].name);
|
||||
}
|
||||
});
|
||||
|
||||
$("#import_db").click(function() {
|
||||
var database_path = $("#db_location").val();
|
||||
var table_name = $("#table_name").val();
|
||||
var import_ignore_interval = $("#import_ignore_interval").val();
|
||||
$(this).prop('disabled', true);
|
||||
|
||||
var app = $("#import_app").val();
|
||||
var database_file = $("#import_database_file")[0].files[0];
|
||||
var database_path = $("#import_database_path").val();
|
||||
var method = $("#import_method").val();
|
||||
var backup = $("#import_backup_db").is(':checked');
|
||||
var table_name = $("#import_table_name").val();
|
||||
var ignore_interval = $("#import_ignore_interval").val();
|
||||
|
||||
var content_type;
|
||||
var process_data;
|
||||
var data;
|
||||
|
||||
if (database_file) {
|
||||
content_type = false;
|
||||
process_data = false;
|
||||
data = new FormData();
|
||||
data.append('app', app);
|
||||
data.append('database_file', database_file);
|
||||
data.append('method', method);
|
||||
data.append('backup', backup);
|
||||
data.append('table_name', table_name);
|
||||
data.append('ignore_interval', ignore_interval);
|
||||
} else {
|
||||
content_type = 'application/x-www-form-urlencoded; charset=UTF-8';
|
||||
process_data = true;
|
||||
data = {
|
||||
app: app,
|
||||
database_path: database_path,
|
||||
method: method,
|
||||
backup: backup,
|
||||
table_name: table_name,
|
||||
ignore_interval: ignore_interval
|
||||
}
|
||||
}
|
||||
|
||||
if (database_file) {
|
||||
$("#status-message").html('<i class="fa fa-fw fa-spin fa-refresh"></i> Uploading database file...');
|
||||
} else {
|
||||
$("#status-message").html('<i class="fa fa-fw fa-spin fa-refresh"></i>');
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: 'import_database',
|
||||
data: {
|
||||
app: "${app}",
|
||||
database_path: database_path,
|
||||
table_name: table_name,
|
||||
import_ignore_interval: import_ignore_interval
|
||||
},
|
||||
type: 'POST',
|
||||
data: data,
|
||||
cache: false,
|
||||
async: true,
|
||||
contentType: content_type,
|
||||
processData: process_data,
|
||||
success: function(data) {
|
||||
$("#status-message").html(data);
|
||||
$("#db_location").val('')
|
||||
var msg;
|
||||
if (data.result === 'success') {
|
||||
msg = "<i class='fa fa-check'></i> " + data.message;
|
||||
} else {
|
||||
msg = "<i class='fa fa-exclamation-triangle'></i> " + data.message;
|
||||
}
|
||||
$("#status-message").html(msg);
|
||||
$("#import_database_file").val(null);
|
||||
$("#import_database_file_name").val('');
|
||||
$("#import_database_path").val('');
|
||||
},
|
||||
error: function (xhr) {
|
||||
var msg = "<i class='fa fa-exclamation-triangle'></i> Error (" + xhr.status + "): ";
|
||||
if (xhr.status === 413) {
|
||||
msg += "file is too large to upload"
|
||||
} else {
|
||||
msg += 'try again'
|
||||
}
|
||||
$("#status-message").html(msg);
|
||||
},
|
||||
complete: function(xhr) {
|
||||
$("#import_db").prop('disabled', false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@@ -13,8 +13,10 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
<link href="${http_root}css/bootstrap3/bootstrap.css" rel="stylesheet">
|
||||
<link href="${http_root}css/bootstrap3/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="${http_root}css/pnotify.custom.min.css" rel="stylesheet" />
|
||||
<link href="${http_root}css/selectize.bootstrap3.css" rel="stylesheet" />
|
||||
<link href="${http_root}css/selectize.min.css" rel="stylesheet" />
|
||||
<link href="${http_root}css/tautulli.css${cache_param}" rel="stylesheet">
|
||||
<link href="${http_root}css/opensans.min.css" rel="stylesheet">
|
||||
<link href="${http_root}css/font-awesome.all.min.css" rel="stylesheet">
|
||||
@@ -22,44 +24,48 @@
|
||||
${next.headIncludes()}
|
||||
|
||||
<!-- Favicons -->
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="${http_root}images/favicon/favicon-32x32.png?v=2.0.5">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="${http_root}images/favicon/favicon-16x16.png?v=2.0.5">
|
||||
<link rel="shortcut icon" href="${http_root}images/favicon/favicon.ico?v=2.0.5">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="${http_root}images/favicon/favicon-32x32.png?v=2.6.0">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="${http_root}images/favicon/favicon-16x16.png?v=2.6.0">
|
||||
<link rel="shortcut icon" href="${http_root}images/favicon/favicon.ico?v=2.6.0">
|
||||
|
||||
<!-- ICONS -->
|
||||
<!-- Android -->
|
||||
<link rel="manifest" href="${http_root}images/favicon/manifest.json?v=2.0.5">
|
||||
<link rel="manifest" href="${http_root}images/favicon/manifest.json?v=2.6.0" crossorigin="use-credentials">
|
||||
<meta name="theme-color" content="#282a2d">
|
||||
<!-- Apple -->
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="${http_root}images/favicon/apple-touch-icon.png?v=2.0.5">
|
||||
<link rel="mask-icon" href="${http_root}images/favicon/safari-pinned-tab.svg?v=2.0.5" color="#282a2d">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="${http_root}images/favicon/apple-touch-icon.png?v=2.6.0">
|
||||
<link rel="mask-icon" href="${http_root}images/favicon/safari-pinned-tab.svg?v=2.6.0" color="#282a2d">
|
||||
<meta name="apple-mobile-web-app-title" content="Tautulli">
|
||||
<!-- Microsoft -->
|
||||
<meta name="application-name" content="Tautulli">
|
||||
<meta name="msapplication-config" content="${http_root}images/favicon/browserconfig.xml?v=2.0.5">
|
||||
<meta name="msapplication-config" content="${http_root}images/favicon/browserconfig.xml?v=2.6.0">
|
||||
</head>
|
||||
|
||||
<body class="content">
|
||||
<div class="container">
|
||||
<div id="ajaxMsg" class="ajaxMsg"></div>
|
||||
% if _session['user_group'] == 'admin':
|
||||
% if plexpy.CONFIG.CHECK_GITHUB and plexpy.UPDATE_AVAILABLE is None:
|
||||
% if plexpy.CONFIG.CHECK_GITHUB and plexpy.UPDATE_AVAILABLE is not False:
|
||||
<div id="updatebar" style="display: none;">
|
||||
% if plexpy.UPDATE_AVAILABLE is None:
|
||||
You are running an unknown version of Tautulli.<br />
|
||||
<a href="update">Update</a> or <a href="#" id="updateDismiss">Dismiss</a>
|
||||
</div>
|
||||
% elif plexpy.CONFIG.CHECK_GITHUB and plexpy.UPDATE_AVAILABLE == 'release':
|
||||
<div id="updatebar" style="display: none;">
|
||||
A <a href="${anon_url('https://github.com/%s/%s/releases/tag/%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO, plexpy.LATEST_RELEASE))}" target="_blank">
|
||||
% elif plexpy.UPDATE_AVAILABLE == 'release':
|
||||
A <a href="${anon_url('https://github.com/%s/%s/releases/tag/%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO, plexpy.LATEST_RELEASE))}" target="_blank" rel="noreferrer">
|
||||
new release (${plexpy.LATEST_RELEASE})</a> of Tautulli is available!<br />
|
||||
<a href="update">Update</a> or <a href="#" id="updateDismiss">Dismiss</a>
|
||||
</div>
|
||||
% elif plexpy.CONFIG.CHECK_GITHUB and plexpy.UPDATE_AVAILABLE == 'commit':
|
||||
<div id="updatebar" style="display: none;">
|
||||
A <a href="${anon_url('https://github.com/%s/%s/compare/%s...%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO, plexpy.CURRENT_VERSION, plexpy.LATEST_VERSION))}" target="_blank">
|
||||
% elif plexpy.UPDATE_AVAILABLE == 'commit':
|
||||
A <a href="${anon_url('https://github.com/%s/%s/compare/%s...%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO, plexpy.CURRENT_VERSION, plexpy.LATEST_VERSION))}" target="_blank" rel="noreferrer">
|
||||
newer version</a> of Tautulli is available!<br />
|
||||
You are ${plexpy.COMMITS_BEHIND} commit${'s' if plexpy.COMMITS_BEHIND > 1 else ''} behind.<br />
|
||||
% endif
|
||||
% if plexpy.INSTALL_TYPE == 'docker':
|
||||
Update your Docker container or <a href="#" id="updateDismiss">Dismiss</a>
|
||||
% elif plexpy.INSTALL_TYPE == 'snap':
|
||||
Update your Snap package or <a href="#" id="updateDismiss">Dismiss</a>
|
||||
% elif plexpy.INSTALL_TYPE in ('windows', 'macos'):
|
||||
<a href="${anon_url('https://github.com/%s/%s/releases/tag/%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO, plexpy.LATEST_RELEASE))}" target="_blank" rel="noreferrer">Download</a> and install the latest version or <a href="#" id="updateDismiss">Dismiss</a>
|
||||
% else:
|
||||
<a href="update">Update</a> or <a href="#" id="updateDismiss">Dismiss</a>
|
||||
% endif
|
||||
</div>
|
||||
% else:
|
||||
<div id="updatebar" style="display: none;"></div>
|
||||
@@ -134,7 +140,7 @@
|
||||
<li><a href="settings"><i class="fa fa-fw fa-cogs"></i> Settings</a></li>
|
||||
<li role="separator" class="divider"></li>
|
||||
<li><a href="logs"><i class="fa fa-fw fa-list-alt"></i> View Logs</a></li>
|
||||
<li><a href="${anon_url('https://github.com/%s/%s-Wiki/wiki/Frequently-Asked-Questions' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO))}" target="_blank"><i class="fa fa-fw fa-question-circle"></i> FAQ</a></li>
|
||||
<li><a href="${anon_url('https://github.com/%s/%s-Wiki/wiki/Frequently-Asked-Questions' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO))}" target="_blank" rel="noreferrer"><i class="fa fa-fw fa-question-circle"></i> FAQ</a></li>
|
||||
<li><a href="support"><i class="fa fa-fw fa-comment"></i> Support</a></li>
|
||||
<li role="separator" class="divider"></li>
|
||||
<li><a href="#" data-target="#donate-modal" data-toggle="modal"><i class="fa fa-fw fa-heart"></i> Donate</a></li>
|
||||
@@ -200,7 +206,7 @@ ${next.modalIncludes()}
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<span id="incorrect-login" style="padding-right: 25px; display: none;">Incorrect username or password.</span>
|
||||
<span id="sign-in-alert" style="padding-right: 25px; display: none;"></span>
|
||||
<button id="sign-in" type="submit" class="btn btn-bright login-button"><i class="fa fa-sign-in"></i> Sign In</button>
|
||||
</div>
|
||||
<input type="hidden" id="admin_login" name="admin_login" value="1" />
|
||||
@@ -228,23 +234,32 @@ ${next.modalIncludes()}
|
||||
</div>
|
||||
</div>
|
||||
<ul id="donation_type" class="nav nav-pills" role="tablist" style="display: flex; justify-content: center; margin: 10px 0;">
|
||||
<li class="active"><a href="#patreon-donation" role="tab" data-toggle="tab">Patreon</a></li>
|
||||
<li class="active"><a href="#github-donation" role="tab" data-toggle="tab">GitHub</a></li>
|
||||
<li><a href="#patreon-donation" role="tab" data-toggle="tab">Patreon</a></li>
|
||||
<li><a href="#paypal-donation" role="tab" data-toggle="tab">PayPal</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div role="tabpanel" class="tab-pane active" id="patreon-donation" style="text-align: center">
|
||||
<div role="tabpanel" class="tab-pane active" id="github-donation" style="text-align: center">
|
||||
<p>
|
||||
Click the button below to continue to GitHub.
|
||||
</p>
|
||||
<a href="${anon_url('https://github.com/sponsors/JonnyWong16')}" target="_blank" rel="noreferrer" class="btn btn-sm btn-default" style="font-weight: 600;">
|
||||
<i class="fa fa-heart fa-sm" style="color: #ea4aaa;"></i> Sponsor
|
||||
</a>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="patreon-donation" style="text-align: center">
|
||||
<p>
|
||||
Click the button below to continue to Patreon.
|
||||
</p>
|
||||
<a href="${anon_url('https://www.patreon.com/join/tautulli')}" target="_blank">
|
||||
<img src="images/become_a_patron_button.png" alt="Become a Patron" height="40">
|
||||
<a href="${anon_url('https://www.patreon.com/join/tautulli')}" target="_blank" rel="noreferrer">
|
||||
<img src="images/become_a_patron_button.png" alt="Become a Patron" width="170" height="40">
|
||||
</a>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="paypal-donation" style="text-align: center">
|
||||
<p>
|
||||
Click the button below to continue to PayPal.
|
||||
</p>
|
||||
<a href="${anon_url('https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=6XPPKTDSX9QFL&lc=US&item_name=Tautulli¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHosted')}" target="_blank">
|
||||
<a href="${anon_url('https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=6XPPKTDSX9QFL&lc=US&item_name=Tautulli¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHosted')}" target="_blank" rel="noreferrer">
|
||||
<img src="images/gold-rect-paypal-34px.png" alt="PayPal">
|
||||
</a>
|
||||
</div>
|
||||
@@ -277,16 +292,18 @@ ${next.modalIncludes()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="${http_root}js/jquery-2.1.4.min.js"></script>
|
||||
<script src="${http_root}js/jquery-3.5.1.min.js"></script>
|
||||
<script src="${http_root}js/bootstrap.min.js"></script>
|
||||
<script src="${http_root}js/bootstrap-hover-dropdown.min.js"></script>
|
||||
<script src="${http_root}js/moment-with-locales.min.js"></script>
|
||||
<script src="${http_root}js/moment-duration-format.min.js"></script>
|
||||
<script src="${http_root}js/pnotify.custom.min.js"></script>
|
||||
<script src="${http_root}js/platform.min.js"></script>
|
||||
<script src="${http_root}js/script.js${cache_param}"></script>
|
||||
<script src="${http_root}js/ipaddr.min.js"></script>
|
||||
<script src="${http_root}js/selectize.min.js"></script>
|
||||
<script src="${http_root}js/jquery.tripleclick.min.js"></script>
|
||||
% if _session['user_group'] == 'admin' and BROWSER_NOTIFIERS:
|
||||
<script src="${http_root}js/script.js${cache_param}"></script>
|
||||
<script src="${http_root}js/ajaxNotifications.js"></script>
|
||||
% endif
|
||||
<script>
|
||||
% if _session['user_group'] == 'admin':
|
||||
$('body').on('click', '#updateDismiss', function() {
|
||||
@@ -309,21 +326,27 @@ ${next.modalIncludes()}
|
||||
complete: function (xhr, status) {
|
||||
var result = $.parseJSON(xhr.responseText);
|
||||
var msg = '';
|
||||
if (result.update === null) {
|
||||
msg = 'You are running an unknown version of Tautulli.<br />' +
|
||||
'<a href="update">Update</a> or <a href="#" id="updateDismiss">Dismiss</a>';
|
||||
$('#updatebar').html(msg).fadeIn();
|
||||
} else if (result.update === true && result.release === true) {
|
||||
msg = 'A <a href="' + result.release_url + '" target="_blank">new release (' + result.latest_release + ')</a> of Tautulli is available!<br />' +
|
||||
'<a href="update">Update</a> or <a href="#" id="updateDismiss">Dismiss</a>';
|
||||
$('#updatebar').html(msg).fadeIn();
|
||||
} else if (result.update === true && result.release === false) {
|
||||
msg = 'A <a href="' + result.compare_url + '" target="_blank">newer version</a> of Tautulli is available!<br />' +
|
||||
'You are '+ result.commits_behind + ' commit' + (result.commits_behind > 1 ? 's' : '') + ' behind.<br />' +
|
||||
'<a href="update">Update</a> or <a href="#" id="updateDismiss">Dismiss</a>';
|
||||
$('#updatebar').html(msg).fadeIn();
|
||||
} else if (result.update === false) {
|
||||
if (result.update === false) {
|
||||
showMsg('<i class="fa fa-check"></i> ' + result.message, false, true, 2000);
|
||||
} else {
|
||||
if (result.update === null) {
|
||||
msg = 'You are running an unknown version of Tautulli.<br />';
|
||||
} else if (result.update === true && result.release === true) {
|
||||
msg = 'A <a href="' + result.release_url + '" target="_blank" rel="noreferrer">new release (' + result.latest_release + ')</a> of Tautulli is available!<br />';
|
||||
} else if (result.update === true && result.release === false) {
|
||||
msg = 'A <a href="' + result.compare_url + '" target="_blank" rel="noreferrer">newer version</a> of Tautulli is available!<br />' +
|
||||
'You are '+ result.commits_behind + ' commit' + (result.commits_behind > 1 ? 's' : '') + ' behind.<br />';
|
||||
}
|
||||
if (result.install_type === 'docker') {
|
||||
msg += 'Update your Docker container or <a href="#" id="updateDismiss">Dismiss</a>';
|
||||
} else if (result.install_type === 'snap') {
|
||||
msg += 'Update your Snap package or <a href="#" id="updateDismiss">Dismiss</a>';
|
||||
} else if (result.install_type === 'windows' || result.install_type === 'macos') {
|
||||
msg += '<a href="' + result.release_url + '" target="_blank" rel="noreferrer">Download</a> and install the latest version or <a href="#" id="updateDismiss">Dismiss</a>'
|
||||
} else {
|
||||
msg += '<a href="update">Update</a> or <a href="#" id="updateDismiss">Dismiss</a>';
|
||||
}
|
||||
$('#updatebar').html(msg).fadeIn();
|
||||
}
|
||||
|
||||
if (_callback) {
|
||||
@@ -407,6 +430,10 @@ ${next.modalIncludes()}
|
||||
$(document).on('hidden.bs.modal', '.modal', function () {
|
||||
$('.modal:visible').length && $(document.body).addClass('modal-open');
|
||||
});
|
||||
|
||||
% if _session['user_group'] == 'admin' and BROWSER_NOTIFIERS:
|
||||
check_notifications();
|
||||
% endif
|
||||
});
|
||||
|
||||
% if _session['user_group'] != 'admin':
|
||||
@@ -423,12 +450,16 @@ ${next.modalIncludes()}
|
||||
data: $(this).serialize(),
|
||||
dataType: 'json',
|
||||
statusCode: {
|
||||
200: function() {
|
||||
200: function(xhr, status) {
|
||||
window.location = "${http_root}";
|
||||
},
|
||||
401: function() {
|
||||
$('#incorrect-login').show();
|
||||
$('#username').focus();
|
||||
401: function(xhr, status) {
|
||||
$('#sign-in-alert').text('Incorrect username or password.').show();
|
||||
$('#username').focus();
|
||||
},
|
||||
429: function(xhr, status) {
|
||||
var retry = Math.ceil(xhr.getResponseHeader('Retry-After') / 60)
|
||||
$('#sign-in-alert').text('Too many login attempts. Try again in ' + retry + ' minute(s).').show();
|
||||
}
|
||||
},
|
||||
complete: function() {
|
||||
|
138
data/interfaces/default/config_import.html
Normal file
@@ -0,0 +1,138 @@
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
|
||||
<h4 class="modal-title">${title}</h4>
|
||||
</div>
|
||||
<div class="modal-body" id="modal-text">
|
||||
<form id="import_config_form" enctype="multipart/form-data" method="post" name="import_config_form">
|
||||
<div class="form-group">
|
||||
<label for="import_config_file">Option 1: Upload a Configuration File</label>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="input-group">
|
||||
<label for="import_config_file" class="input-group-btn">
|
||||
<span class="btn btn-form">Upload</span>
|
||||
<input type="file" style="display: none;" id="import_config_file" name="import_config_file" required>
|
||||
</label>
|
||||
<input id="import_config_file_name" type="text" class="form-control" placeholder="config.ini" disabled>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">Upload the Tautulli configuration file you wish to import.</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="import_config_path">Option 2: Browse for a Configuration File</label>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="input-group">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-form" type="button" id="import_config_path_browse" data-toggle="browse" data-description="Configuration File" data-filter=".ini" data-target="#import_config_path">Browse</button>
|
||||
</span>
|
||||
<input type="text" class="form-control" id="import_config_path" name="import_config_path" value="" placeholder="config.ini" required disabled>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">Browse for the Tautulli configuration file you wish to import.</p>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="import_backup_config" id="import_backup_config" value="1" checked> Backup Current Configuration
|
||||
</label>
|
||||
<p class="help-block">Automatically create a backup of the current configuration before importing.</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Import Notes</label>
|
||||
<p class="help-block">The following settings will <em>not</em> be imported:</p>
|
||||
<ul class="help-block" style="padding-inline-start: 15px;">
|
||||
<li>Git Path, Log / Backup / Cache Directory, Plex Logs Folder</li>
|
||||
<li>Custom Newsletter Templates Folder, Newsletter Output Directory</li>
|
||||
<li>HTTP Host / Port / Root / Username / Password</li>
|
||||
<li>Enable HTTPS, HTTPS Certificate / Certificate Chain / Key</li>
|
||||
</ul>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div>
|
||||
<span id="status-message" style="padding-right: 25px;"></span>
|
||||
<input type="button" id="import_config" class="btn btn-bright" value="Import">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$("#import_config_file").change(function() {
|
||||
if ($(this)[0].files[0]) {
|
||||
$("#import_config_file_name").val($(this)[0].files[0].name);
|
||||
}
|
||||
});
|
||||
|
||||
$("#import_config").click(function() {
|
||||
$(this).prop('disabled', true);
|
||||
|
||||
var config_file = $("#import_config_file")[0].files[0];
|
||||
var config_path = $("#import_config_path").val();
|
||||
var backup = $("#import_backup_config").is(':checked');
|
||||
|
||||
var content_type;
|
||||
var process_data;
|
||||
var data;
|
||||
|
||||
if (config_file) {
|
||||
content_type = false;
|
||||
process_data = false;
|
||||
data = new FormData();
|
||||
data.append('config_file', config_file);
|
||||
data.append('backup', backup);
|
||||
} else {
|
||||
content_type = 'application/x-www-form-urlencoded; charset=UTF-8';
|
||||
process_data = true;
|
||||
data = {
|
||||
config_path: config_path,
|
||||
backup: backup
|
||||
}
|
||||
}
|
||||
|
||||
if (config_file) {
|
||||
$("#status-message").html('<i class="fa fa-fw fa-spin fa-refresh"></i> Uploading config file...');
|
||||
} else {
|
||||
$("#status-message").html('<i class="fa fa-fw fa-spin fa-refresh"></i>');
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: 'import_config',
|
||||
type: 'POST',
|
||||
data: data,
|
||||
cache: false,
|
||||
async: true,
|
||||
contentType: content_type,
|
||||
processData: process_data,
|
||||
success: function(data) {
|
||||
var msg;
|
||||
if (data.result === 'success') {
|
||||
msg = "<i class='fa fa-check'></i> " + data.message;
|
||||
window.location.href = 'restart_import_config';
|
||||
} else {
|
||||
msg = "<i class='fa fa-exclamation-triangle'></i> " + data.message;
|
||||
}
|
||||
$("#status-message").html(msg);
|
||||
$("#import_config_file").val(null);
|
||||
$("#import_config_file_name").val('');
|
||||
$("#import_config_path").val('');
|
||||
},
|
||||
error: function (xhr) {
|
||||
var msg = "<i class='fa fa-exclamation-triangle'></i> Error (" + xhr.status + "): ";
|
||||
if (xhr.status === 413) {
|
||||
msg += "file is too large to upload"
|
||||
} else {
|
||||
msg += 'try again'
|
||||
}
|
||||
$("#status-message").html(msg);
|
||||
},
|
||||
complete: function(xhr) {
|
||||
$("#import_config").prop('disabled', false);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
@@ -22,11 +22,11 @@ DOCUMENTATION :: END
|
||||
% if plexpy.CURRENT_VERSION:
|
||||
<tr>
|
||||
<td>Git Branch:</td>
|
||||
<td><a class="no-highlight" href="${anon_url('https://github.com/%s/%s/tree/%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO, plexpy.CONFIG.GIT_BRANCH))}" target="_blank">${plexpy.CONFIG.GIT_BRANCH}</a></td>
|
||||
<td><a class="no-highlight" href="${anon_url('https://github.com/%s/%s/tree/%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO, plexpy.CONFIG.GIT_BRANCH))}" target="_blank" rel="noreferrer">${plexpy.CONFIG.GIT_BRANCH}</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Git Commit Hash:</td>
|
||||
<td><a class="no-highlight" href="${anon_url('https://github.com/%s/%s/commit/%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO, plexpy.CURRENT_VERSION))}" target="_blank">${plexpy.CURRENT_VERSION}</a></td>
|
||||
<td><a class="no-highlight" href="${anon_url('https://github.com/%s/%s/commit/%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO, plexpy.CURRENT_VERSION))}" target="_blank" rel="noreferrer">${plexpy.CURRENT_VERSION}</a></td>
|
||||
</tr>
|
||||
% endif
|
||||
<tr>
|
||||
@@ -50,16 +50,12 @@ DOCUMENTATION :: END
|
||||
<td>${plexpy.CONFIG.CACHE_DIR}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Newsletter Directory:</td>
|
||||
<td>${plexpy.CONFIG.NEWSLETTER_DIR}</td>
|
||||
<td>Export Directory:</td>
|
||||
<td>${plexpy.CONFIG.EXPORT_DIR}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>GeoLite2 Database:</td>
|
||||
% if plexpy.CONFIG.GEOIP_DB:
|
||||
<td>${plexpy.CONFIG.GEOIP_DB} | <a class="no-highlight" href="#" id="reinstall_geoip_db">Reinstall / Update</a> | <a class="no-highlight" href="#" id="uninstall_geoip_db">Uninstall</a></td>
|
||||
% else:
|
||||
<td><a class="no-highlight" href="#" id="install_geoip_db">Click here to install the GeoLite2 database.</a></td>
|
||||
% endif
|
||||
<td>Newsletter Directory:</td>
|
||||
<td>${plexpy.CONFIG.NEWSLETTER_DIR}</td>
|
||||
</tr>
|
||||
% if plexpy.ARGS:
|
||||
<tr>
|
||||
@@ -82,19 +78,19 @@ DOCUMENTATION :: END
|
||||
<tr>
|
||||
<td class="top-line">Resources:</td>
|
||||
<td class="top-line">
|
||||
<a class="no-highlight" href="${anon_url('https://tautulli.com')}" target="_blank">Tautulli Website</a> |
|
||||
<a class="no-highlight" href="${anon_url('https://github.com/%s/%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO))}" target="_blank">GitHub Source</a> |
|
||||
<a class="no-highlight guidelines-modal-link" href="${anon_url('https://github.com/%s/%s-Issues' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO))}" data-id="issue">GitHub Issues</a> |
|
||||
<a class="no-highlight" href="${anon_url('https://github.com/%s/%s-Wiki' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO))}" target="_blank">GitHub Wiki</a> |
|
||||
<a class="no-highlight guidelines-modal-link" href="${anon_url('http://feathub.com/%s/%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO))}" data-id="feature request">FeatHub Feature Requests</a>
|
||||
<a class="no-highlight" href="${anon_url('https://tautulli.com')}" target="_blank" rel="noreferrer">Tautulli Website</a> |
|
||||
<a class="no-highlight" href="${anon_url('https://github.com/%s/%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO))}" target="_blank" rel="noreferrer">GitHub Source</a> |
|
||||
<a class="no-highlight guidelines-modal-link" href="${anon_url('https://github.com/%s/%s-Issues' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO))}" rel="noreferrer" data-id="issue">GitHub Issues</a> |
|
||||
<a class="no-highlight" href="${anon_url('https://github.com/%s/%s-Wiki' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO))}" target="_blank" rel="noreferrer">GitHub Wiki</a> |
|
||||
<a class="no-highlight guidelines-modal-link" href="${anon_url('http://feathub.com/%s/%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO))}" rel="noreferrer" data-id="feature request">FeatHub Feature Requests</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Support:</td>
|
||||
<td>
|
||||
<a class="no-highlight support-modal-link" href="${anon_url('https://tautulli.com/discord')}" target="_blank">Tautulli Discord Server</a> |
|
||||
<a class="no-highlight support-modal-link" href="${anon_url('https://www.reddit.com/r/Tautulli')}" target="_blank">Tautulli Subreddit</a> |
|
||||
<a class="no-highlight support-modal-link" href="${anon_url('https://forums.plex.tv/t/tautulli-monitor-your-plex-media-server/225242')}" target="_blank">Plex Forums</a>
|
||||
<a class="no-highlight support-modal-link" href="${anon_url('https://tautulli.com/discord')}" target="_blank" rel="noreferrer">Tautulli Discord Server</a> |
|
||||
<a class="no-highlight support-modal-link" href="${anon_url('https://www.reddit.com/r/Tautulli')}" target="_blank" rel="noreferrer">Tautulli Subreddit</a> |
|
||||
<a class="no-highlight support-modal-link" href="${anon_url('https://forums.plex.tv/t/tautulli-monitor-your-plex-media-server/225242')}" target="_blank" rel="noreferrer">Plex Forums</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -102,22 +98,6 @@ DOCUMENTATION :: END
|
||||
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$("#install_geoip_db, #reinstall_geoip_db").click(function () {
|
||||
var msg = 'Are you sure you want to install the GeoLite2 database?<br /><br />' +
|
||||
'The database is used to lookup IP address geolocation info.<br />' +
|
||||
'The database will be downloaded from <a href="${anon_url("https://dev.maxmind.com/geoip/geoip2/geolite2/")}" target="_blank">MaxMind</a>, <br />' +
|
||||
'and requires <strong>100MB</strong> of free space to install in your Tautulli directory.<br />'
|
||||
var url = 'install_geoip_db';
|
||||
confirmAjaxCall(url, msg, null, 'Installing GeoLite2 database.', getConfigurationTable);
|
||||
});
|
||||
|
||||
$("#uninstall_geoip_db").click(function () {
|
||||
var msg = 'Are you sure you want to uninstall the GeoLite2 database?<br /><br />' +
|
||||
'You will not be able to lookup IP address geolocation info.';
|
||||
var url = 'uninstall_geoip_db';
|
||||
confirmAjaxCall(url, msg, null, 'Uninstalling GeoLite2 database.', getConfigurationTable);
|
||||
});
|
||||
|
||||
$('.guidelines-modal-link').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
$('#guidelines-type').text($(this).data('id'))
|
||||
|
@@ -21,7 +21,7 @@ ul.ColVis_collection li {
|
||||
|
||||
.ColVis_Button:hover,
|
||||
ul.ColVis_collection li:hover {
|
||||
color: #F9AA03;
|
||||
color: #E5A00D;
|
||||
}
|
||||
|
||||
button.ColVis_Button {
|
||||
@@ -71,7 +71,7 @@ ul.ColVis_collection {
|
||||
list-style: none;
|
||||
width: 150px;
|
||||
padding: 8px 8px 4px 8px;
|
||||
margin: 10px 0px 0px 0px;
|
||||
margin: 10px 0px 10px 0px;
|
||||
background-color: #444;
|
||||
overflow: hidden;
|
||||
z-index: 2002;
|
||||
|
@@ -101,7 +101,7 @@ table.display tr:hover a {
|
||||
text-decoration:none;
|
||||
}
|
||||
table.display td:hover a {
|
||||
color: #F9AA03;
|
||||
color: #E5A00D;
|
||||
}
|
||||
table.display thead tr:hover {
|
||||
background-color: #212121;
|
||||
|
@@ -62,8 +62,7 @@ DOCUMENTATION :: END
|
||||
% if session is not None:
|
||||
<%
|
||||
from collections import defaultdict
|
||||
from urllib import quote
|
||||
from plexpy import helpers
|
||||
from plexpy.helpers import cast_to_int, page
|
||||
from plexpy.common import VIDEO_RESOLUTION_OVERRIDES, AUDIO_CODEC_OVERRIDES, EXTRA_TYPES
|
||||
import plexpy
|
||||
%>
|
||||
@@ -71,62 +70,65 @@ DOCUMENTATION :: END
|
||||
data = defaultdict(lambda: 'Unknown', **session)
|
||||
sk = data['session_key']
|
||||
|
||||
href = 'info?rating_key={}'.format(data['rating_key']) if data['rating_key'] else '#'
|
||||
parent_href = 'info?rating_key={}'.format(data['parent_rating_key']) if data['parent_rating_key'] else '#'
|
||||
grandparent_href = 'info?rating_key={}'.format(data['grandparent_rating_key']) if data['grandparent_rating_key'] else '#'
|
||||
user_href = 'user?user_id={}'.format(data['user_id']) if data['user_id'] else '#'
|
||||
href = page('info', data['rating_key'])
|
||||
parent_href = page('info', data['parent_rating_key'])
|
||||
grandparent_href = page('info', data['grandparent_rating_key'])
|
||||
user_href = page('user', data['user_id']) if data['user_id'] else '#'
|
||||
%>
|
||||
<div class="dashboard-activity-instance" id="activity-instance-${sk}" data-key="${sk}" data-id="${data['session_id']}"
|
||||
data-rating_key="${data['rating_key']}" data-parent_rating_key="${data['parent_rating_key']}" data-grandparent_rating_key="${data['grandparent_rating_key']}">
|
||||
data-rating_key="${data['rating_key']}" data-parent_rating_key="${data['parent_rating_key']}" data-grandparent_rating_key="${data['grandparent_rating_key']}"
|
||||
data-guid="${data['guid']}">
|
||||
<div class="dashboard-activity-container">
|
||||
<%
|
||||
if data['live'] == 1:
|
||||
background_url = 'images/art-live.png'
|
||||
if data['live']:
|
||||
background_url = page('pms_image_proxy', data['art'], data['rating_key'], 500, 280, 40, '282828', 3, fallback='art-live', refresh=True)
|
||||
elif data['channel_stream'] == 0:
|
||||
background_url = 'pms_image_proxy?img=' + data['art'] + '&width=500&height=280&opacity=40&background=282828&blur=3&fallback=art&refresh=true'
|
||||
background_url = page('pms_image_proxy', data['art'], data['rating_key'], 500, 280, 40, '282828', 3, fallback='art', refresh=True)
|
||||
else:
|
||||
if (data['art'] and data['art'].startswith('http')) or (data['thumb'] and data['thumb'].startswith('http')):
|
||||
background_url = data['art']
|
||||
else:
|
||||
background_url = 'pms_image_proxy?img=' + quote(data['art'] or data['thumb']) + '&width=500&height=280&fallback=art&refresh=true&clip=true'
|
||||
background_url = page('pms_image_proxy', data['art'] or data['thumb'], data['rating_key'], 500, 280, 40, '282828', 3, fallback='art', refresh=True, clip=True)
|
||||
%>
|
||||
<div id="background-${sk}" class="dashboard-activity-background" style="background-image: url(${background_url});">
|
||||
<div class="dashboard-activity-poster-container hidden-xs">
|
||||
% if data['media_type'] == 'track':
|
||||
<div id="poster-${sk}-bg" class="dashboard-activity-poster" style="background-image: url(pms_image_proxy?img=${data['parent_thumb']}&width=300&height=300&opacity=60&background=282828&blur=3&fallback=cover&refresh=true);"></div>
|
||||
<div id="poster-${sk}-bg" class="dashboard-activity-poster" style="background-image: url(${page('pms_image_proxy', data['parent_thumb'], data['parent_rating_key'], 300, 300, 60, '282828', 3, fallback='cover', refresh=True)});"></div>
|
||||
% endif
|
||||
% if data['live'] == 1:
|
||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(images/poster-live.png);"></div>
|
||||
% if data['live']:
|
||||
% if data['media_type'] == 'movie':
|
||||
<a id="poster-url-${sk}" href="${href}" title="${data['title']}">
|
||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(${page('pms_image_proxy', data['thumb'], data['rating_key'], 300, 450, fallback='poster-live', refresh=True)});"></div>
|
||||
</a>
|
||||
% elif data['media_type'] == 'episode':
|
||||
<a id="poster-url-${sk}" href="${href}" title="${data['grandparent_title']}">
|
||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(${page('pms_image_proxy', data['grandparent_thumb'], data['rating_key'], 300, 450, fallback='poster-live', refresh=True)});"></div>
|
||||
</a>
|
||||
% else:
|
||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(${page('pms_image_proxy', data['grandparent_thumb'] or data['thumb'], data['rating_key'], 300, 450, fallback='poster-live', refresh=True)});"></div>
|
||||
% endif
|
||||
% elif data['channel_stream'] == 0:
|
||||
% if data['media_type'] == 'movie':
|
||||
<a id="poster-url-${sk}" href="${href}" title="${data['title']}">
|
||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=300&height=450&fallback=poster&refresh=true);"></div>
|
||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(${page('pms_image_proxy', data['thumb'], data['rating_key'], 300, 450, fallback='poster', refresh=True)});"></div>
|
||||
</a>
|
||||
% elif data['media_type'] == 'episode':
|
||||
<a id="poster-url-${sk}" href="${grandparent_href}" title="${data['grandparent_title']}">
|
||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(pms_image_proxy?img=${data['grandparent_thumb']}&width=300&height=450&fallback=poster&refresh=true);"></div>
|
||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(${page('pms_image_proxy', data['grandparent_thumb'], data['grandparent_rating_key'], 300, 450, fallback='poster', refresh=True)});"></div>
|
||||
</a>
|
||||
% elif data['media_type'] == 'track':
|
||||
<a id="poster-url-${sk}" href="${parent_href}" title="${data['parent_title']}">
|
||||
<div id="poster-${sk}" class="dashboard-activity-cover" style="background-image: url(pms_image_proxy?img=${data['parent_thumb']}&width=300&height=300&fallback=cover&refresh=true);"></div>
|
||||
<div id="poster-${sk}" class="dashboard-activity-cover" style="background-image: url(${page('pms_image_proxy', data['parent_thumb'], data['parent_rating_key'], 300, 300, fallback='cover', refresh=True)});"></div>
|
||||
</a>
|
||||
% elif data['media_type'] in ('photo', 'clip'):
|
||||
% if data['extra_type']:
|
||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(pms_image_proxy?img=${data['art'].replace('/art', '/thumb') or data['thumb']}&width=300&height=450&fallback=poster&refresh=true);"></div>
|
||||
% if data['parent_thumb']:
|
||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(${page('pms_image_proxy', data['parent_thumb'], data['parent_rating_key'], 300, 450, fallback='poster', refresh=True)});"></div>
|
||||
% else:
|
||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(pms_image_proxy?img=${data['parent_thumb'] or data['thumb']}&width=300&height=450&fallback=poster&refresh=true);"></div>
|
||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(${page('pms_image_proxy', data['thumb'], data['rating_key'], 300, 450, fallback='poster', refresh=True)});"></div>
|
||||
% endif
|
||||
% else:
|
||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(images/poster.png);"></div>
|
||||
% endif
|
||||
% else:
|
||||
% if data['channel_icon'].startswith('http'):
|
||||
<div id="poster-${sk}" class="dashboard-activity-poster-blur" style="background-image: url(${data['channel_icon']});"></div>
|
||||
<div id="poster-${sk}" class="dashboard-activity-cover" style="background-image: url(${data['channel_icon']});"></div>
|
||||
% else:
|
||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(pms_image_proxy?img=${data['channel_icon']}&width=300&height=300&opacity=60&background=282828&blur=3&fallback=cover&refresh=true);"></div>
|
||||
<div id="poster-${sk}" class="dashboard-activity-cover" style="background-image: url(pms_image_proxy?img=${data['channel_icon']}&width=300&height=300&fallback=cover&refresh=true);"></div>
|
||||
% endif
|
||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(${page('pms_image_proxy', data['channel_icon'], data['rating_key'], 300, 300, 60, '282828', 3, fallback='cover', refresh=True)});"></div>
|
||||
<div id="poster-${sk}" class="dashboard-activity-cover" style="background-image: url(${page('pms_image_proxy', data['channel_icon'], data['rating_key'], 300, 300, fallback='cover', refresh=True)});"></div>
|
||||
% endif
|
||||
</div>
|
||||
<div class="dashboard-activity-info-icon">
|
||||
@@ -139,7 +141,7 @@ DOCUMENTATION :: END
|
||||
<div id="platform-${sk}" class="dashboard-activity-info-platform${no_terminate} svg-icon platform-${data['platform_name']}" title="${data['platform']}"></div>
|
||||
% if _session['user_group'] == 'admin' and plexpy.CONFIG.PMS_PLEXPASS and data['session_id']:
|
||||
<div class="dashboard-activity-terminate-session" id="terminate-button-${sk}" data-key="${sk}" data-id="${data['session_id']}" data-toggle="tooltip" title="Terminate Stream">
|
||||
<i class="fa fa-times" style="padding-top: 8px;"></i>
|
||||
<i class="fa fa-times" style="padding-top: 10px;"></i>
|
||||
</div>
|
||||
% endif
|
||||
</div>
|
||||
@@ -160,7 +162,7 @@ DOCUMENTATION :: END
|
||||
<div class="sub-value platform-right" id="stream_quality-${sk}">
|
||||
% if data['media_type'] != 'photo' and data['quality_profile'] != 'Unknown':
|
||||
<%
|
||||
br = helpers.cast_to_int(data['stream_bitrate']) or ''
|
||||
br = cast_to_int(data['stream_bitrate']) or ''
|
||||
if br:
|
||||
if br > 1000:
|
||||
br = '(' + str(round(br / 1000.0, 1)) + ' Mbps)'
|
||||
@@ -216,7 +218,7 @@ DOCUMENTATION :: END
|
||||
<div class="sub-heading">Container</div>
|
||||
<div class="sub-value" id="transcode_container-${sk}">
|
||||
% if data['stream_container_decision'] == 'transcode':
|
||||
Transcode (${data['container'].upper()} <i class="fa fa-long-arrow-right"></i> ${data['stream_container'].upper()})
|
||||
Converting (${data['container'].upper()} <i class="fa fa-long-arrow-right"></i> ${data['stream_container'].upper()})
|
||||
% else:
|
||||
Direct Play (${data['stream_container'].upper()})
|
||||
% endif
|
||||
@@ -226,17 +228,24 @@ DOCUMENTATION :: END
|
||||
<li class="dashboard-activity-info-item">
|
||||
<div class="sub-heading">Video</div>
|
||||
<div class="sub-value" id="video_decision-${sk}">
|
||||
% if data['media_type'] in ('movie', 'episode', 'clip'):
|
||||
% if data['media_type'] in ('movie', 'episode', 'clip') and data['stream_video_decision']:
|
||||
<%
|
||||
if data['video_dynamic_range'] == 'HDR':
|
||||
video_dynamic_range = ' ' + data['video_dynamic_range']
|
||||
stream_video_dynamic_range = ' ' + data['stream_video_dynamic_range']
|
||||
else:
|
||||
video_dynamic_range = stream_video_dynamic_range = ''
|
||||
%>
|
||||
% if data['stream_video_decision'] == 'transcode':
|
||||
<%
|
||||
hw_d = ' (HW)' if data['transcode_hw_decoding'] else ''
|
||||
hw_e = ' (HW)' if data['transcode_hw_encoding'] else ''
|
||||
%>
|
||||
Transcode (${data['video_codec'].upper()}${hw_d} ${VIDEO_RESOLUTION_OVERRIDES.get(data['video_resolution'], data['video_resolution'])} <i class="fa fa-long-arrow-right"></i> ${data['stream_video_codec'].upper()}${hw_e} ${VIDEO_RESOLUTION_OVERRIDES.get(data['stream_video_resolution'], data['stream_video_resolution'])})
|
||||
Transcode (${data['video_codec'].upper()}${hw_d} ${data['video_full_resolution']}${video_dynamic_range} <i class="fa fa-long-arrow-right"></i> ${data['stream_video_codec'].upper()}${hw_e} ${data['stream_video_full_resolution']}${stream_video_dynamic_range})
|
||||
% elif data['stream_video_decision'] == 'copy':
|
||||
Direct Stream (${data['stream_video_codec'].upper()} ${VIDEO_RESOLUTION_OVERRIDES.get(data['stream_video_resolution'], data['stream_video_resolution'])})
|
||||
Direct Stream (${data['stream_video_codec'].upper()} ${data['stream_video_full_resolution']}${stream_video_dynamic_range})
|
||||
% else:
|
||||
Direct Play (${data['stream_video_codec'].upper()} ${VIDEO_RESOLUTION_OVERRIDES.get(data['stream_video_resolution'], data['stream_video_resolution'])})
|
||||
Direct Play (${data['stream_video_codec'].upper()} ${data['stream_video_full_resolution']}${stream_video_dynamic_range})
|
||||
% endif
|
||||
% elif data['media_type'] == 'photo':
|
||||
Direct Play (${data['width']}x${data['height']})
|
||||
@@ -248,12 +257,14 @@ DOCUMENTATION :: END
|
||||
<li class="dashboard-activity-info-item">
|
||||
<div class="sub-heading">Audio</div>
|
||||
<div class="sub-value" id="audio_decision-${sk}">
|
||||
% if data['stream_audio_decision'] == 'transcode':
|
||||
Transcode (${AUDIO_CODEC_OVERRIDES.get(data['audio_codec'], data['audio_codec'].upper())} ${data['audio_channel_layout'].split('(')[0].capitalize()} <i class="fa fa-long-arrow-right"></i> ${AUDIO_CODEC_OVERRIDES.get(data['stream_audio_codec'], data['stream_audio_codec'].upper())} ${data['stream_audio_channel_layout'].split('(')[0].capitalize()})
|
||||
% elif data['stream_audio_decision'] == 'copy':
|
||||
Direct Stream (${AUDIO_CODEC_OVERRIDES.get(data['stream_audio_codec'], data['stream_audio_codec'].upper())} ${data['stream_audio_channel_layout'].split('(')[0].capitalize()})
|
||||
% else:
|
||||
Direct Play (${AUDIO_CODEC_OVERRIDES.get(data['stream_audio_codec'], data['stream_audio_codec'].upper())} ${data['stream_audio_channel_layout'].split('(')[0].capitalize()})
|
||||
% if data['stream_audio_decision']:
|
||||
% if data['stream_audio_decision'] == 'transcode':
|
||||
Transcode (${AUDIO_CODEC_OVERRIDES.get(data['audio_codec'], data['audio_codec'].upper())} ${data['audio_channel_layout'].split('(')[0].capitalize()} <i class="fa fa-long-arrow-right"></i> ${AUDIO_CODEC_OVERRIDES.get(data['stream_audio_codec'], data['stream_audio_codec'].upper())} ${data['stream_audio_channel_layout'].split('(')[0].capitalize()})
|
||||
% elif data['stream_audio_decision'] == 'copy':
|
||||
Direct Stream (${AUDIO_CODEC_OVERRIDES.get(data['stream_audio_codec'], data['stream_audio_codec'].upper())} ${data['stream_audio_channel_layout'].split('(')[0].capitalize()})
|
||||
% else:
|
||||
Direct Play (${AUDIO_CODEC_OVERRIDES.get(data['stream_audio_codec'], data['stream_audio_codec'].upper())} ${data['stream_audio_channel_layout'].split('(')[0].capitalize()})
|
||||
% endif
|
||||
% endif
|
||||
</div>
|
||||
</li>
|
||||
@@ -263,14 +274,17 @@ DOCUMENTATION :: END
|
||||
<div class="sub-heading">Subtitle</div>
|
||||
<div class="sub-value" id="subtitle_decision-${sk}">
|
||||
% if data['subtitles'] == 1:
|
||||
<%
|
||||
subtitle_codec = 'None' if data['stream_subtitle_codec'] and data['stream_subtitle_transient'] else data['subtitle_codec'].upper()
|
||||
%>
|
||||
% if data['stream_subtitle_decision'] == 'transcode':
|
||||
Transcode (${data['subtitle_codec'].upper()} <i class="fa fa-long-arrow-right"></i> ${data['stream_subtitle_codec'].upper()})
|
||||
Transcode (${subtitle_codec} <i class="fa fa-long-arrow-right"></i> ${data['stream_subtitle_codec'].upper()})
|
||||
% elif data['stream_subtitle_decision'] == 'copy':
|
||||
Direct Stream (${data['subtitle_codec'].upper()})
|
||||
Direct Stream (${subtitle_codec})
|
||||
% elif data['stream_subtitle_decision'] == 'burn':
|
||||
Burn (${data['subtitle_codec'].upper()})
|
||||
Burn (${subtitle_codec})
|
||||
% else:
|
||||
Direct Play (${data['subtitle_codec'].upper() if data['synced_version'] else data['stream_subtitle_codec'].upper()})
|
||||
Direct Play (${subtitle_codec if data['synced_version'] else data['stream_subtitle_codec'].upper()})
|
||||
% endif
|
||||
% else:
|
||||
None
|
||||
@@ -292,7 +306,11 @@ DOCUMENTATION :: END
|
||||
% endif
|
||||
<span id="location-${sk}">${data['location'].upper()}</span>:
|
||||
% if data['ip_address'] != 'N/A':
|
||||
<span class="ip-container"><span class="ip-address">${data['ip_address']}</span></span>
|
||||
% if len(data['ip_address']) > 20:
|
||||
<span class="ip-container"><span class="ip-address" data-toggle="tooltip" title="${data['ip_address']}">${data['ip_address']}</span></span>
|
||||
% else:
|
||||
<span class="ip-container"><span class="ip-address">${data['ip_address']}</span></span>
|
||||
% endif
|
||||
% if data['relayed']:
|
||||
<span data-toggle="tooltip" title="Plex Relay"><i class="fa fa-exclamation-circle"></i></span>
|
||||
% else:
|
||||
@@ -317,8 +335,10 @@ DOCUMENTATION :: END
|
||||
<div class="sub-value time-right">
|
||||
% if data['media_type'] != 'photo' and data['bandwidth'] != 'Unknown':
|
||||
<%
|
||||
bw = helpers.cast_to_int(data['bandwidth'])
|
||||
if bw > 1000:
|
||||
bw = cast_to_int(data['bandwidth'])
|
||||
if bw > 1000000:
|
||||
bw = str(round(bw / 1000000.0, 1)) + ' Gbps'
|
||||
elif bw > 1000:
|
||||
bw = str(round(bw / 1000.0, 1)) + ' Mbps'
|
||||
else:
|
||||
bw = str(bw) + ' kbps'
|
||||
@@ -337,8 +357,8 @@ DOCUMENTATION :: END
|
||||
</div>
|
||||
% if data['media_type'] != 'photo':
|
||||
<div class="dashboard-activity-info-time">
|
||||
% if data['live'] == 1:
|
||||
<br />Live
|
||||
% if data['live']:
|
||||
<br /><span class="thumb-tooltip" data-toggle="popover" data-img="${data['channel_thumb']}" data-height="40" data-width="40">${data['channel_call_sign']} ${data['channel_identifier']}</span>
|
||||
% elif data['view_offset']:
|
||||
ETA:
|
||||
<span id="stream-eta-${sk}">
|
||||
@@ -367,8 +387,8 @@ DOCUMENTATION :: END
|
||||
</div>
|
||||
<div class="dashboard-activity-progress">
|
||||
<div class="dashboard-activity-progress-bar">
|
||||
% if data['live'] == 1:
|
||||
<div id="progress-bar-${sk}" class="progress-bar" style="width: 100%" data-toggle="tooltip" title="Stream Progress Live">Live</div>
|
||||
% if data['live']:
|
||||
<div id="progress-bar-${sk}" class="progress-bar" style="width: 100%" data-state="live" data-toggle="tooltip" title="Stream Progress Live">Live</div>
|
||||
% else:
|
||||
<div id="buffer-bar-${sk}" class="buffer-bar" style="width: ${data['transcode_progress']}%" data-toggle="tooltip" title="Transcoder Progress ${data['transcode_progress']}%">${data['transcode_progress']}%</div>
|
||||
<div id="progress-bar-${sk}" class="progress-bar" style="width: ${data['progress_percent']}%" data-last_view_offset="${data['view_offset']}" data-view_offset="${data['view_offset']}" data-stream_duration="${data['stream_duration']}" data-state="${data['state']}" data-toggle="tooltip" title="Stream Progress ${data['progress_percent']}%">${data['progress_percent']}%</div>
|
||||
@@ -377,7 +397,7 @@ DOCUMENTATION :: END
|
||||
</div>
|
||||
</div>
|
||||
<div class="dashboard-activity-metadata-wrapper">
|
||||
<a href="${user_href}" title="${data['friendly_name']}">
|
||||
<a href="${user_href}" title="${data['username']}">
|
||||
<div class="dashboard-activity-metadata-user-thumb" style="background-image: url(${data['user_thumb']});"></div>
|
||||
</a>
|
||||
<div class="dashboard-activity-metadata-title-container">
|
||||
@@ -388,10 +408,23 @@ DOCUMENTATION :: END
|
||||
<i class="fa fa-fw fa-pause"></i>
|
||||
% elif data['state'] == 'buffering':
|
||||
<i class="fa fa-fw fa-spinner"></i>
|
||||
% elif data['state'] == 'error':
|
||||
<i class="fa fa-fw fa-exclamation-triangle"></i>
|
||||
% else:
|
||||
<i class="fa fa-fw fa-question-circle"></i>
|
||||
% endif
|
||||
</div>
|
||||
<div class="dashboard-activity-metadata-title">
|
||||
% if data['channel_stream'] == 0:
|
||||
% if data['live']:
|
||||
% if data['media_type'] == 'movie':
|
||||
<a href="${href}" title="${data['title']}">${data['title']}</a>
|
||||
% elif data['media_type'] == 'episode':
|
||||
<a href="${href}" title="${data['grandparent_title']}">${data['grandparent_title']}</a>
|
||||
- <a href="${href}" title="${data['title']}">${data['title']}</a>
|
||||
% else:
|
||||
<span title="${data['title']}">${data['title']}</span>
|
||||
% endif
|
||||
% elif data['channel_stream'] == 0:
|
||||
% if data['media_type'] == 'movie':
|
||||
<a href="${href}" title="${data['title']}">${data['title']}</a>
|
||||
% elif data['media_type'] == 'episode':
|
||||
@@ -416,9 +449,9 @@ DOCUMENTATION :: END
|
||||
</div>
|
||||
</div>
|
||||
<div class="dashboard-activity-metadata-subtitle-container">
|
||||
% if data['live'] == 1:
|
||||
<div id="media-type-${sk}" class="dashboard-activity-metadata-media_type-icon" title="Plex Live TV">
|
||||
<i class="fa fa-fw fa-television"></i>
|
||||
% if data['live']:
|
||||
<div id="media-type-${sk}" class="dashboard-activity-metadata-media_type-icon" title="Live TV">
|
||||
<i class="fa fa-fw fa-broadcast-tower"></i>
|
||||
</div>
|
||||
% elif data['channel_stream'] == 0:
|
||||
<div id="media-type-${sk}" class="dashboard-activity-metadata-media_type-icon" title="${data['media_type'].capitalize()}">
|
||||
@@ -440,8 +473,19 @@ DOCUMENTATION :: END
|
||||
</div>
|
||||
% endif
|
||||
<div class="dashboard-activity-metadata-subtitle">
|
||||
% if data['live'] == 1:
|
||||
<span title="Plex Live TV" class="sub-heading">Plex Live TV</span>
|
||||
% if data['live']:
|
||||
% if data['media_type'] == 'movie':
|
||||
<span title="${data['year']}" class="sub-heading">${data['year']}</span>
|
||||
% elif data['media_type'] == 'episode':
|
||||
% if data['media_index']:
|
||||
<a href="${href}" title="Season ${data['parent_media_index']}" class="sub-heading">S${data['parent_media_index']}</a>
|
||||
· <a href="${href}" title="Episode ${data['media_index']}" class="sub-heading">E${data['media_index']}</a>
|
||||
% else:
|
||||
<a href="${href}" title="${data['originally_available_at']}" class="sub-heading">${data['originally_available_at']}</a>
|
||||
% endif
|
||||
% else:
|
||||
<span title="Live TV" class="sub-heading">Live TV</span>
|
||||
% endif
|
||||
% elif data['channel_stream'] == 0:
|
||||
% if data['media_type'] == 'movie':
|
||||
<span title="${data['year']}" class="sub-heading">${data['year']}</span>
|
||||
@@ -479,7 +523,7 @@ DOCUMENTATION :: END
|
||||
% endif
|
||||
</div>
|
||||
<div class="dashboard-activity-metadata-user">
|
||||
<a href="${user_href}" title="${data['friendly_name']}">${data['friendly_name']}</a>
|
||||
<a href="${user_href}" title="${data['username']}">${data['friendly_name']}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -40,13 +40,22 @@ DOCUMENTATION :: END
|
||||
<div class="modal-body" id="modal-text">
|
||||
<fieldset>
|
||||
<div class="form-group">
|
||||
<label for="profile_url">Library Picture URL</label>
|
||||
<label for="profile_url">Library Thumbnail URL</label>
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<input type="text" class="form-control" id="custom_thumb_url" name="custom_thumb_url" value="${data['library_thumb']}">
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">Change the library's picture in Tautulli. To reset to default, leave this field empty and save.</p>
|
||||
<p class="help-block">Change the library's thumbnail in Tautulli. To reset to default, leave this field empty and save.</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="profile_url">Library Background Art URL</label>
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<input type="text" class="form-control" id="custom_art_url" name="custom_art_url" value="${data['library_art']}">
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">Change the library's background art in Tautulli. To reset to default, leave this field empty and save.</p>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
@@ -80,6 +89,7 @@ DOCUMENTATION :: END
|
||||
// Save library options
|
||||
$("#save_library").on('click', function () {
|
||||
var custom_thumb = $("#custom_thumb_url").val();
|
||||
var custom_art = $("#custom_art_url").val();
|
||||
var keep_history = 0;
|
||||
if ($("#keep_history").is(":checked")) {
|
||||
keep_history = 1;
|
||||
@@ -90,6 +100,7 @@ DOCUMENTATION :: END
|
||||
data: {
|
||||
section_id: '${data["section_id"]}',
|
||||
custom_thumb: custom_thumb,
|
||||
custom_art: custom_art,
|
||||
keep_history: keep_history
|
||||
},
|
||||
cache: false,
|
||||
@@ -104,21 +115,13 @@ DOCUMENTATION :: END
|
||||
var msg = 'Are you REALLY sure you want to purge all history for the <strong>${data["section_name"]}</strong> library?<br>' +
|
||||
'This is permanent and cannot be undone!';
|
||||
var url = 'delete_all_library_history';
|
||||
confirmAjaxCall(url, msg, { section_id: '${data["section_id"]}' }, null, function () { location.reload(); });
|
||||
confirmAjaxCall(url, msg, { server_id: '${server_id}', section_id: '${data["section_id"]}' }, null, function () { location.reload(); });
|
||||
});
|
||||
|
||||
$('#undelete-library').click(function () {
|
||||
var msg = 'Are you sure you want to undelete this user?';
|
||||
var msg = 'Are you sure you want to undelete this library?';
|
||||
var url = 'undelete_library';
|
||||
confirmAjaxCall(url, msg, { section_id: '${data["section_id"]}' }, null, function () { location.reload(); });
|
||||
});
|
||||
|
||||
$(document).ready(function() {
|
||||
// Move #confirm-modal to parent container
|
||||
if (!($('#edit-library-modal').next().is('#confirm-modal-purge'))) {
|
||||
$('#confirm-modal-purge').appendTo($('#edit-library-modal').parent());
|
||||
}
|
||||
$('#edit-library-modal > #confirm-modal-purge').remove();
|
||||
});
|
||||
</script>
|
||||
% endif
|
@@ -134,13 +134,5 @@ DOCUMENTATION :: END
|
||||
var url = 'undelete_user';
|
||||
confirmAjaxCall(url, msg, { user_id: '${data["user_id"]}' }, null, function () { location.reload(); });
|
||||
});
|
||||
|
||||
$(document).ready(function() {
|
||||
// Move #confirm-modal-purge to parent container
|
||||
if (!($('#edit-user-modal').next().is('#confirm-modal-purge'))) {
|
||||
$('#confirm-modal-purge').appendTo($('#edit-user-modal').parent());
|
||||
}
|
||||
$('#edit-user-modal > #confirm-modal-purge').remove();
|
||||
});
|
||||
</script>
|
||||
% endif
|
289
data/interfaces/default/export_modal.html
Normal file
@@ -0,0 +1,289 @@
|
||||
<%doc>
|
||||
USAGE DOCUMENTATION :: PLEASE LEAVE THIS AT THE TOP OF THIS FILE
|
||||
|
||||
For Mako templating syntax documentation please visit: http://docs.makotemplates.org/en/latest/
|
||||
|
||||
Filename: export_modal.html
|
||||
Version: 0.1
|
||||
Variable names: data [list]
|
||||
|
||||
data :: Usable parameters
|
||||
|
||||
== Global keys ==
|
||||
|
||||
DOCUMENTATION :: END
|
||||
</%doc>
|
||||
<%
|
||||
import plexpy
|
||||
from plexpy import exporter
|
||||
from plexpy.helpers import anon_url
|
||||
export = exporter.Export()
|
||||
thumb_media_types = ', '.join([export.PLURAL_MEDIA_TYPES[k] for k, v in export.MEDIA_TYPES.items() if v[0]])
|
||||
art_media_types = ', '.join([export.PLURAL_MEDIA_TYPES[k] for k, v in export.MEDIA_TYPES.items() if v[1]])
|
||||
%>
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="info-modal-title">
|
||||
${title}
|
||||
</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method="post" class="form" id="export_metadata_form">
|
||||
<input type="hidden" id="export_section_id" name="export_section_id" value="${section_id or ''}" />
|
||||
<input type="hidden" id="export_user_id" name="export_user_id" value="${user_id or ''}" />
|
||||
<input type="hidden" id="export_rating_key" name="export_rating_key" value="${rating_key or ''}" />
|
||||
<input type="hidden" id="export_media_type" name="export_media_type" value="${media_type or ''}" />
|
||||
<input type="hidden" id="export_sub_media_type" name="export_sub_media_type" value="${sub_media_type or ''}" />
|
||||
<input type="hidden" id="export_export_type" name="export_export_type" value="${export_type or ''}" />
|
||||
<div class="form-group">
|
||||
<label>Instructions</label>
|
||||
<p class="help-block">
|
||||
Please see the <a href="${anon_url('https://github.com/%s/%s-Wiki/wiki/Exporter-Guide' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO))}" target="_blank" rel="noreferrer">Exporter Guide</a> for more details about each option.
|
||||
</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="export_file_format">Data File Format</label>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<select class="form-control" id="export_file_format" name="export_file_format">
|
||||
% for format in file_formats:
|
||||
<option value="${format}">${format.upper()}</option>
|
||||
% endfor
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">Select the export data file format.</p>
|
||||
</div>
|
||||
% if not rating_key:
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" id="export_individual_files" name="export_individual_files" value="1"> Export Individual Files
|
||||
</label>
|
||||
<p class="help-block">Enable to export one file for each ${media_type} instead of a single file containing all ${media_type}s.</p>
|
||||
</div>
|
||||
% endif
|
||||
<div class="form-group">
|
||||
<label for="export_metadata_level">Metadata Export Level</label>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<select class="form-control" id="export_metadata_level" name="export_metadata_level">
|
||||
<option value="0">Level 0 - None / Custom</option>
|
||||
<option value="1" selected>Level 1 - Basic Metadata</option>
|
||||
<option value="2">Level 2 - Extended Metadata</option>
|
||||
<option value="3">Level 3 - Advanced Metadata</option>
|
||||
<option value="9">Level 9 - All Metadata</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">Select the metadata export level. Higher levels include all fields from the lower levels.</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="export_custom_metadata_fields">Custom Metadata Fields</label>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<input type="text" class="form-control" id="export_custom_metadata_fields" name="export_custom_metadata_fields" data-field_type="Metadata">
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">Add additional fields to the selected metadata export level.</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="export_media_info_level">Media Info Export Level</label>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<select class="form-control" id="export_media_info_level" name="export_media_info_level">
|
||||
<option value="0">Level 0 - None / Custom</option>
|
||||
<option value="1" selected>Level 1 - Basic Media Info</option>
|
||||
<option value="2">Level 2 - Extended Media Info</option>
|
||||
<option value="3">Level 3 - Advanced Media Info</option>
|
||||
<option value="9">Level 9 - All Media Info</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">Select the media info export level. Higher levels include all fields from the lower levels.</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="export_custom_media_info_fields">Custom Media Info Fields</label>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<input type="text" class="form-control" id="export_custom_media_info_fields" name="export_custom_media_info_fields" data-field_type="Media Info">
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">Add additional fields to the selected media info export level.</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="export_thumb_level">Poster and Cover Image Export Level</label>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<select class="form-control" id="export_thumb_level" name="export_thumb_level">
|
||||
<option value="0" selected>Level 0 - None / Custom</option>
|
||||
<option value="1">Level 1 - Uploaded and Selected Posters and Covers Only</option>
|
||||
<option value="2">Level 2 - Selected and Locked Posters and Covers Only</option>
|
||||
<option value="9">Level 9 - All Selected Posters and Covers</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">
|
||||
Select the level to export poster and cover image files.<br>Note: Only applies to ${thumb_media_types}.
|
||||
</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="export_art_level">Background Artwork Image Export Level</label>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<select class="form-control" id="export_art_level" name="export_art_level">
|
||||
<option value="0" selected>Level 0 - None / Custom</option>
|
||||
<option value="1">Level 1 - Uploaded and Selected Artwork Only</option>
|
||||
<option value="2">Level 2 - Selected and Locked Artwork Only</option>
|
||||
<option value="9">Level 9 - All Selected Artwork</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">
|
||||
Select the level to export background artwork image files.<br>Note: Only applies to ${art_media_types}.
|
||||
</p>
|
||||
</div>
|
||||
<p class="help-block">
|
||||
Warning: Exporting images may take a long time! Images will be saved to a folder alongside the data file.
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div>
|
||||
<input type="button" class="btn btn-bright btn-ok" data-dismiss="modal" id="export_metadata" value="Export">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="${http_root}js/selectize.plugin.disable-options.js"></script>
|
||||
<script>
|
||||
$('#export_metadata_form').submit(function(e) {
|
||||
e.preventDefault();
|
||||
})
|
||||
|
||||
var optgroups = (function () {
|
||||
var optgroups = [];
|
||||
for (var i = 0; i <= 9; i++) {
|
||||
optgroups.push({$order: i+1, value: i});
|
||||
}
|
||||
return optgroups
|
||||
})()
|
||||
|
||||
var $export_custom_fields = $('#export_custom_metadata_fields, #export_custom_media_info_fields').selectize({
|
||||
plugins: {
|
||||
'remove_button': {},
|
||||
'disable_options': {
|
||||
disableField: 'level'
|
||||
}
|
||||
},
|
||||
maxItems: null,
|
||||
valueField: 'field',
|
||||
labelField: 'field',
|
||||
sortField: 'field',
|
||||
searchField: ['field'],
|
||||
optgroupField: 'level',
|
||||
optgroups: optgroups,
|
||||
lockOptgroupOrder: true,
|
||||
render: {
|
||||
optgroup_header: function(data, escape) {
|
||||
return '<div class="optgroup-header">' + escape(this.$input.data('field_type') + ' Level: ' + data.value) + '</div>';
|
||||
},
|
||||
option: function (item, escape) {
|
||||
return '<div data-field="' + escape(item.field) + '" data-level="' + escape(item.level) + '">' + escape(item.field) +'</div>';
|
||||
}
|
||||
}
|
||||
});
|
||||
var export_custom_metadata_fields = $export_custom_fields[0].selectize;
|
||||
var export_custom_media_info_fields = $export_custom_fields[1].selectize;
|
||||
|
||||
function setDisabledFields() {
|
||||
var metadata_export_level = $('#export_metadata_level option:selected').val();
|
||||
var media_info_export_level = $('#export_media_info_level option:selected').val();
|
||||
export_custom_metadata_fields.setDisabledOptions([...Array(parseInt(metadata_export_level) + 1).keys()]);
|
||||
export_custom_media_info_fields.setDisabledOptions([...Array(parseInt(media_info_export_level) + 1).keys()]);
|
||||
}
|
||||
|
||||
$('#export_metadata_level, #export_media_info_level').on('change', setDisabledFields);
|
||||
|
||||
function getExportFields() {
|
||||
$.ajax({
|
||||
url: 'get_export_fields',
|
||||
async: true,
|
||||
data: {
|
||||
media_type: $('#export_media_type').val(),
|
||||
sub_media_type: $('#export_sub_media_type').val()
|
||||
},
|
||||
success: function (result) {
|
||||
if (result) {
|
||||
export_custom_metadata_fields.addOption(result.metadata_fields);
|
||||
export_custom_media_info_fields.addOption(result.media_info_fields);
|
||||
setDisabledFields();
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
getExportFields();
|
||||
|
||||
$('#export_file_format').on('change', function() {
|
||||
if ($(this).val() === 'm3u8') {
|
||||
$('#export_metadata_level').prop('disabled', true);
|
||||
$('#export_media_info_level').prop('disabled', true);
|
||||
$("#export_thumb_level").prop('disabled', true);
|
||||
$("#export_art_level").prop('disabled', true);
|
||||
export_custom_metadata_fields.disable();
|
||||
export_custom_media_info_fields.disable();
|
||||
} else {
|
||||
$('#export_metadata_level').prop('disabled', false);
|
||||
$('#export_media_info_level').prop('disabled', false);
|
||||
$("#export_thumb_level").prop('disabled', false);
|
||||
$("#export_art_level").prop('disabled', false);
|
||||
export_custom_metadata_fields.enable();
|
||||
export_custom_media_info_fields.enable();
|
||||
}
|
||||
})
|
||||
|
||||
$("#export_metadata").click(function() {
|
||||
var section_id = $('#export_section_id').val();
|
||||
var user_id = $('#export_user_id').val();
|
||||
var rating_key = $('#export_rating_key').val();
|
||||
var metadata_export_level = $('#export_metadata_level option:selected').val();
|
||||
var media_info_export_level = $('#export_media_info_level option:selected').val();
|
||||
var file_format = $('#export_file_format option:selected').val();
|
||||
var thumb_level = $("#export_thumb_level option:selected").val();
|
||||
var art_level = $("#export_art_level option:selected").val();
|
||||
var custom_fields = [
|
||||
$('#export_custom_metadata_fields').val(),
|
||||
$('#export_custom_media_info_fields').val()
|
||||
].filter(Boolean).join(',');
|
||||
var export_type = $('#export_export_type').val()
|
||||
var individual_files = $('#export_individual_files').is(':checked')
|
||||
|
||||
$.ajax({
|
||||
url: 'export_metadata',
|
||||
data: {
|
||||
section_id: section_id,
|
||||
user_id: user_id,
|
||||
rating_key: rating_key,
|
||||
metadata_level: metadata_export_level,
|
||||
media_info_level: media_info_export_level,
|
||||
file_format: file_format,
|
||||
thumb_level: thumb_level,
|
||||
art_level: art_level,
|
||||
custom_fields: custom_fields,
|
||||
export_type: export_type,
|
||||
individual_files: individual_files
|
||||
},
|
||||
async: true,
|
||||
success: function (data) {
|
||||
if (data.result === 'success') {
|
||||
$("#nav-tabs-export").click();
|
||||
redrawExportTable();
|
||||
showMsg('<i class="fa fa-check"></i> ' + data.message, false, true, 5000);
|
||||
} else {
|
||||
showMsg('<i class="fa fa-exclamation-circle"></i> ' + data.message, false, true, 5000, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
@@ -40,14 +40,14 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class='table-card-back'>
|
||||
<ul class="nav nav-pills" role="tablist" id="graph-tabs">
|
||||
<li role="presentation"><a href="#tabs-1" aria-controls="tabs-1" data-toggle="tab" role="tab">Plays by Period</a></li>
|
||||
<li role="presentation"><a href="#tabs-2" aria-controls="tabs-2" data-toggle="tab" role="tab">Stream Info</a></li>
|
||||
<li role="presentation"><a href="#tabs-3" aria-controls="tabs-3" data-toggle="tab" role="tab">Play Totals</a></li>
|
||||
<div class="table-card-back">
|
||||
<ul class="nav nav-list nav-pills" role="tablist" id="graph-tabs">
|
||||
<li role="presentation"><a id="nav-tabs-plays" href="#tabs-plays" aria-controls="tabs-plays" data-toggle="tab" role="tab">Plays by Period</a></li>
|
||||
<li role="presentation"><a id="nav-tabs-stream" href="#tabs-stream" aria-controls="tabs-stream" data-toggle="tab" role="tab">Stream Info</a></li>
|
||||
<li role="presentation"><a id="nav-tabs-total" href="#tabs-total" aria-controls="tabs-total" data-toggle="tab" role="tab">Play Totals</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div role="tabpanel" class="tab-pane" id="tabs-1">
|
||||
<div role="tabpanel" class="tab-pane" id="tabs-plays">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h4><i class="fa fa-history"></i> Daily <span class="yaxis-text">Play count</span> <small>Last <span class="days">30</span> days</small></h4>
|
||||
@@ -123,7 +123,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="tabs-2">
|
||||
<div role="tabpanel" class="tab-pane" id="tabs-stream">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h4><i class="fa fa-video-camera"></i> Daily Stream type breakdown <small>Last <span class="days">30</span> days</small></h4>
|
||||
@@ -195,7 +195,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="tabs-3">
|
||||
<div role="tabpanel" class="tab-pane" id="tabs-total">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h4><i class="fa fa-calendar"></i> Plays by month <small>Last <span class="months">12</span> months</small></h4>
|
||||
@@ -225,8 +225,6 @@
|
||||
</%def>
|
||||
|
||||
<%def name="javascriptIncludes()">
|
||||
<script src="${http_root}js/moment-with-locale.js"></script>
|
||||
<script src="${http_root}js/moment-duration-format.js"></script>
|
||||
<script src="${http_root}js/highcharts/js/highcharts.js"></script>
|
||||
<script src="${http_root}js/jquery.dataTables.min.js"></script>
|
||||
<script src="${http_root}js/dataTables.bootstrap.min.js"></script>
|
||||
@@ -252,6 +250,7 @@
|
||||
case "TV": media_type = 'episode'; break;
|
||||
case "Movies": media_type = 'movie'; break;
|
||||
case "Music": media_type = 'track'; break;
|
||||
case "Live TV": media_type = 'live'; break;
|
||||
case "Direct Play": transcode_decision = 'direct play'; break;
|
||||
case "Direct Stream": transcode_decision = 'copy'; break;
|
||||
case "Transcode": transcode_decision = 'transcode'; break;
|
||||
@@ -304,6 +303,23 @@
|
||||
|
||||
setLocalStorage(chart_key, JSON.stringify(chart_visibility));
|
||||
}
|
||||
|
||||
function getGraphColors(data_series) {
|
||||
var colors = {
|
||||
'TV': '#E5A00D',
|
||||
'Movies': '#FFFFFF',
|
||||
'Music': '#F06464',
|
||||
'Live TV': '#19A0D7',
|
||||
'Direct Play': '#E5A00D',
|
||||
'Direct Stream': '#FFFFFF',
|
||||
'Transcode': '#F06464'
|
||||
};
|
||||
var series_colors = [];
|
||||
$.each(data_series, function(index, series) {
|
||||
series_colors.push(colors[series.name]);
|
||||
});
|
||||
return series_colors;
|
||||
}
|
||||
</script>
|
||||
<script src="${http_root}js/graphs/plays_by_day.js${cache_param}"></script>
|
||||
<script src="${http_root}js/graphs/plays_by_dayofweek.js${cache_param}"></script>
|
||||
@@ -323,14 +339,29 @@
|
||||
var yaxis = getLocalStorage('graph_type', 'plays');
|
||||
var current_day_range = getLocalStorage('graph_days', 30);
|
||||
var current_month_range = getLocalStorage('graph_months', 12);
|
||||
var current_tab = '#' + getLocalStorage('graph_tab', 'tabs-1');
|
||||
var current_tab = '#' + getLocalStorage('graph_tab', 'tabs-plays');
|
||||
|
||||
// Update tab values from upgrading
|
||||
switch (current_tab) {
|
||||
case '#tabs-1':
|
||||
current_tab = '#tabs-plays'
|
||||
break
|
||||
case '#tabs-2':
|
||||
current_tab = '#tabs-stream'
|
||||
break
|
||||
case '#tabs-3':
|
||||
current_tab = '#tabs-total'
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
$('#yaxis-' + yaxis).prop('checked', true);
|
||||
$('#yaxis-' + yaxis).closest('label').addClass('active');
|
||||
$('#graph-days').val(current_day_range);
|
||||
$('#graph-months').val(current_month_range);
|
||||
$('#graph-tabs a[href="' + current_tab + '"]').closest('li').addClass('active');
|
||||
$(current_tab).addClass('active');
|
||||
$('#nav-' + current_tab.replace('#', '')).tab('show').trigger('show.bs.tab');
|
||||
//$(current_tab).addClass('active');
|
||||
|
||||
|
||||
$('.days').html(current_day_range);
|
||||
@@ -390,6 +421,7 @@
|
||||
hc_plays_by_day_options.yAxis.min = 0;
|
||||
hc_plays_by_day_options.xAxis.categories = dateArray;
|
||||
hc_plays_by_day_options.series = getGraphVisibility(hc_plays_by_day_options.chart.renderTo, data.series);
|
||||
hc_plays_by_day_options.colors = getGraphColors(data.series);
|
||||
var hc_plays_by_day = new Highcharts.Chart(hc_plays_by_day_options);
|
||||
}
|
||||
});
|
||||
@@ -403,6 +435,7 @@
|
||||
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
||||
hc_plays_by_dayofweek_options.xAxis.categories = data.categories;
|
||||
hc_plays_by_dayofweek_options.series = getGraphVisibility(hc_plays_by_dayofweek_options.chart.renderTo, data.series);
|
||||
hc_plays_by_dayofweek_options.colors = getGraphColors(data.series);
|
||||
var hc_plays_by_dayofweek = new Highcharts.Chart(hc_plays_by_dayofweek_options);
|
||||
}
|
||||
});
|
||||
@@ -416,6 +449,7 @@
|
||||
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
||||
hc_plays_by_hourofday_options.xAxis.categories = data.categories;
|
||||
hc_plays_by_hourofday_options.series = getGraphVisibility(hc_plays_by_hourofday_options.chart.renderTo, data.series);
|
||||
hc_plays_by_hourofday_options.colors = getGraphColors(data.series);
|
||||
var hc_plays_by_hourofday = new Highcharts.Chart(hc_plays_by_hourofday_options);
|
||||
}
|
||||
});
|
||||
@@ -429,6 +463,7 @@
|
||||
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
||||
hc_plays_by_platform_options.xAxis.categories = data.categories;
|
||||
hc_plays_by_platform_options.series = getGraphVisibility(hc_plays_by_platform_options.chart.renderTo, data.series);
|
||||
hc_plays_by_platform_options.colors = getGraphColors(data.series);
|
||||
var hc_plays_by_platform = new Highcharts.Chart(hc_plays_by_platform_options);
|
||||
}
|
||||
});
|
||||
@@ -442,11 +477,12 @@
|
||||
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
||||
hc_plays_by_user_options.xAxis.categories = data.categories;
|
||||
hc_plays_by_user_options.series = getGraphVisibility(hc_plays_by_user_options.chart.renderTo, data.series);
|
||||
hc_plays_by_user_options.colors = getGraphColors(data.series);
|
||||
var hc_plays_by_user = new Highcharts.Chart(hc_plays_by_user_options);
|
||||
}
|
||||
});
|
||||
|
||||
$('#graph-tabs a[href="#tabs-1"]').tab('show')
|
||||
$('#nav-tabs-plays').tab('show');
|
||||
}
|
||||
|
||||
function loadGraphsTab2(time_range, yaxis) {
|
||||
@@ -478,6 +514,7 @@
|
||||
hc_plays_by_stream_type_options.yAxis.min = 0;
|
||||
hc_plays_by_stream_type_options.xAxis.categories = dateArray;
|
||||
hc_plays_by_stream_type_options.series = getGraphVisibility(hc_plays_by_stream_type_options.chart.renderTo, data.series);
|
||||
hc_plays_by_stream_type_options.colors = getGraphColors(data.series);
|
||||
var hc_plays_by_stream_type = new Highcharts.Chart(hc_plays_by_stream_type_options);
|
||||
}
|
||||
});
|
||||
@@ -491,6 +528,7 @@
|
||||
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
||||
hc_plays_by_source_resolution_options.xAxis.categories = data.categories;
|
||||
hc_plays_by_source_resolution_options.series = getGraphVisibility(hc_plays_by_source_resolution_options.chart.renderTo, data.series);
|
||||
hc_plays_by_source_resolution_options.colors = getGraphColors(data.series);
|
||||
var hc_plays_by_source_resolution = new Highcharts.Chart(hc_plays_by_source_resolution_options);
|
||||
}
|
||||
});
|
||||
@@ -504,6 +542,7 @@
|
||||
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
||||
hc_plays_by_stream_resolution_options.xAxis.categories = data.categories;
|
||||
hc_plays_by_stream_resolution_options.series = getGraphVisibility(hc_plays_by_stream_resolution_options.chart.renderTo, data.series);
|
||||
hc_plays_by_stream_resolution_options.colors = getGraphColors(data.series);
|
||||
var hc_plays_by_stream_resolution = new Highcharts.Chart(hc_plays_by_stream_resolution_options);
|
||||
}
|
||||
});
|
||||
@@ -517,6 +556,7 @@
|
||||
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
||||
hc_plays_by_platform_by_stream_type_options.xAxis.categories = data.categories;
|
||||
hc_plays_by_platform_by_stream_type_options.series = getGraphVisibility(hc_plays_by_platform_by_stream_type_options.chart.renderTo, data.series);
|
||||
hc_plays_by_platform_by_stream_type_options.colors = getGraphColors(data.series);
|
||||
var hc_plays_by_platform_by_stream_type = new Highcharts.Chart(hc_plays_by_platform_by_stream_type_options);
|
||||
}
|
||||
});
|
||||
@@ -530,11 +570,12 @@
|
||||
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
||||
hc_plays_by_user_by_stream_type_options.xAxis.categories = data.categories;
|
||||
hc_plays_by_user_by_stream_type_options.series = getGraphVisibility(hc_plays_by_user_by_stream_type_options.chart.renderTo, data.series);
|
||||
hc_plays_by_user_by_stream_type_options.colors = getGraphColors(data.series);
|
||||
var hc_plays_by_user_by_stream_type = new Highcharts.Chart(hc_plays_by_user_by_stream_type_options);
|
||||
}
|
||||
});
|
||||
|
||||
$('#graph-tabs a[href="#tabs-2"]').tab('show')
|
||||
$('#nav-tabs-2').tab('show');
|
||||
}
|
||||
|
||||
function loadGraphsTab3(time_range, yaxis) {
|
||||
@@ -553,20 +594,21 @@
|
||||
hc_plays_by_month_options.yAxis.min = 0;
|
||||
hc_plays_by_month_options.xAxis.categories = data.categories;
|
||||
hc_plays_by_month_options.series = getGraphVisibility(hc_plays_by_month_options.chart.renderTo, data.series);
|
||||
hc_plays_by_month_options.colors = getGraphColors(data.series);
|
||||
var hc_plays_by_month = new Highcharts.Chart(hc_plays_by_month_options);
|
||||
}
|
||||
});
|
||||
|
||||
$('#graph-tabs a[href="#tabs-3"]').tab('show')
|
||||
$('#nav-tabs-total').tab('show');
|
||||
}
|
||||
|
||||
// Set initial state
|
||||
if (current_tab === '#tabs-1') { loadGraphsTab1(current_day_range, yaxis); }
|
||||
if (current_tab === '#tabs-2') { loadGraphsTab2(current_day_range, yaxis); }
|
||||
if (current_tab === '#tabs-3') { loadGraphsTab3(current_month_range, yaxis); }
|
||||
if (current_tab === '#tabs-plays') { loadGraphsTab1(current_day_range, yaxis); }
|
||||
if (current_tab === '#tabs-stream') { loadGraphsTab2(current_day_range, yaxis); }
|
||||
if (current_tab === '#tabs-total') { loadGraphsTab3(current_month_range, yaxis); }
|
||||
|
||||
// Tab1 opened
|
||||
$('#graph-tabs a[href="#tabs-1"]').on('shown.bs.tab', function (e) {
|
||||
$('#nav-tabs-plays').on('shown.bs.tab', function (e) {
|
||||
e.preventDefault();
|
||||
current_tab = $(this).attr('href');
|
||||
setLocalStorage('graph_tab', current_tab.replace('#',''));
|
||||
@@ -574,7 +616,7 @@
|
||||
});
|
||||
|
||||
// Tab2 opened
|
||||
$('#graph-tabs a[href="#tabs-2"]').on('shown.bs.tab', function (e) {
|
||||
$('#nav-tabs-stream').on('shown.bs.tab', function (e) {
|
||||
e.preventDefault();
|
||||
current_tab = $(this).attr('href');
|
||||
setLocalStorage('graph_tab', current_tab.replace('#',''));
|
||||
@@ -582,7 +624,7 @@
|
||||
});
|
||||
|
||||
// Tab3 opened
|
||||
$('#graph-tabs a[href="#tabs-3"]').on('shown.bs.tab', function (e) {
|
||||
$('#nav-tabs-total').on('shown.bs.tab', function (e) {
|
||||
e.preventDefault();
|
||||
current_tab = $(this).attr('href');
|
||||
setLocalStorage('graph_tab', current_tab.replace('#',''));
|
||||
@@ -595,8 +637,8 @@
|
||||
forceMinMax($(this));
|
||||
current_day_range = $(this).val();
|
||||
setLocalStorage('graph_days', current_day_range);
|
||||
if (current_tab === '#tabs-1') { loadGraphsTab1(current_day_range, yaxis); }
|
||||
if (current_tab === '#tabs-2') { loadGraphsTab2(current_day_range, yaxis); }
|
||||
if (current_tab === '#tabs-plays') { loadGraphsTab1(current_day_range, yaxis); }
|
||||
if (current_tab === '#tabs-stream') { loadGraphsTab2(current_day_range, yaxis); }
|
||||
$('.days').html(current_day_range);
|
||||
});
|
||||
|
||||
@@ -606,25 +648,25 @@
|
||||
forceMinMax($(this));
|
||||
current_month_range = $(this).val();
|
||||
setLocalStorage('graph_months', current_month_range);
|
||||
if (current_tab === '#tabs-3') { loadGraphsTab3(current_month_range, yaxis); }
|
||||
if (current_tab === '#tabs-total') { loadGraphsTab3(current_month_range, yaxis); }
|
||||
$('.months').html(current_month_range);
|
||||
});
|
||||
|
||||
// User changed
|
||||
$('#graph-user').on('change', function() {
|
||||
selected_user_id = $(this).val() || null;
|
||||
if (current_tab === '#tabs-1') { loadGraphsTab1(current_day_range, yaxis); }
|
||||
if (current_tab === '#tabs-2') { loadGraphsTab2(current_day_range, yaxis); }
|
||||
if (current_tab === '#tabs-3') { loadGraphsTab3(current_month_range, yaxis); }
|
||||
if (current_tab === '#tabs-plays') { loadGraphsTab1(current_day_range, yaxis); }
|
||||
if (current_tab === '#tabs-stream') { loadGraphsTab2(current_day_range, yaxis); }
|
||||
if (current_tab === '#tabs-total') { loadGraphsTab3(current_month_range, yaxis); }
|
||||
});
|
||||
|
||||
// Y-axis changed
|
||||
$('#yaxis-selection').on('change', function() {
|
||||
yaxis = $('input[name=yaxis-options]:checked', '#yaxis-selection').val();
|
||||
setLocalStorage('graph_type', yaxis);
|
||||
if (current_tab === '#tabs-1') { loadGraphsTab1(current_day_range, yaxis); }
|
||||
if (current_tab === '#tabs-2') { loadGraphsTab2(current_day_range, yaxis); }
|
||||
if (current_tab === '#tabs-3') { loadGraphsTab3(current_month_range, yaxis); }
|
||||
if (current_tab === '#tabs-plays') { loadGraphsTab1(current_day_range, yaxis); }
|
||||
if (current_tab === '#tabs-stream') { loadGraphsTab2(current_day_range, yaxis); }
|
||||
if (current_tab === '#tabs-total') { loadGraphsTab3(current_month_range, yaxis); }
|
||||
});
|
||||
|
||||
function setGraphFormat(type) {
|
||||
|
@@ -8,6 +8,13 @@
|
||||
|
||||
<%def name="body()">
|
||||
<div class='container-fluid'>
|
||||
% if config['database_is_importing']:
|
||||
<div style="text-align: center; margin-top: 20px;">
|
||||
<i class="fa fa-refresh fa-spin"></i> Tautulli is importing history from another database. This could take a few minutes depending on the size of your database.
|
||||
<br />
|
||||
You may leave this page and check back later.
|
||||
</div>
|
||||
% endif
|
||||
<div class='table-card-header'>
|
||||
<div class="header-bar">
|
||||
<span><i class="fa fa-history"></i> History</span>
|
||||
@@ -44,6 +51,9 @@
|
||||
<label class="btn btn-dark">
|
||||
<input type="radio" name="media_type-filter" id="history-track" value="track" autocomplete="off"> Music
|
||||
</label>
|
||||
<label class="btn btn-dark">
|
||||
<input type="radio" name="media_type-filter" id="history-live" value="live" autocomplete="off"> Live TV
|
||||
</label>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-dark refresh-history-button" id="refresh-history-list"><i class="fa fa-refresh"></i> Refresh history</button>
|
||||
@@ -60,7 +70,8 @@
|
||||
<th align="left" id="friendly_name">User</th>
|
||||
<th align="left" id="ip_address">IP Address</th>
|
||||
<th align="left" id="platform">Platform</th>
|
||||
<th align="left" id="device">Player</th>
|
||||
<th align="left" id="product">Product</th>
|
||||
<th align="left" id="player">Player</th>
|
||||
<th align="left" id="title">Title</th>
|
||||
<th align="left" id="started">Started</th>
|
||||
<th align="left" id="paused_counter">Paused</th>
|
||||
@@ -106,7 +117,6 @@
|
||||
<script src="${http_root}js/dataTables.colVis.js"></script>
|
||||
<script src="${http_root}js/dataTables.bootstrap.min.js"></script>
|
||||
<script src="${http_root}js/dataTables.bootstrap.pagination.js"></script>
|
||||
<script src="${http_root}js/moment-with-locale.js"></script>
|
||||
<script src="${http_root}js/tables/history_table.js${cache_param}"></script>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
@@ -143,7 +153,7 @@
|
||||
var colvis = new $.fn.dataTable.ColVis(history_table, {
|
||||
buttonText: '<i class="fa fa-columns"></i> Select columns',
|
||||
buttonClass: 'btn btn-dark',
|
||||
exclude: [0, 11]
|
||||
exclude: [0, 12]
|
||||
});
|
||||
$(colvis.button()).appendTo('div.colvis-button-bar');
|
||||
|
||||
@@ -181,19 +191,17 @@
|
||||
$('#deleteCount').text(history_to_delete.length);
|
||||
$('#confirm-modal-delete').modal();
|
||||
$('#confirm-modal-delete').one('click', '#confirm-delete', function () {
|
||||
history_to_delete.forEach(function(row, idx) {
|
||||
$.ajax({
|
||||
url: 'delete_history_rows',
|
||||
type: 'POST',
|
||||
data: { row_id: row },
|
||||
async: true,
|
||||
success: function (data) {
|
||||
var msg = "History deleted";
|
||||
showMsg(msg, false, true, 2000);
|
||||
}
|
||||
});
|
||||
$.ajax({
|
||||
url: 'delete_history_rows',
|
||||
type: 'POST',
|
||||
data: { row_ids: history_to_delete.join(',') },
|
||||
async: true,
|
||||
success: function (data) {
|
||||
var msg = "History deleted";
|
||||
showMsg(msg, false, true, 2000);
|
||||
history_table.draw();
|
||||
}
|
||||
});
|
||||
history_table.draw();
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -6,7 +6,7 @@
|
||||
<h4 class="modal-title" id="myModalLabel">
|
||||
<strong><span id="modal_header_ip_address">
|
||||
% if data.get('media_type'):
|
||||
<% h = {'episode': 'TV Show', 'track': 'Music'} %>
|
||||
<% h = {'episode': 'TV Show', 'track': 'Music', 'live': 'Live TV'} %>
|
||||
<i class="fa fa-history"></i> ${h.get(data['media_type'], data['media_type'].title())} History for <span id="date-header">${data['start_date']}</span>
|
||||
% elif data.get('transcode_decision'):
|
||||
<% h = {'copy': 'Direct Stream'} %>
|
||||
@@ -26,6 +26,7 @@
|
||||
<th align="left" id="friendly_name">User</th>
|
||||
<th align="left" id="ip_address">IP Address</th>
|
||||
<th align="left" id="platform">Platform</th>
|
||||
<th align="left" id="product">Product</th>
|
||||
<th align="left" id="device">Player</th>
|
||||
<th align="left" id="title">Title</th>
|
||||
<th align="left" id="started">Started</th>
|
||||
@@ -61,7 +62,7 @@
|
||||
};
|
||||
|
||||
history_table = $('#history_table_modal').DataTable(history_table_options);
|
||||
history_table.columns([0, 3, 4, 8, 10, 11]).visible(false);
|
||||
history_table.columns([0, 3, 4, 5, 9, 11, 12]).visible(false);
|
||||
|
||||
clearSearchButton('history_table_modal', history_table);
|
||||
|
||||
|
@@ -53,11 +53,11 @@ DOCUMENTATION :: END
|
||||
</%doc>
|
||||
|
||||
<%!
|
||||
from plexpy import helpers
|
||||
from plexpy.helpers import cast_to_int, page
|
||||
|
||||
# Human readable duration
|
||||
def hd(seconds):
|
||||
m, s = divmod(helpers.cast_to_int(seconds), 60)
|
||||
m, s = divmod(cast_to_int(seconds), 60)
|
||||
h, m = divmod(m, 60)
|
||||
return str(h).zfill(1) + ':' + str(m).zfill(2)
|
||||
%>
|
||||
@@ -72,11 +72,8 @@ DOCUMENTATION :: END
|
||||
<div class="dashboard-stats-instance" id="stats-instance-${stat_id}" data-stat_id="${stat_id}">
|
||||
<div class="dashboard-stats-container">
|
||||
% if stat_id in ('top_movies', 'popular_movies', 'top_tv', 'popular_tv', 'top_music', 'popular_music', 'last_watched'):
|
||||
% if row0['art']:
|
||||
<div id="stats-background-${stat_id}" class="dashboard-stats-background" style="background-image: url(pms_image_proxy?img=${row0['art']}&width=500&height=280&opacity=40&background=282828&blur=3&fallback=art);">
|
||||
% else:
|
||||
<div id="stats-background-${stat_id}" class="dashboard-stats-background" style="background-image: url(images/art.png);">
|
||||
% endif
|
||||
<% fallback = 'art-live' if row0['live'] else 'art' %>
|
||||
<div id="stats-background-${stat_id}" class="dashboard-stats-background" style="background-image: url(${page('pms_image_proxy', row0['art'], row0['rating_key'], 500, 280, 40, '282828', 3, fallback=fallback)});">
|
||||
% elif stat_id == 'top_platforms':
|
||||
<div id="stats-background-${stat_id}" class="dashboard-stats-background platform-${row0['platform_name']}-rgba no-image">
|
||||
% else:
|
||||
@@ -85,21 +82,29 @@ DOCUMENTATION :: END
|
||||
% if stat_id in ('top_movies', 'popular_movies', 'top_tv', 'popular_tv', 'top_music', 'popular_music', 'last_watched'):
|
||||
<div class="dashboard-stats-poster-container hidden-xs">
|
||||
% if stat_id in ('top_music', 'popular_music'):
|
||||
<div id="stats-thumb-${stat_id}-bg" class="dashboard-stats-poster" style="background-image: url(pms_image_proxy?img=${row0['thumb']}&width=300&height=300&opacity=60&background=282828&blur=3&fallback=cover);"></div>
|
||||
<div id="stats-thumb-${stat_id}-bg" class="dashboard-stats-poster" style="background-image: url(${page('pms_image_proxy', row0['thumb'], row0['rating_key'], 300, 300, 60, '282828', 3, fallback='cover')});"></div>
|
||||
% endif
|
||||
<% height, type = ('300', 'cover') if stat_id in ('top_music', 'popular_music') else ('450', 'poster') %>
|
||||
<% href = 'info?rating_key={}'.format(row0['rating_key']) if row0['rating_key'] else '#' %>
|
||||
<%
|
||||
height, fallback = ('450', 'poster')
|
||||
if stat_id in ('top_music', 'popular_music'):
|
||||
height, fallback = ('300', 'cover')
|
||||
elif row0['live']:
|
||||
height, fallback = ('450', 'poster-live')
|
||||
|
||||
href = '#'
|
||||
if row0['rating_key']:
|
||||
if row0['live']:
|
||||
href = page('info', row0['rating_key'], row0['guid'], history=True, live=row0['live'])
|
||||
else:
|
||||
href = page('info', row0['rating_key'])
|
||||
%>
|
||||
<a id="stats-thumb-url-${stat_id}" href="${href}" title="${row0['title']}">
|
||||
% if row0['thumb']:
|
||||
<div id="stats-thumb-${stat_id}" class="dashboard-stats-${type}" style="background-image: url(pms_image_proxy?img=${row0['thumb']}&width=300&height=${height}&fallback=${type});"></div>
|
||||
% else:
|
||||
<div id="stats-thumb-${stat_id}" class="dashboard-stats-${type}" style="background-image: url(images/${type}.png);"></div>
|
||||
% endif
|
||||
<div id="stats-thumb-${stat_id}" class="dashboard-stats-${fallback.split('-')[0]}" style="background-image: url(${page('pms_image_proxy', row0['thumb'], row0['rating_key'], 300, height, fallback=fallback)});"></div>
|
||||
</a>
|
||||
</div>
|
||||
% elif stat_id == 'top_users':
|
||||
<% user_href = 'user?user_id={}'.format(row0['user_id']) if row0['user_id'] else '#' %>
|
||||
<a id="stats-thumb-url-${stat_id}" href="${user_href}" title="${row0['friendly_name']}" class="hidden-xs">
|
||||
<% user_href = page('user', row0['user_id']) if row0['user_id'] else '#' %>
|
||||
<a id="stats-thumb-url-${stat_id}" href="${user_href}" title="${row0['user']}" class="hidden-xs">
|
||||
<div id="stats-thumb-${stat_id}" class="dashboard-stats-circle" style="background-image: url(${row0['user_thumb'] or 'images/gravatar-default.png'})"></div>
|
||||
</a>
|
||||
% elif stat_id == 'top_platforms':
|
||||
@@ -117,7 +122,7 @@ DOCUMENTATION :: END
|
||||
% elif stat_id.startswith('popular'):
|
||||
<span class="dashboard-stats-stats-units">users</span>
|
||||
% elif stat_id == 'last_watched':
|
||||
<span class="dashboard-stats-stats-units" id="last-watched-header-info">${row0['friendly_name']}</span>
|
||||
<span class="dashboard-stats-stats-units" id="last-watched-header-info" title="${row0['user']}">${row0['friendly_name']}</span>
|
||||
% elif stat_id == 'most_concurrent':
|
||||
<span class="dashboard-stats-stats-units" id="most-concurrent-header-info">streams</span>
|
||||
% endif
|
||||
@@ -126,20 +131,28 @@ DOCUMENTATION :: END
|
||||
<div class="dashboard-stats-info scoller-content">
|
||||
<ul class="list-unstyled dashboard-stats-info-list">
|
||||
% for row in top_stat['rows']:
|
||||
<li class="dashboard-stats-info-item ${'expanded' if loop.index == 0 else ''}" data-stat_id="${stat_id}" data-rating_key="${row.get('rating_key')}" data-title="${row.get('title')}"
|
||||
<li class="dashboard-stats-info-item ${'expanded' if loop.index == 0 else ''}" data-stat_id="${stat_id}"
|
||||
data-rating_key="${row.get('rating_key')}" data-guid="${row.get('guid')}" data-title="${row.get('title')}"
|
||||
data-art="${row.get('art')}" data-thumb="${row.get('thumb')}" data-platform="${row.get('platform_name')}"
|
||||
data-user_id="${row.get('user_id')}" data-friendly_name="${row.get('friendly_name')}" data-user_thumb="${row.get('user_thumb')}"
|
||||
data-last_watch="${row.get('last_watch')}" data-started="${row.get('started')}">
|
||||
data-user_id="${row.get('user_id')}" data-user="${row.get('user')}" data-friendly_name="${row.get('friendly_name')}" data-user_thumb="${row.get('user_thumb')}"
|
||||
data-last_watch="${row.get('last_watch')}" data-started="${row.get('started')}" data-live="${row.get('live')}">
|
||||
<div class="sub-list">${loop.index + 1}</div>
|
||||
<div class="sub-value">
|
||||
% if stat_id in ('top_movies', 'popular_movies', 'top_tv', 'popular_tv', 'top_music', 'popular_music', 'last_watched'):
|
||||
<% href = 'info?rating_key={}'.format(row['rating_key']) if row['rating_key'] else '#' %>
|
||||
<%
|
||||
href = '#'
|
||||
if row['rating_key']:
|
||||
if row['live']:
|
||||
href = page('info', row['rating_key'], row['guid'], history=True, live=row['live'])
|
||||
else:
|
||||
href = page('info', row['rating_key'])
|
||||
%>
|
||||
<a href="${href}" title="${row['title']}">
|
||||
${row['title']}
|
||||
</a>
|
||||
% elif stat_id == 'top_users':
|
||||
<% user_href = 'user?user_id={}'.format(row['user_id']) if row['user_id'] else '#' %>
|
||||
<a href="${user_href}" title="${row['friendly_name']}">
|
||||
<% user_href = page('user', row['user_id']) if row['user_id'] else '#' %>
|
||||
<a href="${user_href}" title="${row['user']}">
|
||||
${row['friendly_name']}
|
||||
</a>
|
||||
% elif stat_id == 'top_platforms':
|
||||
@@ -170,78 +183,6 @@ DOCUMENTATION :: END
|
||||
</div>
|
||||
% endif
|
||||
% endfor
|
||||
<script>
|
||||
$('.dashboard-stats-instance .dashboard-stats-info-scroller').scrollbar()
|
||||
|
||||
function changeImages(elem) {
|
||||
var stat_id = $(elem).data('stat_id');
|
||||
var art = $(elem).data('art');
|
||||
var thumb = $(elem).data('thumb');
|
||||
var user_id = $(elem).data('user_id');
|
||||
var user_thumb = $(elem).data('user_thumb');
|
||||
var rating_key = $(elem).data('rating_key');
|
||||
var [height, fallback] = ($.inArray(stat_id, ['top_music', 'popular_music']) > -1) ? [300, 'cover'] : [450, 'poster'];
|
||||
var href;
|
||||
|
||||
if (stat_id == 'most_concurrent') {
|
||||
return
|
||||
} else if (stat_id == 'top_users') {
|
||||
$('#stats-thumb-' + stat_id).css('background-image', 'url(' + (user_thumb || 'images/gravatar-default.png') + ')');
|
||||
if (user_id) {
|
||||
href = 'user?user_id=' + user_id;
|
||||
} else {
|
||||
href = '#';
|
||||
}
|
||||
$('#stats-thumb-url-' + stat_id).attr('href', href).prop('title', $(elem).data('friendly_name'));
|
||||
} else if (stat_id == 'top_platforms') {
|
||||
$('#stats-thumb-' + stat_id).removeClass(function (index, className) {
|
||||
return (className.match (/(^|\s)platform-\S+/g) || []).join(' ');
|
||||
}).addClass('platform-' + $(elem).data('platform'));
|
||||
$('#stats-background-' + stat_id).removeClass(function (index, className) {
|
||||
return (className.match (/(^|\s)platform-\S+/g) || []).join(' ');
|
||||
}).addClass('platform-' + $(elem).data('platform') + '-rgba');
|
||||
} else {
|
||||
if (rating_key) {
|
||||
href = 'info?rating_key=' + rating_key;
|
||||
} else {
|
||||
href = '#';
|
||||
}
|
||||
$('#stats-thumb-url-' + stat_id).attr('href', href).prop('title', $(elem).data('title'));
|
||||
if (art) {
|
||||
$('#stats-background-' + stat_id).css('background-image', 'url(pms_image_proxy?img=' + art + '&width=500&height=280&opacity=40&background=282828&blur=3&fallback=art)');
|
||||
} else {
|
||||
$('#stats-background-' + stat_id).css('background-image', 'url(images/art.png)');
|
||||
}
|
||||
if (thumb) {
|
||||
$('#stats-thumb-' + stat_id).css('background-image', 'url(pms_image_proxy?img=' + thumb + '&width=300&height=' + height + '&fallback=' + fallback + ')');
|
||||
$('#stats-thumb-' + stat_id + '-bg').css('background-image', 'url(pms_image_proxy?img=' + thumb + '&width=300&height=' + height + '&opacity=60&background=282828&blur=3&fallback=' + fallback + ')');
|
||||
} else {
|
||||
$('#stats-thumb-' + stat_id).css('background-image', 'url(images/' + fallback + '.png)');
|
||||
$('#stats-thumb-' + stat_id + '-bg').css('background-image', 'url(images/' + fallback + '.png)');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$('.dashboard-stats-info-item').mouseenter(function () {
|
||||
changeImages(this)
|
||||
if ($(this).data('stat_id') == 'last_watched') {
|
||||
var friendly_name = $(this).data('friendly_name');
|
||||
var last_watch = moment($(this).data('last_watch'), 'X').format(date_format);
|
||||
$('#last-watched-header-info').html(friendly_name);
|
||||
} else if ($(this).data('stat_id') == 'most_concurrent') {
|
||||
var started = moment($(this).data('started'), 'X').format(date_format + ' ' + time_format);
|
||||
$('#most-concurrent-header-info').html(started);
|
||||
}
|
||||
});
|
||||
$('.dashboard-stats-instance').mouseleave(function () {
|
||||
changeImages($(this).find('.dashboard-stats-info-item').first())
|
||||
if ($(this).data('stat_id') == 'last_watched') {
|
||||
$('#last-watched-header-info').text($(this).find('.dashboard-stats-info-item').first().data('friendly_name'));
|
||||
} else if ($(this).data('stat_id') == 'most_concurrent') {
|
||||
$('#most-concurrent-header-info').text('streams');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
% else:
|
||||
<div class="text-muted">No stats to show for the selected period.</div><br>
|
||||
% endif
|
BIN
data/interfaces/default/images/art-live-full.png
Normal file
After Width: | Height: | Size: 786 KiB |
BIN
data/interfaces/default/images/check-solid.ico
Normal file
After Width: | Height: | Size: 99 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 4.5 KiB |
@@ -2,7 +2,7 @@
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="${http_root}images/favicon/mstile-150x150.png?v=2.0.5"/>
|
||||
<square150x150logo src="mstile-150x150.png?v=2.6.0"/>
|
||||
<TileColor>#282a2d</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
|
Before Width: | Height: | Size: 553 B After Width: | Height: | Size: 997 B |
Before Width: | Height: | Size: 971 B After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -1,18 +1,23 @@
|
||||
{
|
||||
"name": "Tautulli",
|
||||
"name": "Tautulli: Monitor your Plex Media Server",
|
||||
"short_name": "Tautulli",
|
||||
"Description": "A Python based monitoring and tracking tool for Plex Media Server.",
|
||||
"start_url": "../../",
|
||||
"scope": "../../",
|
||||
"icons": [
|
||||
{
|
||||
"src": "${http_root}images/favicon/android-chrome-192x192.png?v=2.0.5",
|
||||
"src": "android-chrome-192x192.png?v=2.6.0",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "${http_root}images/favicon/android-chrome-256x256.png?v=2.0.5",
|
||||
"src": "android-chrome-256x256.png?v=2.6.0",
|
||||
"sizes": "256x256",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#282a2d",
|
||||
"background_color": "#282a2d",
|
||||
"display": "standalone"
|
||||
"display": "standalone",
|
||||
"orientation": "any"
|
||||
}
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 10 KiB |
@@ -1 +1,32 @@
|
||||
<svg version="1" xmlns="http://www.w3.org/2000/svg" width="700.000000pt" height="700.000000pt" viewBox="0 0 700.000000 700.000000" preserveAspectRatio="xMidYMid meet"><g transform="translate(0.000000,700.000000) scale(0.100000,-0.100000)" fill="#000000" stroke="none"><path d="M5695 6555 c-135 -34 -244 -94 -342 -189 -40 -39 -73 -76 -73 -83 0 -7 -4 -13 -10 -13 -14 0 -87 -156 -106 -225 -22 -83 -26 -234 -8 -320 17 -79 86 -230 133 -288 l30 -39 -48 -71 c-39 -57 -159 -228 -251 -357 -69 -97 -398 -564 -416 -590 -13 -19 -60 -87 -105 -150 -45 -63 -107 -151 -138 -195 -30 -44 -59 -84 -63 -90 -7 -9 -251 -354 -346 -490 -92 -131 -173 -245 -175 -245 -1 0 -34 9 -72 21 -130 38 -325 31 -454 -18 -168 -63 -313 -196 -385 -354 -39 -87 -65 -183 -68 -256 0 -24 -3 -43 -4 -43 -2 0 -43 46 -91 102 -49 57 -100 117 -115 133 -14 17 -128 149 -253 295 -125 146 -251 292 -279 324 -56 65 -77 89 -108 126 -58 68 -152 178 -172 200 -12 14 -50 57 -83 96 l-61 71 27 44 c58 93 91 217 92 342 2 161 -38 294 -125 412 -133 181 -316 279 -542 292 -470 27 -833 -434 -699 -887 74 -251 275 -437 530 -490 132 -28 334 -6 421 45 l42 24 173 -197 c96 -108 186 -210 200 -227 15 -16 163 -187 330 -380 458 -529 491 -567 526 -605 18 -19 31 -35 30 -36 -6 -5 -265 -161 -277 -167 -8 -4 -34 -20 -58 -35 -194 -124 -634 -382 -651 -382 -12 0 -46 20 -75 44 -60 49 -180 112 -242 127 -21 5 -48 12 -59 15 -11 4 -65 9 -121 11 -81 4 -117 1 -182 -15 -261 -66 -462 -270 -528 -537 -10 -40 -11 -217 -2 -258 5 -23 11 -51 14 -61 29 -145 147 -312 284 -403 123 -82 224 -114 370 -118 83 -3 124 2 240 29 36 9 133 57 187 94 60 41 111 91 153 152 14 19 28 37 32 40 19 15 71 140 89 217 17 73 20 107 16 198 -4 61 -7 121 -9 134 -3 28 -46 0 482 321 179 108 379 228 444 265 104 59 120 65 133 52 13 -13 12 -22 -10 -78 -49 -123 -58 -165 -62 -262 -7 -149 25 -286 89 -383 47 -72 91 -128 125 -158 19 -17 39 -36 45 -42 27 -25 136 -94 150 -94 8 0 17 -4 20 -9 3 -5 16 -11 28 -14 13 -3 50 -12 83 -21 74 -19 278 -15 345 7 198 65 358 196 435 358 16 34 20 36 49 28 17 -4 49 -10 71 -14 22 -3 99 -16 170 -30 72 -13 144 -26 160 -29 28 -5 101 -18 170 -31 17 -3 80 -14 140 -25 61 -11 124 -22 140 -25 17 -4 49 -9 72 -12 40 -5 42 -7 48 -47 14 -98 29 -147 73 -235 36 -75 61 -110 121 -171 154 -154 280 -210 480 -213 134 -2 180 5 273 40 212 83 371 262 427 481 24 93 25 255 2 342 -64 241 -245 428 -481 501 -62 18 -97 23 -200 22 -107 0 -136 -4 -205 -26 -44 -15 -109 -43 -145 -64 -83 -48 -208 -171 -250 -245 -17 -32 -35 -60 -38 -61 -4 -2 -46 4 -93 13 -48 10 -104 20 -125 23 -22 3 -46 8 -54 11 -8 3 -33 7 -55 10 -38 5 -58 9 -122 21 -16 3 -53 10 -83 15 -30 6 -66 12 -79 15 -13 2 -103 19 -200 36 -169 30 -207 42 -196 60 10 16 -28 155 -62 224 -19 39 -54 96 -78 127 l-45 58 40 52 c96 125 143 266 143 433 1 164 -27 263 -108 391 -19 30 -35 57 -35 61 0 3 31 49 69 102 57 81 450 638 625 889 28 40 62 88 76 107 14 18 194 274 400 568 291 414 379 534 393 531 10 -2 27 -6 37 -9 78 -25 240 -29 338 -9 433 87 677 573 489 974 -93 200 -255 332 -478 389 -87 22 -227 25 -304 6z"/></g></svg>
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="350.000000pt" height="350.000000pt" viewBox="0 0 350.000000 350.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.11, written by Peter Selinger 2001-2013
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,350.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M1566 3489 c-433 -46 -867 -274 -1141 -601 -404 -481 -526 -1100
|
||||
-334 -1688 91 -278 283 -569 498 -756 676 -589 1646 -589 2322 0 215 187 407
|
||||
478 498 756 142 436 113 895 -84 1305 -320 666 -1027 1061 -1759 984z m1147
|
||||
-604 c87 -36 146 -118 154 -214 10 -111 -39 -203 -137 -254 -49 -26 -63 -28
|
||||
-131 -25 l-76 3 -109 -154 c-60 -85 -190 -269 -290 -409 l-181 -255 26 -46
|
||||
c22 -38 26 -59 26 -121 0 -63 -5 -84 -29 -132 -27 -54 -28 -59 -13 -76 22 -24
|
||||
47 -86 47 -117 0 -14 6 -28 13 -30 6 -3 91 -16 187 -30 157 -23 175 -24 183
|
||||
-10 38 68 115 118 199 130 103 15 220 -51 268 -151 26 -52 29 -154 6 -207 -19
|
||||
-48 -82 -114 -129 -138 -151 -77 -346 22 -373 189 -7 46 15 39 -222 74 -142
|
||||
20 -155 21 -163 6 -65 -116 -225 -163 -347 -102 -116 58 -167 187 -126 323 8
|
||||
29 13 55 11 57 -3 3 -65 -33 -138 -79 -74 -46 -162 -100 -196 -120 l-62 -38 6
|
||||
-47 c11 -100 -46 -207 -136 -254 -43 -23 -66 -28 -121 -28 -77 0 -124 16 -175
|
||||
62 -48 41 -76 99 -82 167 -7 72 9 129 50 183 85 112 256 132 372 44 l31 -24
|
||||
174 109 c96 60 180 111 185 113 6 2 -2 16 -16 32 -35 39 -412 468 -414 471 0
|
||||
1 -21 -5 -45 -13 -57 -20 -142 -14 -196 14 -162 84 -197 288 -71 419 102 108
|
||||
291 101 386 -14 62 -75 78 -185 40 -273 l-21 -49 23 -28 c13 -16 102 -118 198
|
||||
-227 l175 -198 20 61 c26 78 64 125 124 155 63 31 117 39 177 26 49 -11 51
|
||||
-11 72 17 21 26 533 749 548 773 4 6 -4 28 -17 48 -88 133 -44 307 94 376 61
|
||||
31 163 36 221 11z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 1.8 KiB |
BIN
data/interfaces/default/images/libraries/live.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
9
data/interfaces/default/images/libraries/live.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>live</title>
|
||||
<path fill="#fff" d="M9.636 10.115c-0.829 0.544-1.243 0.816-2.072 1.361-2.331-3.547-2.331-6.195 0-9.749 0.829 0.546 1.244 0.819 2.072 1.361-1.68 2.557-1.68 4.464 0 7.027z"></path>
|
||||
<path fill="#fff" d="M4.374 11.662c-0.828 0.542-1.243 0.815-2.072 1.359-3.069-4.676-3.069-8.159 0-12.838 0.829 0.546 1.244 0.817 2.072 1.362-2.418 3.684-2.418 6.426 0 10.117z"></path>
|
||||
<path fill="#fff" d="M22.365 10.115c0.826 0.544 1.242 0.816 2.070 1.361 2.334-3.547 2.334-6.195 0-9.749-0.828 0.546-1.244 0.819-2.070 1.361 1.677 2.557 1.677 4.464 0 7.027z"></path>
|
||||
<path fill="#fff" d="M27.627 11.662c0.827 0.542 1.243 0.815 2.070 1.359 3.070-4.676 3.070-8.159 0-12.838-0.827 0.546-1.243 0.817-2.070 1.362 2.419 3.684 2.419 6.426 0 10.117z"></path>
|
||||
<path fill="#fff" d="M25.211 31.982l2.611-0.95-8.172-22.45c0.32-0.589 0.502-1.263 0.502-1.979 0-2.293-1.859-4.152-4.152-4.152s-4.151 1.858-4.151 4.152c0 0.672 0.16 1.305 0.443 1.868l-8.212 22.561 2.612 0.95 1.952-5.362h14.616l1.951 5.362zM17.396 10.513l3.945 10.834-7.903-7.9 1.080-2.966c0.46 0.176 0.96 0.272 1.481 0.272 0.49 0.001 0.961-0.084 1.397-0.24zM12.39 16.329l7.51 7.512h-10.245l2.735-7.512z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
BIN
data/interfaces/default/images/logo-circle.icns
Normal file
BIN
data/interfaces/default/images/logo-circle.ico
Normal file
After Width: | Height: | Size: 118 KiB |
BIN
data/interfaces/default/images/logo-flat-white.ico
Normal file
After Width: | Height: | Size: 200 KiB |
BIN
data/interfaces/default/images/logo-flat-white.png
Normal file
After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 112 KiB |
Before Width: | Height: | Size: 107 KiB |
@@ -1,8 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64">
|
||||
<title>android</title>
|
||||
<path fill="#fff" d="M31.944 21.318c5.556 0 11.113 0 16.67 0 0.042 0 0.084-0 0.126 0.001 0.548 0.012 0.554 0.012 0.554 0.555 0.002 2.526 0.001 5.052 0.001 7.577 0 5.789 0.003 11.577-0.002 17.365-0.001 1.197-0.344 2.274-1.205 3.155-0.759 0.777-1.671 1.191-2.753 1.22-0.757 0.019-1.515 0.011-2.273 0.016-0.772 0.005-0.774 0.006-0.774 0.751-0.001 2.505-0.032 5.010 0.013 7.514 0.024 1.305-0.386 2.363-1.302 3.29-1.214 1.23-3.457 1.485-4.769 0.396-1.051-0.873-1.725-1.978-1.715-3.423 0.019-2.547 0.010-5.093 0.003-7.64-0.003-1.010 0.144-0.869-0.858-0.876-1.158-0.008-2.315-0.005-3.473-0.001-0.829 0.003-0.76-0.103-0.76 0.794-0.002 2.505-0.027 5.010 0.010 7.514 0.019 1.278-0.377 2.325-1.281 3.235-1.199 1.208-3.371 1.494-4.716 0.437-1.067-0.838-1.779-1.932-1.77-3.386 0.017-2.61 0.005-5.219 0.005-7.829 0-0.147-0.008-0.295 0-0.442 0.013-0.24-0.092-0.339-0.334-0.335-0.736 0.012-1.473 0.002-2.209 0.022-0.575 0.015-1.129-0.058-1.673-0.251-1.682-0.597-2.691-2.017-2.737-3.858-0.063-2.566-0.031-5.135-0.035-7.703-0.007-5.304-0.010-10.608-0.016-15.912-0.001-0.568-0.017-1.136-0.018-1.704-0-0.464 0.006-0.472 0.494-0.479 0.989-0.013 1.978-0.023 2.968-0.023 4.609-0.002 9.219-0.001 13.829-0.001-0.001 0.006-0.001 0.014-0.001 0.021z"></path>
|
||||
<path fill="#fff" d="M31.944 19.89c-5.535 0-11.071 0.002-16.606-0.002-0.717-0-0.772 0.153-0.687-0.747 0.189-2.003 0.58-3.948 1.437-5.784 1.041-2.228 2.47-4.152 4.433-5.648 0.864-0.658 1.646-1.43 2.624-1.932 0.216-0.111 0.25-0.23 0.129-0.443-0.363-0.64-0.715-1.286-1.059-1.937-0.441-0.835-0.877-1.674-1.302-2.518-0.247-0.491-0.206-0.765 0.103-0.941 0.342-0.194 0.625-0.077 0.892 0.415 0.721 1.329 1.429 2.664 2.142 3.997 0.069 0.13 0.141 0.258 0.215 0.386 0.226 0.39 0.228 0.394 0.671 0.218 2.478-0.987 5.051-1.43 7.715-1.338 2.143 0.074 4.214 0.501 6.214 1.273 0.118 0.045 0.241 0.081 0.35 0.142 0.186 0.102 0.303 0.067 0.405-0.126 0.534-1.023 1.075-2.043 1.617-3.062 0.297-0.557 0.592-1.115 0.908-1.66 0.189-0.325 0.514-0.408 0.809-0.253 0.292 0.153 0.366 0.43 0.175 0.817-0.39 0.79-0.791 1.575-1.204 2.353-0.383 0.725-0.789 1.438-1.18 2.159-0.19 0.351-0.181 0.348 0.158 0.573 1.666 1.102 3.266 2.297 4.577 3.814 1.895 2.192 3.115 4.723 3.574 7.598 0.119 0.746 0.175 1.503 0.266 2.254 0.038 0.311-0.097 0.421-0.393 0.394-0.146-0.014-0.295-0.002-0.442-0.002-5.514 0-11.028 0-16.543 0zM25.561 12.038c-0.063-1.117-0.623-1.553-1.433-1.566-0.833-0.014-1.419 0.462-1.455 1.603-0.025 0.776 0.66 1.407 1.463 1.409 0.79 0.001 1.421-0.64 1.424-1.445zM39.872 13.483c0.788-0.007 1.497-0.676 1.439-1.441-0.076-0.997-0.486-1.549-1.506-1.576-0.841-0.022-1.403 0.67-1.386 1.605 0.016 0.816 0.635 1.418 1.453 1.411z"></path>
|
||||
<path fill="#fff" d="M50.587 32.655c0-2.715-0.003-5.429 0.001-8.143 0.003-1.77 0.853-2.959 2.453-3.698 0.717-0.331 1.433-0.52 2.172-0.287 0.794 0.251 1.537 0.649 2.123 1.273 0.519 0.552 0.839 1.207 0.944 1.957 0.052 0.374 0.082 0.754 0.083 1.131 0.005 5.282-0.005 10.564 0.010 15.846 0.004 1.249-0.402 2.288-1.278 3.179-1.245 1.267-3.35 1.546-4.76 0.479-1.076-0.815-1.719-1.943-1.745-3.342-0.019-1.010-0.013-2.020-0.014-3.030-0.002-1.789-0.001-3.578-0.001-5.366 0.004-0 0.008-0 0.012-0z"></path>
|
||||
<path fill="#fff" d="M13.369 32.464c0 2.335-0.001 4.669 0.001 7.004 0 0.63 0.047 1.263 0.002 1.889-0.072 1.003-0.541 1.811-1.23 2.554-0.931 1.004-2.059 1.18-3.323 1.058-1.55-0.15-3.156-2.028-3.181-3.665-0.004-0.231-0.015-0.462-0.014-0.694 0.003-5.406 0.007-10.812 0.011-16.218 0.001-1.655 0.863-2.749 2.268-3.501 0.683-0.366 1.397-0.602 2.158-0.402 1.622 0.427 3.305 1.697 3.292 3.834-0.016 2.713-0.004 5.427-0.004 8.141 0.007-0 0.013-0 0.020 0z"></path>
|
||||
<path fill="#fff" d="M46.73 40.88c-0.003 0-0.007 0-0.010 0-1.475 0-2.67-1.195-2.67-2.67s1.195-2.67 2.67-2.67c1.475 0 2.67 1.195 2.67 2.67v0c0 0 0 0 0 0 0 1.471-1.19 2.664-2.659 2.67h-0.001zM17.27 40.88c-1.475 0-2.67-1.195-2.67-2.67s1.195-2.67 2.67-2.67c1.475 0 2.67 1.195 2.67 2.67v0c0 0.003 0 0.007 0 0.010 0 1.469-1.191 2.66-2.66 2.66-0.003 0-0.007 0-0.011 0h0.001zM47.68 24.83l5.32-9.23c0.095-0.159 0.151-0.351 0.151-0.557 0-0.405-0.219-0.76-0.546-0.951l-0.005-0.003c-0.16-0.095-0.354-0.152-0.56-0.152-0.407 0-0.764 0.22-0.957 0.547l-0.003 0.005-5.38 9.34c-4.027-1.851-8.738-2.93-13.7-2.93s-9.673 1.079-13.909 3.016l0.209-0.086-5.39-9.34c-0.204-0.28-0.531-0.46-0.9-0.46-0.613 0-1.11 0.497-1.11 1.11 0 0.167 0.037 0.325 0.103 0.467l-0.003-0.007 5.33 9.23c-9.153 5.047-15.453 14.286-16.323 25.059l-0.007 0.111h64c-0.875-10.883-7.171-20.121-16.158-25.088l-0.162-0.082z"></path>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 1.0 KiB |
7
data/interfaces/default/images/platforms/lg.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64">
|
||||
<title>lg</title>
|
||||
<path fill="#fff" d="M30.203 31.797c0 8.176-6.654 14.832-14.835 14.82-7.927-0.011-14.818-6.28-14.812-14.838 0.005-8.282 6.541-14.82 14.841-14.803 8.618 0.017 14.807 6.969 14.806 14.822zM26.577 32.388c-0.087 4.433-3.485 9.518-9.37 10.487-6.122 1.008-11.584-2.989-12.814-8.656-0.632-2.912-0.221-5.696 1.362-8.228 2.347-3.754 5.815-5.502 10.222-5.453 0-0.387 0-0.761 0-1.134-4.114-0.281-9.226 1.824-11.763 6.923-2.454 4.932-1.296 10.953 2.811 14.672 4.153 3.762 10.224 4.309 14.953 1.326 2.328-1.468 3.999-3.496 4.997-6.067 0.628-1.617 0.882-3.296 0.813-5.032-2.967 0-5.909 0-8.864 0 0 0.39 0 0.768 0 1.162 2.558-0 5.097-0 7.652-0zM15.991 37.112c0-0.129 0-0.221 0-0.313 0-3.731 0-7.463 0-11.194 0-0.060-0.004-0.119 0-0.179 0.009-0.118-0.038-0.166-0.16-0.163-0.278 0.006-0.556 0.012-0.833-0.002-0.178-0.008-0.237 0.042-0.237 0.23 0.005 4.194 0.005 8.389-0 12.583-0 0.198 0.065 0.239 0.249 0.237 1.224-0.007 2.448-0.004 3.672-0.004 0.072 0 0.143 0 0.244 0 0-0.343-0.008-0.665 0.003-0.987 0.006-0.166-0.050-0.214-0.214-0.212-0.82 0.007-1.641 0.003-2.461 0.003-0.078 0-0.155 0-0.263 0zM12.434 27.068c0.003-0.987-0.799-1.798-1.785-1.805s-1.799 0.796-1.805 1.782c-0.006 0.985 0.799 1.8 1.783 1.805 0.985 0.004 1.804-0.803 1.807-1.783z"></path>
|
||||
<path fill="#fff" d="M63.467 30.606c0 2.864 0 5.707 0 8.571-1.242 0-2.479 0-3.742 0 0-0.468 0-0.933 0-1.433-0.203 0.226-0.366 0.432-0.553 0.612-0.683 0.656-1.518 1-2.441 1.136-1.187 0.174-2.348 0.075-3.462-0.4-1.234-0.526-2.145-1.407-2.8-2.565-0.599-1.058-0.906-2.207-1.035-3.409-0.148-1.367-0.103-2.723 0.28-4.051 0.797-2.764 2.635-4.391 5.453-4.899 1.534-0.277 3.058-0.208 4.54 0.311 1.243 0.436 2.298 1.139 3.011 2.276 0.431 0.688 0.584 1.467 0.687 2.258 0.013 0.097 0.028 0.195 0.046 0.318-0.064 0.003-0.126 0.010-0.188 0.010-1.389 0.001-2.779-0.002-4.169 0.003-0.151 0.001-0.215-0.034-0.245-0.197-0.229-1.234-1.281-1.773-2.308-1.679-1.182 0.108-1.823 0.859-2.22 1.888-0.211 0.547-0.315 1.12-0.352 1.703-0.066 1.061-0.039 2.117 0.31 3.138 0.211 0.618 0.523 1.173 1.050 1.579 1.371 1.055 3.326 0.436 3.877-1.228 0.090-0.274 0.157-0.557 0.246-0.875-0.112 0-0.182 0-0.251 0-0.794 0-1.588-0.005-2.382 0.004-0.168 0.002-0.213-0.053-0.212-0.214 0.006-0.887 0.005-1.774 0.001-2.66-0.001-0.139 0.019-0.215 0.192-0.215 2.17 0.006 4.341 0.004 6.511 0.004 0.045 0 0.090 0.008 0.157 0.013z"></path>
|
||||
<path fill="#fff" d="M48.501 35.522c0 1.233 0 2.44 0 3.661-3.613 0-7.216 0-10.834 0 0-4.923 0-9.841 0-14.77 1.44 0 2.872 0 4.331 0 0 0.092 0 0.175 0 0.259 0 3.526 0 7.053 0 10.579 0 0.271 0 0.271 0.267 0.271 1.985 0 3.97 0 5.954 0 0.086 0 0.171 0 0.281 0z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 2.7 KiB |
1
data/interfaces/default/images/rating/imdb.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 1000 560" xmlns="http://www.w3.org/2000/svg" stroke-miterlimit="1.414" clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round"><path d="M0 89.996C0 62.384 22.378 40 49.997 40h900.006C977.616 40 1000 62.388 1000 89.996v380.008c0 27.612-22.378 49.996-49.997 49.996H49.997C22.384 520 0 497.612 0 470.004V89.996z" fill="#e1be00"/><path d="M769.68 134.76v94.64c6.03-6.976 12.753-12.181 20.17-15.61 7.419-3.428 18.552-5.157 27.24-5.157 10.01 0 18.685 1.552 26.04 4.667 7.362 3.109 12.967 7.471 16.829 13.08 3.857 5.614 6.172 11.11 6.962 16.485.781 5.377 1.176 16.843 1.176 34.41v81.63c0 17.448-1.176 30.434-3.528 38.981-2.357 8.543-7.881 15.958-16.567 22.23-8.691 6.267-19 9.405-30.952 9.405-8.567 0-19.648-1.857-27.07-5.581-7.424-3.724-14.21-9.314-20.362-16.767l-4.709 18.538h-68.04v-290.95h72.809m-631.58 290.95h75.58v-290.95h-75.58v290.95m199.38-290.95c2.881 17.615 5.9 38.29 9.06 62.01l10.829 73.915 17.505-135.92h98.73v290.95h-65.99l-.239-196.38-26.433 196.38h-47.15l-27.862-192.11-.238 192.11h-66.2v-290.95h97.99m218.36 0c36.581 0 57.629 1.681 70.52 5.03 12.895 3.347 22.705 8.847 29.419 16.504 6.719 7.657 10.915 16.181 12.595 25.567 1.677 9.39 2.752 27.843 2.752 55.36v102.18c0 26.08-1.461 43.519-3.918 52.31-2.462 8.8-6.748 15.676-12.862 20.638-6.124 4.962-13.676 8.433-22.672 10.404-9 1.977-22.551 2.962-40.657 2.962h-91.57v-290.95h56.39m239.33 220.35c0 14.08-.7 22.977-2.096 26.677-1.4 3.704-7.485 5.566-12.1 5.566-4.5 0-7.5-1.786-9.02-5.371-1.519-3.581-2.272-11.757-2.272-24.538v-76.891c0-13.257.667-21.519 2-24.809 1.333-3.277 4.248-4.924 8.743-4.924 4.609 0 10.796 1.871 12.376 5.633 1.576 3.762 2.367 11.795 2.367 24.09v74.57m-203.37-167.99c2.986 1.728 4.901 4.457 5.734 8.157.833 3.709 1.257 12.138 1.257 25.29v112.8c0 19.371-1.257 31.23-3.767 35.595-2.509 4.371-9.2 6.548-20.06 6.548v-190.99c8.234 0 13.852.866 16.838 2.6"/></svg>
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="560" height="560" viewBox="0 0 560 560">
|
||||
<g fill="none" transform="translate(33 140)">
|
||||
<path fill="#FFF" d="M43.8020066,267.3152 L281.745403,290.797105 C286.539148,305.7344 292.894623,320.31421 302.004138,331.0528 L71.7380852,300.927619 C61.4905377,294.175695 50.8770689,281.050362 43.8020066,267.3152 Z M266.684852,192.017143 C267.285384,212.923048 270.116459,239.981562 275.03101,263.034133 L33.8766098,243.950705 C26.3585902,221.21181 24.03,207.991848 22.1723803,189.066133 L266.684852,192.017143 Z M275.03101,89.3083429 C270.116459,112.360914 267.285384,139.419429 266.684852,160.325333 L22.1723803,163.276343 C24.03,144.350629 26.3585902,131.130667 33.8766098,108.391771 L275.03101,89.3083429 Z M302.004138,21.2896762 C292.894623,32.030019 286.539148,46.6080762 281.745403,61.5471238 L43.8020066,85.0272762 C50.8770689,71.2921143 61.4905377,58.1685333 71.7380852,51.4148571 L302.004138,21.2896762 Z"/>
|
||||
<path fill="#00641E" d="M303.565869,264.667352 C306.720846,256.846476 317.903331,252.081752 325.93259,252.63901 C334.515108,253.234819 343.631626,262.264838 345.224872,271.145905 C345.520761,270.823467 345.830656,270.518552 346.145803,270.218895 C348.901593,267.583314 352.35421,265.834438 356.132479,265.352533 C355.554708,262.790552 355.416393,260.048076 355.812079,257.233752 C357.207482,247.3328 365.145698,239.907962 374.234203,239.981562 C380.099449,240.028876 385.245108,243.032457 388.597928,247.646476 C388.897318,247.271467 389.228223,246.928 389.550374,246.577524 C393.384669,226.586362 395.814807,203.999924 396.368066,180.030857 C398.267705,97.6111238 377.375174,30.2776381 349.70522,29.6397714 C322.033515,29.0001524 298.061292,95.2962286 296.161652,177.715962 C296.161652,177.715962 294.696216,207.778057 303.565869,264.667352"/>
|
||||
<path fill="#FFD700" d="M490.910577,354.797562 C492.545843,352.0656 493.45977,348.7904 493.396741,345.310171 C493.927239,334.065143 486.214879,323.871543 475.484105,325.000076 C475.794,323.713829 475.997095,322.376762 476.075882,320.997638 C476.718433,309.733333 468.957049,300.025143 458.739266,299.315429 C458.515161,299.30141 458.294557,299.2944 458.072203,299.28739 C459.134951,296.492343 459.661948,293.371352 459.47461,290.06461 C458.945862,280.692876 452.488839,272.796648 444.088407,271.242286 C441.054236,270.681524 438.111108,270.960152 435.416597,271.894171 C432.870905,265.617143 427.525652,260.961067 421.023108,259.977981 C420.508367,249.786133 413.153174,241.397486 403.68299,240.740343 C397.728452,240.326781 392.257141,243.064 388.597928,247.646476 C385.245108,243.032457 380.099449,240.030629 374.234203,239.983314 C365.145698,239.907962 357.207482,247.3328 355.812079,257.235505 C355.416393,260.048076 355.554708,262.790552 356.132479,265.354286 C352.35421,265.834438 348.901593,267.585067 346.145803,270.218895 C345.830656,270.518552 345.520761,270.823467 345.224872,271.145905 C343.631626,262.264838 334.515108,253.236571 325.93259,252.63901 C317.903331,252.081752 306.575528,256.963886 303.565869,264.667352 C304.885987,278.101105 313.275915,314.72061 343.621121,347.570743 L343.890748,347.590019 C346.816367,350.239619 350.636656,351.699352 354.709062,351.33661 C357.233744,351.110552 359.558833,350.206324 361.56177,348.811429 L362.050249,348.844724 C364.720249,350.700495 367.929502,351.671314 371.320839,351.369905 C372.616446,351.254248 373.852525,350.942324 375.027325,350.497219 C377.933685,356.51139 384.41522,360.398171 391.649607,359.760305 C397.25223,359.266133 402.014459,356.164419 404.81402,351.799238 L405.720944,351.862324 C408.517003,354.636343 412.233993,356.252038 416.24337,356.131124 C419.557672,361.149943 425.645272,364.237638 432.363167,363.647086 C434.893102,363.424533 437.254957,362.692038 439.361193,361.582781 C442.875089,365.90941 448.642289,368.481905 454.969751,367.924648 C461.22543,367.376152 466.509403,363.904686 469.384249,359.104914 C472.208321,361.374248 475.746728,362.592152 479.503987,362.257448 C483.149193,361.931505 486.38821,360.208914 488.821849,357.603124 L489.228039,357.631162 C489.781298,356.828571 490.25402,356.006705 490.693475,355.177829 C490.70398,355.162057 490.712734,355.144533 490.721489,355.128762 C490.781016,355.018362 490.854551,354.909714 490.910577,354.797562"/>
|
||||
<path fill="#04A53C" d="M281.745403,61.5471238 L43.8020066,85.0272762 C50.8770689,71.2921143 61.4905377,58.1685333 71.7380852,51.4148571 L302.004138,21.2896762 C292.894623,32.030019 286.539148,46.6080762 281.745403,61.5471238 Z M302.004138,331.0528 L71.7380852,300.927619 C61.4905377,294.175695 50.8770689,281.050362 43.8020066,267.316952 L281.745403,290.797105 C286.539148,305.7344 292.894623,320.31421 302.004138,331.0528 Z M33.8766098,243.950705 C26.3585902,221.21181 24.03,207.9936 22.1723803,189.066133 L266.684852,192.017143 C267.285384,212.923048 270.116459,239.981562 275.03101,263.034133 L33.8766098,243.950705 Z M33.8766098,108.391771 L275.03101,89.3083429 C270.116459,112.360914 267.285384,139.419429 266.684852,160.327086 L22.1723803,163.276343 C24.03,144.350629 26.3585902,131.130667 33.8766098,108.391771 Z M378.597246,25.7126857 C363.342354,7.93478095 352.390977,-0.411809524 343.010085,0.672914286 C341.261016,0.895466667 76.1168852,37.8952381 76.1168852,37.8952381 C34.0429377,42.1780571 0.416695082,103.32739 0,176.172114 C0.416695082,249.015086 34.0429377,310.164419 76.1168852,314.44899 C76.1168852,314.44899 341.758249,351.583695 343.010085,351.669562 C345.228374,351.655543 347.418649,351.357638 349.57741,350.803886 C347.476426,350.178286 345.538269,349.083048 343.890748,347.590019 L343.621121,347.570743 C313.275915,314.722362 304.885987,278.101105 303.565869,264.667352 C303.56937,264.656838 303.576374,264.648076 303.579875,264.637562 C303.576374,264.648076 303.56937,264.656838 303.565869,264.667352 C294.696216,207.778057 296.161652,177.715962 296.161652,177.715962 C298.061292,95.2962286 322.033515,29.0001524 349.70522,29.638019 C377.375174,30.2776381 398.267705,97.6111238 396.368066,180.030857 C395.814807,203.999924 393.384669,226.586362 389.550374,246.577524 C393.489718,242.226362 398.773692,240.393371 403.68299,240.740343 C404.586413,240.805181 405.465325,240.957638 406.326728,241.155657 C423.131095,149.125867 405.514348,59.262019 378.597246,25.7126857 Z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.1 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="560" height="560"><g fill="none"><path fill="#FFF" d="M370.57 474.214l23.466-237.956c14.93-4.796 29.498-11.15 40.23-20.262L404.16 446.278c-6.748 10.248-19.863 20.86-33.59 27.936zm-78.197 21.631l2.947-244.528c20.894-.599 47.933-3.43 70.97-8.346l-19.07 241.17c-22.724 7.518-35.934 9.848-54.847 11.704zm-99.694-252.874c23.038 4.916 50.077 7.747 70.971 8.346l2.948 244.528c-18.914-1.856-32.123-4.186-54.847-11.705l-19.072-241.17zm-67.974-26.975c10.732 9.112 25.3 15.466 40.23 20.262l23.464 237.956c-13.726-7.075-26.84-17.688-33.59-27.936l-30.104-230.282z"/><path fill="gold" d="M118.905 157.445c1.357 28.827 72.771 51.677 160.578 51.176 76.687-.438 140.659-18.546 156.329-42.336a22.976 22.976 0 00-14.058-7.426c.06-.7.098-1.406.095-2.122-.065-11.4-8.429-20.788-19.327-22.54.287-1.474.438-2.999.43-4.559-.072-12.696-10.426-22.928-23.124-22.856-.287.001-.568.036-.853.049a22.911 22.911 0 001.254-7.56c-.074-12.697-10.425-22.93-23.123-22.858a22.914 22.914 0 00-8.247 1.6c-3.632-6.835-10.606-11.6-18.737-12.149-1.416-11.4-11.157-20.195-22.93-20.129-7.41.042-13.963 3.6-18.136 9.065-4.233-4.605-10.3-7.494-17.047-7.456-12.698.072-22.932 10.424-22.86 23.118a22.983 22.983 0 001.115 6.946 22.918 22.918 0 00-13.07 7.459c-2.644-9.847-11.637-17.084-22.314-17.024-9.975.057-18.406 6.47-21.537 15.366-8.474 3.426-14.439 11.738-14.383 21.433.012 2.154.342 4.227.907 6.202a22.876 22.876 0 00-9.328-1.932c-10.012.058-18.47 6.516-21.574 15.465a22.83 22.83 0 00-9.788-2.149c-12.698.072-22.934 10.422-22.86 23.118a22.833 22.833 0 003.159 11.463c-.202.203-.379.426-.571.636"/><path fill="#FA320A" d="M404.161 446.278c-6.749 10.248-19.864 20.86-33.59 27.936l23.465-237.956c14.93-4.796 29.498-11.15 40.23-20.262L404.16 446.278zM347.22 484.14c-22.723 7.519-35.934 9.85-54.847 11.705l2.947-244.528c20.894-.599 47.933-3.43 70.973-8.346L347.22 484.14zm-135.47 0l-19.07-241.17c23.037 4.917 50.076 7.748 70.97 8.347l2.948 244.528c-18.914-1.856-32.123-4.186-54.847-11.705zm-56.94-37.862l-30.105-230.282c10.732 9.112 25.3 15.466 40.23 20.262l23.464 237.956c-13.726-7.075-26.84-17.688-33.588-27.936zm247.668-321.143c.298 1.453.465 2.955.473 4.498a23.018 23.018 0 01-.43 4.56c10.9 1.749 19.263 11.137 19.328 22.54a23.59 23.59 0 01-.095 2.12 22.976 22.976 0 0114.058 7.425c-15.669 23.792-79.642 41.9-156.327 42.34-87.807.502-159.221-22.346-160.58-51.175.192-.208.37-.433.57-.634-1.355-2.311-2.29-4.887-2.773-7.62-8.408 7.979-13.495 14.412-12.6 23.78.085 1.251 37.196 266.911 37.196 266.911 4.282 42.075 65.391 75.703 138.187 76.12 72.796-.417 133.907-34.045 138.187-76.12 0 0 37.11-265.66 37.197-266.912 1.777-18.736-20.15-35.745-52.39-47.833z"/></g></svg>
|
After Width: | Height: | Size: 2.6 KiB |
1
data/interfaces/default/images/rating/themoviedb.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 190.24 81.52"><defs><linearGradient id="a" y1="40.76" x2="190.24" y2="40.76" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#90cea1"/><stop offset=".56" stop-color="#3cbec9"/><stop offset="1" stop-color="#00b3e5"/></linearGradient></defs><g data-name="Layer 2"><path d="M105.67 36.06h66.9a17.67 17.67 0 0017.67-17.66A17.67 17.67 0 00172.57.73h-66.9A17.67 17.67 0 0088 18.4a17.67 17.67 0 0017.67 17.66zm-88 45h76.9a17.67 17.67 0 0017.67-17.66 17.67 17.67 0 00-17.67-17.67h-76.9A17.67 17.67 0 000 63.4a17.67 17.67 0 0017.67 17.66zm-7.26-45.64h7.8V6.92h10.1V0h-28v6.9h10.1zm28.1 0h7.8V8.25h.1l9 27.15h6l9.3-27.15h.1V35.4h7.8V0H66.76l-8.2 23.1h-.1L50.31 0h-11.8zm113.92 20.25a15.07 15.07 0 00-4.52-5.52 18.57 18.57 0 00-6.68-3.08 33.54 33.54 0 00-8.07-1h-11.7v35.4h12.75a24.58 24.58 0 007.55-1.15 19.34 19.34 0 006.35-3.32 16.27 16.27 0 004.37-5.5 16.91 16.91 0 001.63-7.58 18.5 18.5 0 00-1.68-8.25zM145 68.6a8.8 8.8 0 01-2.64 3.4 10.7 10.7 0 01-4 1.82 21.57 21.57 0 01-5 .55h-4.05v-21h4.6a17 17 0 014.67.63 11.66 11.66 0 013.88 1.87A9.14 9.14 0 01145 59a9.87 9.87 0 011 4.52 11.89 11.89 0 01-1 5.08zm44.63-.13a8 8 0 00-1.58-2.62 8.38 8.38 0 00-2.42-1.85 10.31 10.31 0 00-3.17-1v-.1a9.22 9.22 0 004.42-2.82 7.43 7.43 0 001.68-5 8.42 8.42 0 00-1.15-4.65 8.09 8.09 0 00-3-2.72 12.56 12.56 0 00-4.18-1.3 32.84 32.84 0 00-4.62-.33h-13.2v35.4h14.5a22.41 22.41 0 004.72-.5 13.53 13.53 0 004.28-1.65 9.42 9.42 0 003.1-3 8.52 8.52 0 001.2-4.68 9.39 9.39 0 00-.55-3.18zm-19.42-15.75h5.3a10 10 0 011.85.18 6.18 6.18 0 011.7.57 3.39 3.39 0 011.22 1.13 3.22 3.22 0 01.48 1.82 3.63 3.63 0 01-.43 1.8 3.4 3.4 0 01-1.12 1.2 4.92 4.92 0 01-1.58.65 7.51 7.51 0 01-1.77.2h-5.65zm11.72 20a3.9 3.9 0 01-1.22 1.3 4.64 4.64 0 01-1.68.7 8.18 8.18 0 01-1.82.2h-7v-8h5.9a15.35 15.35 0 012 .15 8.47 8.47 0 012.05.55 4 4 0 011.57 1.18 3.11 3.11 0 01.63 2 3.71 3.71 0 01-.43 1.92z" fill="url(#a)" data-name="Layer 1"/></g></svg>
|
After Width: | Height: | Size: 1.9 KiB |
1
data/interfaces/default/images/rating/tomato-ripe.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="560" height="560"><g fill="none"><path fill="#FA320A" d="M478.29 296.976c-3.99-63.966-36.52-111.823-85.468-138.579.278 1.56-1.109 3.508-2.688 2.818-32.016-14.006-86.328 31.32-124.282 7.584.285 8.519-1.378 50.072-59.914 52.483-1.382.056-2.142-1.355-1.268-2.354 7.828-8.929 15.732-31.535 4.367-43.586-24.338 21.81-38.472 30.017-85.138 19.186-29.878 31.241-46.809 74-43.485 127.265 6.78 108.735 108.63 170.89 211.193 164.49 102.556-6.395 193.466-80.572 186.683-189.307"/><path fill="#00912D" d="M291.375 132.293c21.075-5.023 81.693-.49 101.114 25.274 1.166 1.545-.475 4.468-2.355 3.648-32.016-14.006-86.328 31.32-124.282 7.584.285 8.519-1.378 50.072-59.914 52.483-1.382.056-2.142-1.355-1.268-2.354 7.828-8.929 15.73-31.535 4.367-43.586-26.512 23.758-40.884 31.392-98.426 15.838-1.883-.508-1.241-3.535.762-4.298 10.876-4.157 35.515-22.361 58.824-30.385 4.438-1.526 8.862-2.71 13.18-3.4-25.665-2.293-37.235-5.862-53.559-3.4-1.789.27-3.004-1.813-1.895-3.241 21.995-28.332 62.513-36.888 87.512-21.837-15.41-19.094-27.48-34.321-27.48-34.321l28.601-16.246s11.817 26.4 20.414 45.614c21.275-31.435 60.86-34.336 77.585-12.033.992 1.326-.045 3.21-1.702 3.171-13.612-.331-21.107 12.05-21.675 21.466l.197.023"/></g></svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
data/interfaces/default/images/rating/tomato-rotten.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="560" height="560"><path fill="#0AC855" d="M445.185 444.684c-79.369 4.167-95.587-86.652-126.726-86.006-13.268.279-23.726 14.151-19.133 30.32 2.525 8.888 9.53 21.923 13.944 30.011 15.57 28.544-7.447 60.845-34.383 63.577-44.76 4.54-63.433-21.426-62.278-48.007 1.3-29.84 26.6-60.331.65-73.305-27.194-13.597-49.301 39.572-75.325 51.439-23.553 10.741-56.248 2.413-67.872-23.741-8.164-18.379-6.68-53.768 29.67-67.27 22.706-8.433 73.305 11.029 75.9-13.623 2.992-28.416-53.155-30.812-70.06-37.626-29.912-12.055-47.567-37.85-33.734-65.522 10.378-20.757 40.915-29.203 64.223-20.11 27.922 10.892 32.404 39.853 46.71 51.897 12.324 10.38 29.19 11.68 40.22 4.543 8.135-5.265 10.843-16.828 7.774-27.39-4.07-14.023-14.875-22.773-25.415-31.346-18.758-15.249-45.24-28.36-29.222-69.983 13.13-34.11 51.642-35.34 51.642-35.34 15.3-1.72 29.002 2.9 40.167 12.875 14.927 13.335 17.834 31.16 15.336 50.176-2.283 17.358-8.426 32.56-11.63 49.759-3.717 19.966 6.954 40.086 27.249 40.869 26.694 1.031 34.698-19.486 37.964-32.492 4.782-19.028 11.058-36.694 28.718-47.82 25.346-15.97 60.552-12.47 76.886 18.222 12.92 24.284 8.772 57.715-11.047 75.97-8.892 8.188-19.584 11.075-31.148 11.156-16.585.117-33.162-.29-48.556 7.471-10.48 5.281-15.047 13.888-15.045 25.423 0 11.242 5.853 18.585 15.336 23.363 17.86 9.003 37.577 10.843 56.871 14.222 27.98 4.9 52.581 14.755 68.375 40.72.142.228.28.458.415.69 18.139 30.741-.831 75.005-36.476 76.878"/></svg>
|
After Width: | Height: | Size: 1.4 KiB |
@@ -24,17 +24,13 @@
|
||||
</div>
|
||||
<div id="currentActivity">
|
||||
% if PLEX_SERVER_UP:
|
||||
<div class="text-muted" id="dashboard-checking-activity"><i class="fa fa-refresh fa-spin"></i> Checking for activity...</div>
|
||||
<div class="text-muted" id="dashboard-checking-activity"><i class="fa fa-refresh fa-spin"></i> Checking for activity...</div>
|
||||
% elif config['pms_is_cloud']:
|
||||
<div id="dashboard-no-activity" class="text-muted">Plex Cloud server is sleeping.</div>
|
||||
% elif not config['first_run_complete']:
|
||||
<div id="dashboard-no-activity" class="text-muted">The Tautulli setup wizard has not been completed. Please click <a href="welcome">here</a> to go to the setup wizard.</div>
|
||||
% else:
|
||||
<div id="dashboard-no-activity" class="text-muted">There was an error communicating with your Plex Server.
|
||||
% if _session['user_group'] == 'admin':
|
||||
Check the <a href="logs">logs</a> and verify your server connection in the <a href="settings#tab_tabs-plex_media_server">settings</a>.
|
||||
% endif
|
||||
</div>
|
||||
<div class="text-muted" id="dashboard-checking-activity"><i class="fa fa-refresh fa-spin"></i> Tautulli is connecting to the Plex server...</div>
|
||||
% endif
|
||||
</div>
|
||||
</div>
|
||||
@@ -65,7 +61,7 @@
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div id="home-stats" class="home-platforms">
|
||||
<div class="text-muted"><i class="fa fa-refresh fa-spin"></i> Loading stats...</div>
|
||||
<div class="text-muted"><i class="fa fa-refresh fa-spin"></i> Loading stats...</div>
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
@@ -84,7 +80,7 @@
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div id="library-stats" class="library-platforms">
|
||||
<div class="text-muted"><i class="fa fa-refresh fa-spin"></i> Loading stats...</div>
|
||||
<div class="text-muted"><i class="fa fa-refresh fa-spin"></i> Loading stats...</div>
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
@@ -132,17 +128,12 @@
|
||||
<div class="col-md-12">
|
||||
<div id="recentlyAdded" style="margin-right: -15px;">
|
||||
% if PLEX_SERVER_UP:
|
||||
<div class="text-muted"><i class="fa fa-refresh fa-spin"></i> Looking for new items...</div>
|
||||
<div id="dashboard-checking-recently-added" class="text-muted"><i class="fa fa-refresh fa-spin"></i> Looking for new items...</div>
|
||||
% elif config['pms_is_cloud']:
|
||||
<div class="text-muted">Plex Cloud server is sleeping.</div>
|
||||
% else:
|
||||
<div class="text-muted">There was an error communicating with your Plex Server.
|
||||
% if _session['user_group'] == 'admin':
|
||||
Check the <a href="logs">logs</a> and verify your server connection in the <a href="settings#tab_tabs-plex_media_server">settings</a>.
|
||||
% endif
|
||||
</div>
|
||||
<div id="dashboard-no-recently-added" class="text-muted"><i class="fa fa-refresh fa-spin"></i> Tautulli is connecting to your Plex server...</div>
|
||||
% endif
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -179,10 +170,10 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
|
||||
<h4 class="modal-title">Terminate Session</h4>
|
||||
<h4 class="modal-title">Terminate Stream</h4>
|
||||
</div>
|
||||
<div class="modal-body" style="text-align: center;">
|
||||
<p>Are you sure you want to terminate this session?</p>
|
||||
<p>Are you sure you want to terminate this stream?</p>
|
||||
<p>
|
||||
<strong>
|
||||
<span id="terminate-user"></span><br />
|
||||
@@ -221,6 +212,28 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% from plexpy.helpers import anon_url %>
|
||||
<div id="python2-modal" class="modal fade wide" tabindex="-1" role="dialog" aria-labelledby="python2-modal">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
|
||||
<h4 class="modal-title">Unable to Update</h4>
|
||||
</div>
|
||||
<div class="modal-body" style="text-align: center;">
|
||||
<p>Tautulli is still running using Python 2 and cannot be updated past v2.6.3.</p>
|
||||
<p>Python 3 is required to continue receiving updates.</p>
|
||||
<p>
|
||||
<strong>Please see the <a href="${anon_url('https://github.com/Tautulli/Tautulli-Wiki/wiki/Upgrading-to-Python-3-%28Tautulli-v2.5%29')}" target="_blank" rel="noreferrer">wiki</a>
|
||||
for instructions on how to upgrade to Python 3.</strong>
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<input type="button" class="btn btn-bright" data-dismiss="modal" value="Close">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
% endif
|
||||
|
||||
<div class="modal fade" id="ip-info-modal" tabindex="-1" role="dialog" aria-labelledby="ip-info-modal">
|
||||
@@ -229,8 +242,6 @@
|
||||
</%def>
|
||||
|
||||
<%def name="javascriptIncludes()">
|
||||
<% from plexpy import PLEX_SERVER_UP %>
|
||||
<script src="${http_root}js/moment-with-locale.js"></script>
|
||||
<script src="${http_root}js/jquery.scrollbar.min.js"></script>
|
||||
<script src="${http_root}js/jquery.mousewheel.min.js"></script>
|
||||
<script>
|
||||
@@ -260,8 +271,33 @@
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
% if _session['user_group'] == 'admin':
|
||||
var msg_settings = ' Check the <a href="logs">logs</a> and verify your server connection in the <a href="settings#tab_tabs-plex_media_server">settings</a>.';
|
||||
% else:
|
||||
var msg_settings = '';
|
||||
% endif
|
||||
|
||||
var error_msg = 'There was an error communicating with your Plex Server.' + msg_settings;
|
||||
|
||||
var server_status;
|
||||
server_status = setInterval(function() {
|
||||
$.getJSON('server_status', function (data) {
|
||||
if (data.connected === true) {
|
||||
clearInterval(server_status);
|
||||
$('#currentActivity').html('<div id="dashboard-checking-activity" class="text-muted"><i class="fa fa-refresh fa-spin"></i> Checking for activity...</div>');
|
||||
$('#recentlyAdded').html('<div id="dashboard-checking-recently-added" class="text-muted"><i class="fa fa-refresh fa-spin"></i> Looking for new items...</div>');
|
||||
activityConnected();
|
||||
recentlyAddedConnected();
|
||||
} else if (data.connected === false) {
|
||||
clearInterval(server_status);
|
||||
$('#currentActivity').html('<div id="dashboard-no-activity" class="text-muted">' + error_msg + '</div>');
|
||||
$('#recentlyAdded').html('<div id="dashboard-no-recently-added" class="text-muted">' + error_msg + '</div>');
|
||||
}
|
||||
});
|
||||
}, 1000);
|
||||
</script>
|
||||
% if 'current_activity' in config['home_sections'] and PLEX_SERVER_UP:
|
||||
% if 'current_activity' in config['home_sections']:
|
||||
<script>
|
||||
var defaultHandler = {
|
||||
get: function(target, name) {
|
||||
@@ -272,7 +308,7 @@
|
||||
var create_instances = [];
|
||||
var activity_ready = true;
|
||||
|
||||
$('#currentActivityHeader-bandwidth-tooltip').tooltip({ container: 'body', placement: 'right', delay: 50 });
|
||||
$('#currentActivityHeader-bandwidth-tooltip').tooltip({ container: 'body', placement: 'right', delay: 50 });
|
||||
|
||||
function getCurrentActivity() {
|
||||
activity_ready = false;
|
||||
@@ -298,13 +334,8 @@
|
||||
}
|
||||
|
||||
if (!(current_activity)) {
|
||||
% if _session['user_group'] == 'admin':
|
||||
var msg_settings = ' Check the <a href="logs">logs</a> and verify your server connection in the <a href="settings#tab_tabs-plex_media_server">settings</a>.';
|
||||
% else:
|
||||
var msg_settings = '';
|
||||
% endif
|
||||
$('#currentActivityHeader').hide();
|
||||
$('#currentActivity').html('<div id="dashboard-no-activity" class="text-muted">There was an error communicating with your Plex Server.' + msg_settings + '</div>');
|
||||
$('#currentActivity').html('<div id="dashboard-no-activity" class="text-muted">' + error_msg + '</div>');
|
||||
return
|
||||
}
|
||||
|
||||
@@ -334,13 +365,13 @@
|
||||
streams_header = streams_header.replace(/, $/, '') + ')';
|
||||
$('#currentActivityHeader-streams').text(streams_header);
|
||||
|
||||
var bandwidth_header = ((total_bw > 1000) ? ((total_bw / 1000).toFixed(1) + ' Mbps') : (total_bw + ' kbps'));
|
||||
var bandwidth_header = ((total_bw > 1000000) ? ((total_bw / 1000000).toFixed(1) + ' Gbps') : ((total_bw > 1000) ? ((total_bw / 1000).toFixed(1) + ' Mbps') : (total_bw + ' kbps')));
|
||||
var lan_wan_bandwidth_header = '';
|
||||
if (lan_bw) {
|
||||
lan_wan_bandwidth_header += 'LAN: ' + ((lan_bw > 1000) ? ((lan_bw / 1000).toFixed(1) + ' Mbps') : (lan_bw + ' kbps')) + ', ';
|
||||
lan_wan_bandwidth_header += 'LAN: ' + ((lan_bw > 1000000) ? ((lan_bw / 1000000).toFixed(1) + ' Gbps') : ((lan_bw > 1000) ? ((lan_bw / 1000).toFixed(1) + ' Mbps') : (lan_bw + ' kbps'))) + ', ';
|
||||
}
|
||||
if (wan_bw) {
|
||||
lan_wan_bandwidth_header += 'WAN: ' + ((wan_bw > 1000) ? ((wan_bw / 1000).toFixed(1) + ' Mbps') : (wan_bw + ' kbps')) + ', ';
|
||||
lan_wan_bandwidth_header += 'WAN: ' + ((wan_bw > 1000000) ? ((wan_bw / 1000000).toFixed(1) + ' Gbps') : ((wan_bw > 1000) ? ((wan_bw / 1000).toFixed(1) + ' Mbps') : (wan_bw + ' kbps'))) + ', ';
|
||||
}
|
||||
if (lan_wan_bandwidth_header) {
|
||||
bandwidth_header += ' (' + lan_wan_bandwidth_header.replace(/, $/, '') + ')';
|
||||
@@ -355,8 +386,11 @@
|
||||
var session_id = s.session_id;
|
||||
var instance = $('#activity-instance-' + key);
|
||||
|
||||
// Create a new instance if it doesn't exist
|
||||
if (!(instance.length)) {
|
||||
// Create a new instance if it doesn't exist or recreate the entire instance
|
||||
// if the rating key changed (for movies or episodes) of guid changed (for live tv) with the same session key
|
||||
if (!(instance.length) ||
|
||||
(s.media_type !== 'track' && s.rating_key !== instance.data('rating_key').toString()) ||
|
||||
(s.live === 1 && s.guid !== instance.data('guid'))) {
|
||||
create_instances.push(key);
|
||||
getActivityInstance(key);
|
||||
return;
|
||||
@@ -374,6 +408,9 @@
|
||||
case 'buffering':
|
||||
state_icon = '<i class="fa fa-fw fa-spinner"></i> ';
|
||||
break;
|
||||
case 'error':
|
||||
state_icon = '<i class="fa fa-fw fa-exclamation-triangle"></i> ';
|
||||
break;
|
||||
default:
|
||||
state_icon = '<i class="fa fa-fw fa-question-circle"></i> ';
|
||||
}
|
||||
@@ -382,33 +419,33 @@
|
||||
// Switching tracks can be under the same session key, so need to update the info.
|
||||
if (s.media_type === 'track') {
|
||||
// Update if artist changed
|
||||
if (s.grandparent_rating_key !== instance.data('grandparent_rating_key')) {
|
||||
$('#background-' + key).css('background-image', 'url(pms_image_proxy?img=' + s.art + '&width=500&height=280&opacity=40&background=282828&blur=3&fallback=art&refresh=true)');
|
||||
if (s.grandparent_rating_key !== instance.data('grandparent_rating_key').toString()) {
|
||||
$('#background-' + key).css('background-image', 'url(' + page('pms_image_proxy', s.art, s.rating_key, 500, 280, 40, '282828', 3, 'art', true) + ')');
|
||||
$('#metadata-grandparent_title-' + key)
|
||||
.attr('href', 'info?rating_key=' + s.grandparent_rating_key)
|
||||
.attr('href', page('info', s.grandparent_rating_key))
|
||||
.attr('title', s.original_title || s.grandparent_title)
|
||||
.text(s.original_title || s.grandparent_title);
|
||||
}
|
||||
// Update cover if album changed
|
||||
if (s.parent_rating_key !== instance.data('parent_rating_key')) {
|
||||
$('#poster-' + key).css('background-image', 'url(pms_image_proxy?img=' + s.parent_thumb + '&width=300&height=300&fallback=poster&refresh=true)');
|
||||
$('#poster-' + key + '-bg').css('background-image', 'url(pms_image_proxy?img=' + s.parent_thumb + '&width=300&height=300&opacity=60&background=282828&blur=3&fallback=poster&refresh=true)');
|
||||
if (s.parent_rating_key !== instance.data('parent_rating_key').toString()) {
|
||||
$('#poster-' + key).css('background-image', 'url(' + page('pms_image_proxy', s.parent_thumb, s.parent_rating_key, 300, 300, null, null, null, 'poster', true) + ')');
|
||||
$('#poster-' + key + '-bg').css('background-image', 'url(' + page('pms_image_proxy', s.parent_thumb, s.parent_rating_key, 300, 300, 60, '282828', 3, 'poster', true) + ')');
|
||||
$('#poster-url-' + key)
|
||||
.attr('href', 'info?rating_key=' + s.parent_rating_key)
|
||||
.attr('href', page('info', s.parent_rating_key))
|
||||
.attr('title', s.parent_title);
|
||||
$('#metadata-parent_title-' + key)
|
||||
.attr('href', 'info?rating_key=' + s.parent_rating_key)
|
||||
.attr('href', page('info', s.parent_rating_key))
|
||||
.attr('title', s.parent_title)
|
||||
.text(s.parent_title);
|
||||
}
|
||||
// Update cover if track changed
|
||||
if (s.rating_key !== instance.data('rating_key')) {
|
||||
if (s.rating_key !== instance.data('rating_key').toString()) {
|
||||
$('#metadata-grandparent_title-' + key)
|
||||
.attr('href', 'info?rating_key=' + s.grandparent_rating_key)
|
||||
.attr('href', page('info', s.grandparent_rating_key))
|
||||
.attr('title', s.original_title || s.grandparent_title)
|
||||
.text(s.original_title || s.grandparent_title);
|
||||
$('#metadata-title-' + key)
|
||||
.attr('href', 'info?rating_key=' + s.rating_key)
|
||||
.attr('href', page('info', s.rating_key))
|
||||
.attr('title', s.title)
|
||||
.text(s.title);
|
||||
}
|
||||
@@ -428,7 +465,7 @@
|
||||
|
||||
var transcode_container = '';
|
||||
if (s.stream_container_decision === 'transcode') {
|
||||
transcode_container = 'Transcode (' + s.container.toUpperCase() + ' <i class="fa fa-long-arrow-right"></i> ' + s.stream_container.toUpperCase() + ')';
|
||||
transcode_container = 'Converting (' + s.container.toUpperCase() + ' <i class="fa fa-long-arrow-right"></i> ' + s.stream_container.toUpperCase() + ')';
|
||||
} else {
|
||||
transcode_container = 'Direct Play (' + s.stream_container.toUpperCase() + ')';
|
||||
}
|
||||
@@ -436,6 +473,8 @@
|
||||
|
||||
var video_decision = '';
|
||||
if (['movie', 'episode', 'clip'].indexOf(s.media_type) > -1 && s.stream_video_decision) {
|
||||
var v_bd = (s.video_dynamic_range === 'HDR') ? ' ' + s.video_dynamic_range : '';
|
||||
var sv_bd = (s.video_dynamic_range === 'HDR') ? ' ' + s.stream_video_dynamic_range : '';
|
||||
var v_res= '';
|
||||
switch (s.video_resolution.toLowerCase()) {
|
||||
case 'sd':
|
||||
@@ -445,7 +484,7 @@
|
||||
v_res = '4k';
|
||||
break;
|
||||
default:
|
||||
v_res = s.video_resolution + 'p'
|
||||
v_res = s.video_full_resolution;
|
||||
}
|
||||
var sv_res = '';
|
||||
switch (s.stream_video_resolution.toLowerCase()) {
|
||||
@@ -456,16 +495,16 @@
|
||||
sv_res = '4k';
|
||||
break;
|
||||
default:
|
||||
sv_res = s.stream_video_resolution + 'p'
|
||||
sv_res = s.stream_video_full_resolution;
|
||||
}
|
||||
if (s.stream_video_decision === 'transcode') {
|
||||
var hw_d = (s.transcode_hw_decoding === 1) ? ' (HW)' : '';
|
||||
var hw_e = (s.transcode_hw_encoding === 1) ? ' (HW)' : '';
|
||||
video_decision = 'Transcode (' + s.video_codec.toUpperCase() + hw_d + ' ' + v_res + ' <i class="fa fa-long-arrow-right"></i> ' + s.stream_video_codec.toUpperCase() + hw_e + ' ' + sv_res + ')';
|
||||
video_decision = 'Transcode (' + s.video_codec.toUpperCase() + hw_d + ' ' + v_res + v_bd + ' <i class="fa fa-long-arrow-right"></i> ' + s.stream_video_codec.toUpperCase() + hw_e + ' ' + sv_res + sv_bd + ')';
|
||||
} else if (s.stream_video_decision === 'copy') {
|
||||
video_decision = 'Direct Stream (' + s.stream_video_codec.toUpperCase() + ' ' + sv_res + ')';
|
||||
video_decision = 'Direct Stream (' + s.stream_video_codec.toUpperCase() + ' ' + sv_res + sv_bd + ')';
|
||||
} else {
|
||||
video_decision = 'Direct Play (' + s.stream_video_codec.toUpperCase() + ' ' + sv_res + ')';
|
||||
video_decision = 'Direct Play (' + s.stream_video_codec.toUpperCase() + ' ' + sv_res + sv_bd + ')';
|
||||
}
|
||||
} else if (s.media_type === 'photo') {
|
||||
video_decision = 'Direct Play (' + s.width + 'x' + s.height + ')';
|
||||
@@ -488,14 +527,15 @@
|
||||
|
||||
var subtitle_decision = 'None';
|
||||
if (['movie', 'episode', 'clip'].indexOf(s.media_type) > -1 && s.subtitles === 1) {
|
||||
var subtitle_codec = (s.stream_subtitle_codec && s.stream_subtitle_transient) ? 'None' : s.subtitle_codec.toUpperCase();
|
||||
if (s.stream_subtitle_decision === 'transcode') {
|
||||
subtitle_decision = 'Transcode (' + s.subtitle_codec.toUpperCase() + ' <i class="fa fa-long-arrow-right"></i> ' + s.stream_subtitle_codec.toUpperCase() + ')';
|
||||
subtitle_decision = 'Transcode (' + subtitle_codec + ' <i class="fa fa-long-arrow-right"></i> ' + s.stream_subtitle_codec.toUpperCase() + ')';
|
||||
} else if (s.stream_subtitle_decision === 'copy') {
|
||||
subtitle_decision = 'Direct Stream (' + s.subtitle_codec.toUpperCase() + ')';
|
||||
subtitle_decision = 'Direct Stream (' + subtitle_codec + ')';
|
||||
} else if (s.stream_subtitle_decision === 'burn') {
|
||||
subtitle_decision = 'Burn (' + s.subtitle_codec.toUpperCase() + ')';
|
||||
subtitle_decision = 'Burn (' + subtitle_codec + ')';
|
||||
} else {
|
||||
subtitle_decision = 'Direct Play (' + ((s.synced_version === '1') ? s.subtitle_codec.toUpperCase() : s.stream_subtitle_codec.toUpperCase()) + ')';
|
||||
subtitle_decision = 'Direct Play (' + ((s.synced_version === '1') ? subtitle_codec : s.stream_subtitle_codec.toUpperCase()) + ')';
|
||||
}
|
||||
}
|
||||
$('#subtitle_decision-' + key).html(subtitle_decision);
|
||||
@@ -521,7 +561,9 @@
|
||||
|
||||
if (s.media_type !== 'photo' && s.bandwidth !== 'Unknown') {
|
||||
var bw = parseInt(s.bandwidth) || 0;
|
||||
if (bw > 1000) {
|
||||
if (bw > 1000000) {
|
||||
bw = (bw / 1000000).toFixed(1) + ' Gbps';
|
||||
} else if (bw > 1000) {
|
||||
bw = (bw / 1000).toFixed(1) + ' Mbps';
|
||||
} else {
|
||||
bw = bw + ' kbps'
|
||||
@@ -538,12 +580,14 @@
|
||||
}
|
||||
|
||||
// Update the progress bars, percent - 3 because of 3px padding-right
|
||||
$('#buffer-bar-' + key).width(parseInt(s.transcode_progress) - 3 + '%').html(s.transcode_progress + '%')
|
||||
$('#buffer-bar-' + key).css({width: parseInt(s.transcode_progress) - 3 + '%'}).html(s.transcode_progress + '%')
|
||||
.attr('data-original-title', 'Transcoder Progress ' + s.transcode_progress + '%');
|
||||
var progress_bar = $('#progress-bar-' + key);
|
||||
progress_bar.data('state', s.state);
|
||||
if (progress_bar.data('last_view_offset') !== s.view_offset) {
|
||||
progress_bar.data('last_view_offset', s.view_offset).data('view_offset', s.view_offset);
|
||||
if (s.live !== 1) {
|
||||
var progress_bar = $('#progress-bar-' + key);
|
||||
progress_bar.data('state', s.state);
|
||||
if (progress_bar.data('last_view_offset') !== s.view_offset) {
|
||||
progress_bar.data('last_view_offset', s.view_offset).data('view_offset', s.view_offset);
|
||||
}
|
||||
}
|
||||
|
||||
// Add temporary class so we know which instances are still active
|
||||
@@ -556,6 +600,7 @@
|
||||
$(instance).removeClass('updated-temp');
|
||||
} else {
|
||||
$(instance).find('[data-toggle=tooltip]').tooltip('destroy');
|
||||
$(instance).find('[data-toggle=popover]').popover('destroy');
|
||||
$(instance).remove();
|
||||
}
|
||||
});
|
||||
@@ -580,9 +625,27 @@
|
||||
session_key: session_key
|
||||
},
|
||||
complete: function(xhr, status) {
|
||||
$('#currentActivity').append(xhr.responseText);
|
||||
var instance = $('#activity-instance-' + session_key);
|
||||
|
||||
if (instance.length) {
|
||||
instance.replaceWith(xhr.responseText);
|
||||
} else {
|
||||
$('#currentActivity').append(xhr.responseText);
|
||||
}
|
||||
|
||||
$('#activity-instance-' + session_key + ' .dashboard-activity-info-scroller').scrollbar();
|
||||
$('#activity-instance-' + session_key + ' [data-toggle=tooltip]').tooltip({ container: 'body', placement: 'right', delay: 50 });
|
||||
$('#activity-instance-' + session_key + ' [data-toggle=popover]').popover({
|
||||
html: true,
|
||||
container: 'body',
|
||||
trigger: 'hover',
|
||||
placement: 'right',
|
||||
delay: 50,
|
||||
template: '<div class="popover channel-thumbnail-popover" role="tooltip"><div class="arrow" style="top: 50%;"></div><div class="popover-content"></div></div>',
|
||||
content: function () {
|
||||
return '<div class="channel-thumbnail" style="background-image: url(' + $(this).data('img') + ');" />';
|
||||
}
|
||||
});
|
||||
$('#terminate-button-' + session_key).tooltip('destroy').tooltip({ container: 'body', placement: 'left', delay: 50 });
|
||||
lockScroll('#activity-instance-' + session_key + ' .dashboard-activity-info-scroller');
|
||||
|
||||
@@ -594,34 +657,36 @@
|
||||
});
|
||||
}
|
||||
|
||||
getCurrentActivity();
|
||||
setInterval(function () {
|
||||
if (!(create_instances.length) && activity_ready) {
|
||||
getCurrentActivity();
|
||||
}
|
||||
}, ${config['home_refresh_interval'] * 1000});
|
||||
function activityConnected() {
|
||||
getCurrentActivity();
|
||||
setInterval(function () {
|
||||
if (!(create_instances.length) && activity_ready) {
|
||||
getCurrentActivity();
|
||||
}
|
||||
}, ${config['home_refresh_interval'] * 1000});
|
||||
|
||||
setInterval(function(){
|
||||
$('.progress_time_offset').each(function () {
|
||||
if ($(this).data('state') === 'playing' && $(this).data('view_offset') >= 0) {
|
||||
var view_offset = parseInt($(this).data('view_offset'));
|
||||
var stream_duration = parseInt($(this).data('stream_duration'));
|
||||
var timestamp = millisecondsToMinutes(Math.min(view_offset, stream_duration), false);
|
||||
$(this).html(timestamp).data('view_offset', Math.min(view_offset + 1000, stream_duration))
|
||||
}
|
||||
});
|
||||
$('.progress-bar').each(function () {
|
||||
if ($(this).data('state') === 'playing' && $(this).data('view_offset') >= 0) {
|
||||
var view_offset = parseInt($(this).data('view_offset'));
|
||||
var stream_duration = parseInt($(this).data('stream_duration'));
|
||||
var progress_percent = Math.floor(view_offset / stream_duration * 100);
|
||||
progress_percent = (progress_percent >= 0) ? Math.min(progress_percent, 100) : 100;
|
||||
$(this).width(progress_percent - 3 + '%').html(progress_percent + '%')
|
||||
.attr('data-original-title', 'Stream Progress ' + progress_percent + '%')
|
||||
.data('view_offset', Math.min(view_offset + 1000, stream_duration));
|
||||
}
|
||||
});
|
||||
}, 1000);
|
||||
setInterval(function(){
|
||||
$('.progress_time_offset').each(function () {
|
||||
if ($(this).data('state') === 'playing' && $(this).data('view_offset') >= 0) {
|
||||
var view_offset = parseInt($(this).data('view_offset'));
|
||||
var stream_duration = parseInt($(this).data('stream_duration'));
|
||||
var timestamp = millisecondsToMinutes(Math.min(view_offset, stream_duration), false);
|
||||
$(this).html(timestamp).data('view_offset', Math.min(view_offset + 1000, stream_duration))
|
||||
}
|
||||
});
|
||||
$('.progress-bar').each(function () {
|
||||
if ($(this).data('state') === 'playing' && $(this).data('view_offset') >= 0) {
|
||||
var view_offset = parseInt($(this).data('view_offset'));
|
||||
var stream_duration = parseInt($(this).data('stream_duration'));
|
||||
var progress_percent = Math.floor(view_offset / stream_duration * 100);
|
||||
progress_percent = (progress_percent >= 0) ? Math.min(progress_percent, 100) : 100;
|
||||
$(this).css({width: progress_percent - 3 + '%'}).html(progress_percent + '%')
|
||||
.attr('data-original-title', 'Stream Progress ' + progress_percent + '%')
|
||||
.data('view_offset', Math.min(view_offset + 1000, stream_duration));
|
||||
}
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
$('#currentActivity').on('click', '.external_ip-modal', function () {
|
||||
$.get('get_ip_address_details', {
|
||||
@@ -698,6 +763,88 @@
|
||||
% endif
|
||||
</script>
|
||||
% endif
|
||||
% if 'watch_stats' in config['home_sections'] or 'library_stats' in config['home_sections']:
|
||||
<script>
|
||||
function statsCardCallback() {
|
||||
$('.dashboard-stats-instance .dashboard-stats-info-scroller').scrollbar();
|
||||
|
||||
function changeImages(elem) {
|
||||
var stat_id = $(elem).data('stat_id');
|
||||
var art = $(elem).data('art');
|
||||
var thumb = $(elem).data('thumb');
|
||||
var user_id = $(elem).data('user_id');
|
||||
var user_thumb = $(elem).data('user_thumb');
|
||||
var rating_key = $(elem).data('rating_key');
|
||||
var guid = $(elem).data('guid');
|
||||
var live = $(elem).data('live');
|
||||
var [height, fallback_poster, fallback_art] = [450, 'poster', 'art'];
|
||||
if ($.inArray(stat_id, ['top_music', 'popular_music']) > -1) {
|
||||
[height, fallback_poster, fallback_art] = [300, 'cover', 'art'];
|
||||
} else if (live) {
|
||||
[height, fallback_poster, fallback_art] = [450, 'poster-live', 'art-live'];
|
||||
}
|
||||
var href = '#';
|
||||
|
||||
if (stat_id === 'most_concurrent') {
|
||||
return
|
||||
} else if (stat_id === 'top_users') {
|
||||
$('#stats-thumb-' + stat_id).css('background-image', 'url(' + (user_thumb || 'images/gravatar-default.png') + ')');
|
||||
if (user_id) {
|
||||
href = page('user', user_id);
|
||||
}
|
||||
$('#stats-thumb-url-' + stat_id).attr('href', href).prop('title', $(elem).data('user'));
|
||||
} else if (stat_id === 'top_platforms') {
|
||||
$('#stats-thumb-' + stat_id).removeClass(function (index, className) {
|
||||
return (className.match (/(^|\s)platform-\S+/g) || []).join(' ');
|
||||
}).addClass('platform-' + $(elem).data('platform'));
|
||||
$('#stats-background-' + stat_id).removeClass(function (index, className) {
|
||||
return (className.match (/(^|\s)platform-\S+/g) || []).join(' ');
|
||||
}).addClass('platform-' + $(elem).data('platform') + '-rgba');
|
||||
} else {
|
||||
if (rating_key) {
|
||||
if (live) {
|
||||
href = page('info', rating_key, guid, true, live);
|
||||
} else {
|
||||
href = page('info', rating_key);
|
||||
}
|
||||
}
|
||||
$('#stats-thumb-url-' + stat_id).attr('href', href).prop('title', $(elem).data('title'));
|
||||
$('#stats-background-' + stat_id).css('background-image', 'url(' + page('pms_image_proxy', art, rating_key, 500, 280, 40, '282828', 3, fallback_art) + ')');
|
||||
$('#stats-thumb-' + stat_id).css('background-image', 'url(' + page('pms_image_proxy', thumb, rating_key, 300, height, null, null, null, fallback_poster) + ')');
|
||||
$('#stats-thumb-' + stat_id + '-bg').css('background-image', 'url(' + page('pms_image_proxy', thumb, rating_key, 300, height, 60, '282828', 3, fallback_poster) + ')');
|
||||
$('#library-stats-background-' + stat_id).css('background-image', 'url(' + page('pms_image_proxy', art, rating_key, 500, 280, 40, '282828', 3, fallback_art) + ')');
|
||||
if (thumb.startsWith('http')) {
|
||||
$('#library-stats-thumb-' + stat_id).css('background-image', 'url(' + page('pms_image_proxy', thumb, rating_key, 300, 300, null, null, null, 'cover') + ')')
|
||||
.removeClass('svg-icon library-' + stat_id);
|
||||
} else {
|
||||
$('#library-stats-thumb-' + stat_id).css('background-image', '')
|
||||
.addClass('svg-icon library-' + stat_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$('.dashboard-stats-info-item').mouseenter(function () {
|
||||
changeImages(this);
|
||||
if ($(this).data('stat_id') === 'last_watched') {
|
||||
var friendly_name = $(this).data('friendly_name');
|
||||
var last_watch = moment($(this).data('last_watch'), 'X').format(date_format);
|
||||
$('#last-watched-header-info').html(friendly_name);
|
||||
} else if ($(this).data('stat_id') === 'most_concurrent') {
|
||||
var started = moment($(this).data('started'), 'X').format(date_format + ' ' + time_format);
|
||||
$('#most-concurrent-header-info').html(started);
|
||||
}
|
||||
});
|
||||
$('.dashboard-stats-instance').mouseleave(function () {
|
||||
changeImages($(this).find('.dashboard-stats-info-item').first());
|
||||
if ($(this).data('stat_id') === 'last_watched') {
|
||||
$('#last-watched-header-info').text($(this).find('.dashboard-stats-info-item').first().data('friendly_name'));
|
||||
} else if ($(this).data('stat_id') === 'most_concurrent') {
|
||||
$('#most-concurrent-header-info').text('streams');
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
% endif
|
||||
% if 'watch_stats' in config['home_sections']:
|
||||
<script>
|
||||
function getHomeStats(time_range, stats_type) {
|
||||
@@ -716,6 +863,7 @@
|
||||
$("#home-stats").html(xhr.responseText);
|
||||
$('#ajaxMsg').fadeOut();
|
||||
lockScroll('#home-stats .dashboard-stats-info-scroller');
|
||||
statsCardCallback();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -755,13 +903,14 @@
|
||||
data: { },
|
||||
complete: function (xhr, status) {
|
||||
$("#library-stats").html(xhr.responseText);
|
||||
statsCardCallback();
|
||||
}
|
||||
});
|
||||
}
|
||||
getLibraryStats();
|
||||
</script>
|
||||
% endif
|
||||
% if 'recently_added' in config['home_sections'] and PLEX_SERVER_UP:
|
||||
% if 'recently_added' in config['home_sections']:
|
||||
<script>
|
||||
function recentlyAdded(recently_added_count, recently_added_type) {
|
||||
showMsg("Loading recently added items...", true, false, 0);
|
||||
@@ -789,7 +938,9 @@
|
||||
$('#recently-added-toggle-' + recently_added_type).closest('label').addClass('active');
|
||||
$('#recently-added-count').val(recently_added_count);
|
||||
|
||||
recentlyAdded(recently_added_count, recently_added_type);
|
||||
function recentlyAddedConnected() {
|
||||
recentlyAdded(recently_added_count, recently_added_type);
|
||||
}
|
||||
|
||||
function highlightAddedScrollerButton() {
|
||||
var scroller = $("#recently-added-row-scroller");
|
||||
@@ -873,9 +1024,24 @@
|
||||
async: true,
|
||||
complete: function (xhr, status) {
|
||||
$("#changelog-modal .modal-body").html(xhr.responseText);
|
||||
$('#changelog-modal').modal();
|
||||
$('#changelog-modal').modal({
|
||||
backdrop: 'static',
|
||||
keyboard: false
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
% endif
|
||||
% if _session['user_group'] == 'admin':
|
||||
<script>
|
||||
const queryString = window.location.search;
|
||||
const urlParams = new URLSearchParams(queryString);
|
||||
if (urlParams.get('update') === 'python2') {
|
||||
$("#python2-modal").modal({
|
||||
backdrop: 'static',
|
||||
keyboard: false
|
||||
});
|
||||
}
|
||||
</script>
|
||||
% endif
|
||||
</%def>
|
@@ -36,25 +36,34 @@ DOCUMENTATION :: END
|
||||
</%doc>
|
||||
|
||||
<%!
|
||||
from collections import defaultdict
|
||||
import re
|
||||
|
||||
from plexpy import notifiers
|
||||
from plexpy.common import MEDIA_TYPE_HEADERS, MEDIA_FLAGS_AUDIO, MEDIA_FLAGS_VIDEO
|
||||
from plexpy.helpers import page, get_percent, cast_to_int
|
||||
|
||||
# Get audio codec file
|
||||
def af(codec):
|
||||
for pattern, file_type in MEDIA_FLAGS_AUDIO.iteritems():
|
||||
for pattern, file_type in MEDIA_FLAGS_AUDIO.items():
|
||||
if re.match(pattern, codec):
|
||||
return file_type
|
||||
return codec
|
||||
|
||||
# Get audio codec file
|
||||
# Get video codec file
|
||||
def vf(codec):
|
||||
for pattern, file_type in MEDIA_FLAGS_VIDEO.iteritems():
|
||||
for pattern, file_type in MEDIA_FLAGS_VIDEO.items():
|
||||
if re.match(pattern, codec):
|
||||
return file_type
|
||||
return codec
|
||||
|
||||
# Get video resolution file
|
||||
def vr(resolution):
|
||||
if resolution in ('1080i', '576i', '480i'):
|
||||
return resolution
|
||||
else:
|
||||
return resolution.lower().rstrip('ip')
|
||||
|
||||
def br(text):
|
||||
return text.replace('\n', '<br /><br />')
|
||||
%>
|
||||
@@ -68,11 +77,17 @@ DOCUMENTATION :: END
|
||||
</%def>
|
||||
|
||||
<%def name="body()">
|
||||
% if data:
|
||||
<% media_info = data['media_info'][0] if data['media_info'] else {} %>
|
||||
% if metadata:
|
||||
<%
|
||||
data = defaultdict(lambda: None, **metadata)
|
||||
media_info = defaultdict(lambda: None, **(data['media_info'][0] if data['media_info'] else {}))
|
||||
%>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="art-face" style="background-image:url(pms_image_proxy?img=${data['art']}&width=1920&height=1080)"></div>
|
||||
% if data['media_type'] not in ('photo_album', 'photo', 'playlist'):
|
||||
<% fallback = 'art-live-full' if data['live'] else None %>
|
||||
<div class="art-face" style="background-image:url(${page('pms_image_proxy', data['art'], data['rating_key'], 1920, 1080, fallback=fallback)})"></div>
|
||||
% endif
|
||||
% if _session['user_group'] == 'admin':
|
||||
<span class="overlay-refresh-image info-art" title="Refresh background image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||
% endif
|
||||
@@ -81,46 +96,85 @@ DOCUMENTATION :: END
|
||||
<div class="col-md-12">
|
||||
<div class="summary-navbar-list">
|
||||
<ul class="list-unstyled breadcrumb">
|
||||
% if data['media_type'] in ('movie', 'collection'):
|
||||
<li><a href="library?section_id=${data['section_id']}">${data['library_name']}</a></li>
|
||||
% if data['live']:
|
||||
<li><a href="${page('library', data['section_id'])}">${data['library_name']}</a></li>
|
||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||
% if data['media_type'] == 'movie':
|
||||
<li class="active metadata-xml">${data['title']}</li>
|
||||
% elif data['media_type'] == 'episode':
|
||||
<li class="hidden-xs hidden-sm">${data['grandparent_title']}</li>
|
||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||
% if data['media_index']:
|
||||
<li>Season ${data['parent_media_index']}</li>
|
||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||
<li class="active metadata-xml">Episode ${data['media_index']} - ${data['title']}</li>
|
||||
% else:
|
||||
<li class="active metadata-xml">${data['title']}</li>
|
||||
% endif
|
||||
% endif
|
||||
% elif data['media_type'] in ('movie', 'collection'):
|
||||
<li><a href="${page('library', data['section_id'])}">${data['library_name']}</a></li>
|
||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||
<li class="active metadata-xml">${data['title']}</li>
|
||||
% elif data['media_type'] == 'show':
|
||||
<li><a href="library?section_id=${data['section_id']}">${data['library_name']}</a></li>
|
||||
<li><a href="${page('library', data['section_id'])}">${data['library_name']}</a></li>
|
||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||
<li class="active metadata-xml">${data['title']}</li>
|
||||
% elif data['media_type'] == 'season':
|
||||
<li class="hidden-xs hidden-sm"><a href="library?section_id=${data['section_id']}">${data['library_name']}</a></li>
|
||||
<li class="hidden-xs hidden-sm"><a href="${page('library', data['section_id'])}">${data['library_name']}</a></li>
|
||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||
<li><a href="info?rating_key=${data['parent_rating_key']}">${data['parent_title']}</a></li>
|
||||
<li><a href="${page('info', data['parent_rating_key'])}">${data['parent_title']}</a></li>
|
||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||
<li class="active metadata-xml">Season ${data['media_index']}</li>
|
||||
% elif data['media_type'] == 'episode':
|
||||
<li class="hidden-xs hidden-sm"><a href="library?section_id=${data['section_id']}">${data['library_name']}</a></li>
|
||||
<li class="hidden-xs hidden-sm"><a href="${page('library', data['section_id'])}">${data['library_name']}</a></li>
|
||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||
<li class="hidden-xs hidden-sm"><a href="info?rating_key=${data['grandparent_rating_key']}">${data['grandparent_title']}</a></li>
|
||||
<li class="hidden-xs hidden-sm"><a href="${page('info', data['grandparent_rating_key'])}">${data['grandparent_title']}</a></li>
|
||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||
<li><a href="info?rating_key=${data['parent_rating_key']}">Season ${data['parent_media_index']}</a></li>
|
||||
<li><a href="${page('info', data['parent_rating_key'])}">Season ${data['parent_media_index']}</a></li>
|
||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||
<li class="active metadata-xml">Episode ${data['media_index']} - ${data['title']}</li>
|
||||
% elif data['media_type'] == 'artist':
|
||||
<li><a href="library?section_id=${data['section_id']}">${data['library_name']}</a></li>
|
||||
<li><a href="${page('library', data['section_id'])}">${data['library_name']}</a></li>
|
||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||
<li class="active metadata-xml">${data['title']}</li>
|
||||
% elif data['media_type'] == 'album':
|
||||
<li class="hidden-xs hidden-sm"><a href="library?section_id=${data['section_id']}">${data['library_name']}</a></li>
|
||||
<li class="hidden-xs hidden-sm"><a href="${page('library', data['section_id'])}">${data['library_name']}</a></li>
|
||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||
<li><a href="info?rating_key=${data['parent_rating_key']}">${data['parent_title']}</a></li>
|
||||
<li><a href="${page('info', data['parent_rating_key'])}">${data['parent_title']}</a></li>
|
||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||
<li class="active metadata-xml">${data['title']}</li>
|
||||
% elif data['media_type'] == 'track':
|
||||
<li class="hidden-xs hidden-sm"><a href="library?section_id=${data['section_id']}">${data['library_name']}</a></li>
|
||||
<li class="hidden-xs hidden-sm"><a href="${page('library', data['section_id'])}">${data['library_name']}</a></li>
|
||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||
<li class="hidden-xs hidden-sm"><a href="info?rating_key=${data['grandparent_rating_key']}">${data['grandparent_title']}</a></li>
|
||||
<li class="hidden-xs hidden-sm"><a href="${page('info', data['grandparent_rating_key'])}">${data['grandparent_title']}</a></li>
|
||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||
<li><a href="info?rating_key=${data['parent_rating_key']}">${data['parent_title']}</a></li>
|
||||
<li><a href="${page('info', data['parent_rating_key'])}">${data['parent_title']}</a></li>
|
||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||
<li class="active metadata-xml">Track ${data['media_index']} - ${data['title']}</li>
|
||||
% elif data['media_type'] == 'photo_album':
|
||||
<li><a href="${page('library', data['section_id'])}">${data['library_name']}</a></li>
|
||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||
% if data['parent_title']:
|
||||
<li><a href="${page('info', data['parent_rating_key'])}">${data['parent_title']}</a></li>
|
||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||
% endif
|
||||
<li class="active metadata-xml">${data['title']}</li>
|
||||
% elif data['media_type'] in ('photo', 'clip'):
|
||||
<li class="hidden-xs hidden-sm"><a href="${page('library', data['section_id'])}">${data['library_name']}</a></li>
|
||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||
<li><a href="${page('info', data['parent_rating_key'])}">${data['parent_title']}</a></li>
|
||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||
<li class="active metadata-xml">${data['title']}</li>
|
||||
% elif data['media_type'] == 'playlist':
|
||||
% if user_info.get('user_id'):
|
||||
<li><a href="${page('user', user_info.get('user_id'))}">${user_info.get('friendly_name')}</a></li>
|
||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||
% elif data['section_id']:
|
||||
<li><a href="${page('library', data['section_id'])}">${data['library_name']}</a></li>
|
||||
<span class="breadcrumb-arrow"><i class="fa fa-chevron-right"></i></span>
|
||||
% endif
|
||||
<li class="active metadata-xml">${data['title']}</li>
|
||||
% endif
|
||||
</ul>
|
||||
</div>
|
||||
@@ -129,13 +183,23 @@ DOCUMENTATION :: END
|
||||
<div class="summary-content-title-wrapper">
|
||||
<div class="col-md-9">
|
||||
<div class="summary-content-poster hidden-xs hidden-sm">
|
||||
% if data['media_type'] == 'track':
|
||||
<a href="${config['pms_web_url']}#!/server/${config['pms_identifier']}/details?key=%2Flibrary%2Fmetadata%2F${data['parent_rating_key']}" target="_blank" title="View on Plex Web">
|
||||
% else:
|
||||
<a href="${config['pms_web_url']}#!/server/${config['pms_identifier']}/details?key=%2Flibrary%2Fmetadata%2F${data['rating_key']}" target="_blank" title="View on Plex Web">
|
||||
<% legacy = '&legacy=1' if data['media_type'] in ('photo_album', 'photo', 'clip') else '' %>
|
||||
% if data['media_type'] in ('track', 'photo'):
|
||||
<a href="${config['pms_web_url']}#!/server/${config['pms_identifier']}/details?key=%2Flibrary%2Fmetadata%2F${data['parent_rating_key']}${legacy}" target="_blank" rel="noreferrer" title="View on Plex Web">
|
||||
% elif data['media_type'] == 'playlist':
|
||||
<a href="${config['pms_web_url']}#!/server/${config['pms_identifier']}/playlist?key=%2Fplaylists%2F${data['rating_key']}" target="_blank" rel="noreferrer" title="View on Plex Web">
|
||||
% elif not data['live']:
|
||||
<a href="${config['pms_web_url']}#!/server/${config['pms_identifier']}/details?key=%2Flibrary%2Fmetadata%2F${data['rating_key']}${legacy}" target="_blank" rel="noreferrer" title="View on Plex Web">
|
||||
% endif
|
||||
% if data['live']:
|
||||
<div class="summary-poster-face" style="background-image: url(${page('pms_image_proxy', data['grandparent_thumb'] or data['thumb'], data['rating_key'], 300, 450, fallback='poster-live')});">
|
||||
<div class="summary-poster-face-overlay">
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
% else:
|
||||
% if data['media_type'] == 'episode':
|
||||
<div class="summary-poster-face-episode" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=500&height=280&fallback=art);">
|
||||
<div class="summary-poster-face-episode" style="background-image: url(${page('pms_image_proxy', data['thumb'], data['rating_key'], 500, 280, fallback='art')});">
|
||||
<div class="summary-poster-face-overlay">
|
||||
<span></span>
|
||||
</div>
|
||||
@@ -143,17 +207,20 @@ DOCUMENTATION :: END
|
||||
% if _session['user_group'] == 'admin':
|
||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||
% endif
|
||||
% elif data['media_type'] == 'artist' or data['media_type'] == 'album' or data['media_type'] == 'track':
|
||||
<div class="summary-poster-face-track" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=500&height=500&fallback=cover);">
|
||||
% elif data['media_type'] in ('artist', 'album', 'track', 'playlist', 'photo_album', 'photo', 'clip'):
|
||||
<div class="summary-poster-face-track" style="background-image: url(${page('pms_image_proxy', data['thumb'], data['rating_key'], 500, 500, fallback='cover')});">
|
||||
<div class="summary-poster-face-overlay">
|
||||
<span></span>
|
||||
</div>
|
||||
% if data['media_type'] == 'playlist' and data['smart']:
|
||||
<span class="smart-playlist-image" title="Smart Playlist"><i class="fa fa-cog"></i></span>
|
||||
% endif
|
||||
</div>
|
||||
% if _session['user_group'] == 'admin':
|
||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||
% endif
|
||||
% else:
|
||||
<div class="summary-poster-face" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=300&height=450&fallback=poster);">
|
||||
<div class="summary-poster-face" style="background-image: url(${page('pms_image_proxy', data['thumb'], data['rating_key'], 300, 450, fallback='poster')});">
|
||||
<div class="summary-poster-face-overlay">
|
||||
<span></span>
|
||||
</div>
|
||||
@@ -162,51 +229,68 @@ DOCUMENTATION :: END
|
||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||
% endif
|
||||
% endif
|
||||
% endif
|
||||
% if not data['live']:
|
||||
</a>
|
||||
% endif
|
||||
</div>
|
||||
<div class="summary-content-title">
|
||||
% if data['media_type'] in ('movie', 'show', 'artist', 'collection'):
|
||||
% if data['live']:
|
||||
% if data['media_type'] == 'movie':
|
||||
<h1> </h1><h1>${data['title']}</h1>
|
||||
% elif data['media_type'] == 'episode':
|
||||
<h1>${data['grandparent_title']}</h1>
|
||||
<h2>${data['title']}</h2>
|
||||
% if data['media_index']:
|
||||
<h3 class="hidden-xs">S${data['parent_media_index']} · E${data['media_index']}</h3>
|
||||
% endif
|
||||
% endif
|
||||
% elif data['media_type'] in ('movie', 'show', 'artist', 'collection', 'playlist', 'photo_album'):
|
||||
<h1> </h1><h1>${data['title']}</h1>
|
||||
% elif data['media_type'] == 'season':
|
||||
<h1> </h1><h1><a href="info?rating_key=${data['parent_rating_key']}">${data['parent_title']}</a></h1>
|
||||
<h1> </h1><h1><a href="${page('info', data['parent_rating_key'])}">${data['parent_title']}</a></h1>
|
||||
<h3 class="hidden-xs">S${data['media_index']}</h3>
|
||||
% elif data['media_type'] == 'episode':
|
||||
<h1><a href="info?rating_key=${data['grandparent_rating_key']}">${data['grandparent_title']}</a></h1>
|
||||
<h1><a href="${page('info', data['grandparent_rating_key'])}">${data['grandparent_title']}</a></h1>
|
||||
<h2>${data['title']}</h2>
|
||||
<h3 class="hidden-xs">S${data['parent_media_index']} · E${data['media_index']}</h3>
|
||||
% elif data['media_type'] == 'album':
|
||||
<h1><a href="info?rating_key=${data['parent_rating_key']}">${data['parent_title']}</a></h1>
|
||||
<h1><a href="${page('info', data['parent_rating_key'])}">${data['parent_title']}</a></h1>
|
||||
<h2>${data['title']}</h2>
|
||||
% elif data['media_type'] == 'track':
|
||||
<h1><a href="info?rating_key=${data['grandparent_rating_key']}">${data['original_title'] or data['grandparent_title']}</a></h1>
|
||||
<h2><a href="info?rating_key=${data['parent_rating_key']}">${data['parent_title']}</a> - ${data['title']}</h2>
|
||||
<h1><a href="${page('info', data['grandparent_rating_key'])}">${data['original_title'] or data['grandparent_title']}</a></h1>
|
||||
<h2><a href="${page('info', data['parent_rating_key'])}">${data['parent_title']}</a> - ${data['title']}</h2>
|
||||
<h3 class="hidden-xs">T${data['media_index']}</h3>
|
||||
% elif data['media_type'] in ('photo', 'clip'):
|
||||
<h1><a href="${page('info', data['parent_rating_key'])}">${data['parent_title']}</a></h1>
|
||||
<h2>${data['title']}</h2>
|
||||
% endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-content-wrapper">
|
||||
<div class="col-md-9">
|
||||
% if data['media_type'] == 'movie':
|
||||
<div class="summary-content-padding hidden-xs hidden-sm" style="height: 305px;">
|
||||
% elif data['media_type'] in ('show', 'season', 'collection'):
|
||||
<div class="summary-content-padding hidden-xs hidden-sm" style="height: 270px;">
|
||||
% elif data['media_type'] == 'episode':
|
||||
<div class="summary-content-padding hidden-xs hidden-sm" style="height: 70px;">
|
||||
% elif data['media_type'] == 'artist' or data['media_type'] == 'album':
|
||||
<div class="summary-content-padding hidden-xs hidden-sm" style="height: 150px;">
|
||||
% elif data['media_type'] == 'track':
|
||||
<div class="summary-content-padding hidden-xs hidden-sm" style="height: 180px;">
|
||||
% else:
|
||||
<div class="summary-content-padding hidden-xs hidden-sm">
|
||||
% endif
|
||||
% if data['media_type'] in ('movie', 'episode', 'track'):
|
||||
<%
|
||||
padding_height = ''
|
||||
if data['media_type'] == 'movie' or data['live']:
|
||||
padding_height = 'height: 305px;'
|
||||
elif data['media_type'] in ('show', 'season', 'collection'):
|
||||
padding_height = 'height: 270px;'
|
||||
elif data['media_type'] == 'episode':
|
||||
padding_height = 'height: 70px;'
|
||||
elif data['media_type'] in ('artist', 'album', 'playlist', 'photo_album', 'photo'):
|
||||
padding_height = 'height: 150px;'
|
||||
elif data['media_type'] in ('track', 'clip'):
|
||||
padding_height = 'height: 180px;'
|
||||
%>
|
||||
<div class="summary-content-padding hidden-xs hidden-sm" style="${padding_height}">
|
||||
% if data['media_type'] in ('movie', 'episode', 'track', 'clip'):
|
||||
<div class="summary-content-media-info-wrapper">
|
||||
% if data['media_type'] != 'track' and media_info['video_codec']:
|
||||
<img class="summary-content-media-flag" title="${media_info['video_codec']}" src="${http_root}images/media_flags/video_codec/${media_info['video_codec'] | vf}.png" />
|
||||
% endif
|
||||
% if data['media_type'] != 'track' and media_info['video_resolution']:
|
||||
<img class="summary-content-media-flag" title="${media_info['video_resolution']}" src="${http_root}images/media_flags/video_resolution/${media_info['video_resolution']}.png" />
|
||||
<img class="summary-content-media-flag" title="${media_info['video_resolution']}" src="${http_root}images/media_flags/video_resolution/${media_info['video_full_resolution'] | vr}.png" />
|
||||
% endif
|
||||
% if media_info['audio_codec']:
|
||||
<img class="summary-content-media-flag" title="${media_info['audio_codec']}" src="${http_root}images/media_flags/audio_codec/${media_info['audio_codec'] | af}.png" />
|
||||
@@ -219,17 +303,48 @@ DOCUMENTATION :: END
|
||||
</div>
|
||||
<div class="summary-content">
|
||||
<div class="summary-content-details-wrapper">
|
||||
% if data['rating']:
|
||||
<div class="star-rating hidden-xs hidden-sm" title="${data['rating']}">
|
||||
% for i in range(0,5):
|
||||
% if round(float(data['rating']) / 2) > i:
|
||||
<i class="star-icon fa fa-star"></i>
|
||||
% else:
|
||||
<i class="star-icon-o fa fa-star-o"></i>
|
||||
% endif
|
||||
% endfor
|
||||
<% rating = data['rating'] or data['audience_rating'] %>
|
||||
% if rating:
|
||||
% if data['audience_rating_image']:
|
||||
% if data['audience_rating_image'].startswith('imdb://'):
|
||||
<div class="critic-rating hidden-xs hidden-sm" title="${rating}">
|
||||
<span class="rating-image rating-imdb"><strong>${rating}</strong></span>
|
||||
</div>
|
||||
% endif
|
||||
% if data['audience_rating_image'].startswith('themoviedb://'):
|
||||
<div class="critic-rating hidden-xs hidden-sm" title="${rating}">
|
||||
<span class="rating-image rating-themoviedb"><strong>${get_percent(rating, 10)}%</strong></span>
|
||||
</div>
|
||||
% endif
|
||||
% if data['audience_rating_image'].startswith('rottentomatoes://'):
|
||||
<div class="critic-rating hidden-xs hidden-sm" title="${data['audience_rating']}">
|
||||
<span class="rating-image rating-rottentomatos-${data['audience_rating_image'].rsplit('.')[-1]}"><strong>${get_percent(data['audience_rating'], 10)}%</strong></span>
|
||||
</div>
|
||||
% endif
|
||||
% if data['rating_image'].startswith('rottentomatoes://'):
|
||||
<div class="critic-rating hidden-xs hidden-sm" title="${data['rating']}">
|
||||
<span class="rating-image rating-rottentomatos-${data['rating_image'].rsplit('.')[-1]}"><strong>${get_percent(data['rating'], 10)}%</strong></span>
|
||||
</div>
|
||||
% endif
|
||||
% else:
|
||||
<div class="critic-rating hidden-xs hidden-sm" title="${rating}">
|
||||
<i class="star-icon fa fa-star"></i> <strong>${get_percent(rating, 10)}%</strong>
|
||||
</div>
|
||||
% endif
|
||||
% endif
|
||||
<div class="summary-content-details-tag">
|
||||
% if data['media_type'] in ('collection', 'playlist') and data['children_count']:
|
||||
<%
|
||||
if data['media_type'] == 'collection':
|
||||
suffix = MEDIA_TYPE_HEADERS[data['sub_media_type']]
|
||||
elif data['media_type'] == 'playlist':
|
||||
suffix = MEDIA_TYPE_HEADERS[data['playlist_type']]
|
||||
if data['children_count'] == 1:
|
||||
suffix = suffix[:-1]
|
||||
%>
|
||||
Items <strong> ${data['children_count']} ${suffix} </strong>
|
||||
% endif
|
||||
</div>
|
||||
<div class="summary-content-details-tag">
|
||||
% if data['directors']:
|
||||
Directed by <strong> ${data['directors'][0]}</strong>
|
||||
@@ -249,13 +364,17 @@ DOCUMENTATION :: END
|
||||
Aired <strong> <span id="airdate">${data['originally_available_at']}</span></strong>
|
||||
% elif data['media_type'] == 'album' or data['media_type'] == 'track':
|
||||
Released <strong> ${data['year']}</strong>
|
||||
% elif data['media_type'] in ('photo', 'clip'):
|
||||
Taken <strong> <span id="airdate">${data['originally_available_at']}</span></strong>
|
||||
% elif data['media_type'] == 'collection':
|
||||
Year <strong> ${data['min_year']} - ${data['max_year']}</strong>
|
||||
% elif data['year']:
|
||||
Year <strong> ${data['year']}</strong>
|
||||
% endif
|
||||
</div>
|
||||
<div class="summary-content-details-tag">
|
||||
% if data['duration']:
|
||||
Runtime <strong> <span id="runtime">${data['duration']}</span> mins</strong>
|
||||
Runtime <strong> <span id="runtime">${data['duration']}</span></strong>
|
||||
% endif
|
||||
</div>
|
||||
<div class="summary-content-details-tag">
|
||||
@@ -263,6 +382,11 @@ DOCUMENTATION :: END
|
||||
Rated <strong> ${data['content_rating']} </strong>
|
||||
% endif
|
||||
</div>
|
||||
<div class="summary-content-details-tag" id="channel-icon">
|
||||
% if media_info['channel_identifier']:
|
||||
Channel <strong> <span class="thumb-tooltip" data-toggle="popover" data-img="${media_info['channel_thumb']}" data-height="40" data-width="40">${media_info['channel_call_sign']} ${media_info['channel_identifier']}</span> </strong>
|
||||
% endif
|
||||
</div>
|
||||
</div>
|
||||
% if data['tagline']:
|
||||
<div class="summary-content-summary">
|
||||
@@ -366,6 +490,17 @@ DOCUMENTATION :: END
|
||||
<div id="children-list" class="children-list"><i class="fa fa-refresh fa-spin"></i> Loading track list...</div>
|
||||
</div>
|
||||
</div>
|
||||
% elif data['media_type'] == 'photo_album':
|
||||
<div class="col-md-12">
|
||||
<div class="table-card-header">
|
||||
<div class="header-bar">
|
||||
<span>Photo List for <strong>${data['title']}</strong></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-card-back">
|
||||
<div id="children-list" class="children-list"><i class="fa fa-refresh fa-spin"></i> Loading photo list...</div>
|
||||
</div>
|
||||
</div>
|
||||
% elif data['media_type'] == 'collection':
|
||||
<div class="col-md-12">
|
||||
<div class="table-card-header">
|
||||
@@ -374,30 +509,36 @@ DOCUMENTATION :: END
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-card-back">
|
||||
<div id="children-list" class="children-list"><i class="fa fa-refresh fa-spin"></i> Loading movies list...</div>
|
||||
<div id="children-list" class="children-list"><i class="fa fa-refresh fa-spin"></i> Loading collection items...</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="collection-related-list-container" style="display: none;">
|
||||
</div>
|
||||
% endif
|
||||
% if data['media_type'] != 'collection':
|
||||
% elif data['media_type'] == 'playlist':
|
||||
<div class="col-md-12">
|
||||
<div class="table-card-header">
|
||||
<div class="header-bar">
|
||||
% if data['media_type'] in ('artist', 'album', 'track'):
|
||||
<span>Play History for <strong>${data['title']}</strong></span>
|
||||
% else:
|
||||
<span>Watch History for <strong>${data['title']}</strong></span>
|
||||
% endif
|
||||
<span>${MEDIA_TYPE_HEADERS[data['playlist_type']]} List for <strong>${data['title']}</strong></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-card-back">
|
||||
<div id="children-list" class="children-list"><i class="fa fa-refresh fa-spin"></i> Loading playlist items...</div>
|
||||
</div>
|
||||
</div>
|
||||
% endif
|
||||
<%
|
||||
history_type = data['media_type'] in ('movie', 'show', 'season', 'episode', 'artist', 'album', 'track')
|
||||
history_active = 'active' if history_type else ''
|
||||
export_active = 'active' if not history_type else ''
|
||||
%>
|
||||
% if history_type and _session['user_group'] == 'admin':
|
||||
<div class="col-md-12">
|
||||
<div class="table-card-header">
|
||||
<ul class="nav nav-list nav-pills" role="tablist">
|
||||
<li class="${history_active}"><a id="nav-tabs-history" href="#tabs-history" role="tab" data-toggle="tab">History</a></li>
|
||||
<li class="${export_active}"><a id="nav-tabs-export" href="#tabs-export" role="tab" data-toggle="tab">Export</a></li>
|
||||
</ul>
|
||||
<div class="button-bar">
|
||||
% if _session['user_group'] == 'admin':
|
||||
<div class="alert alert-danger alert-edit" role="alert" id="row-edit-mode-alert"><i class="fa fa-exclamation-triangle"></i> Select rows to delete. Data is deleted upon exiting delete mode.</div>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-danger btn-edit" data-toggle="button" aria-pressed="false" autocomplete="off" id="row-edit-mode">
|
||||
<i class="fa fa-trash-o"></i> Delete mode
|
||||
</button>
|
||||
</div>
|
||||
% if source == 'history':
|
||||
<div class="btn-group">
|
||||
<a href="update_metadata?rating_key=${data['rating_key']}&update=True" class="btn btn-danger btn-edit" id="fix-metadata">
|
||||
@@ -405,17 +546,17 @@ DOCUMENTATION :: END
|
||||
</a>
|
||||
</div>
|
||||
% endif
|
||||
% if data.get('tvmaze_id') or data.get('themoviedb_id'):
|
||||
% if data.get('tvmaze_id') or data.get('themoviedb_id') or data.get('musicbrainz_id'):
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-danger btn-edit" data-toggle="modal" aria-pressed="false" autocomplete="off" id="delete-lookup-info"
|
||||
data-id="${data['grandparent_rating_key'] if data['media_type'] in ('episode', 'track') else data['parent_rating_key'] if data['media_type'] in ('season', 'album') else data['rating_key']}"
|
||||
data-title="${data['grandparent_title'] if data['media_type'] in ('episode', 'track') else data['parent_title'] if data['media_type'] in ('season', 'album') else data['title']}">
|
||||
data-id="${data['grandparent_rating_key'] if data['media_type'] == 'episode' else data['parent_rating_key'] if data['media_type'] == 'season' else data['rating_key']}"
|
||||
data-title="${data['grandparent_title'] if data['media_type'] == 'episode' else data['parent_title'] if data['media_type'] == 'season' else data['title']}">
|
||||
<i class="fa fa-search"></i> Delete Lookup Info
|
||||
</button>
|
||||
</div>
|
||||
% endif
|
||||
% if data.get('poster_url'):
|
||||
<div class="btn-group">
|
||||
<div class="btn-group" id="hosted-poster">
|
||||
% if data['media_type'] == 'artist' or data['media_type'] == 'album' or data['media_type'] == 'track':
|
||||
<span class="hosted-poster-tooltip" data-toggle="popover" data-img="${data['poster_url']}" data-height="80" data-width="80" style="display: inline-flex;">
|
||||
% else:
|
||||
@@ -429,6 +570,7 @@ DOCUMENTATION :: END
|
||||
</span>
|
||||
</div>
|
||||
% endif
|
||||
% if not data['live']:
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-dark" data-toggle="modal" aria-pressed="false" autocomplete="off" id="send-recently-added-notification"
|
||||
data-id="${data['rating_key']}">
|
||||
@@ -436,35 +578,117 @@ DOCUMENTATION :: END
|
||||
</button>
|
||||
</div>
|
||||
% endif
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-dark refresh-history-button" id="refresh-history-list"><i class="fa fa-refresh"></i> Refresh history</button>
|
||||
</div>
|
||||
<div class="btn-group colvis-button-bar"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-card-back">
|
||||
<table class="display history_table" id="history_table-RK-${data['rating_key']}" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th align="left" id="delete">Delete</th>
|
||||
<th align="left" id="date">Date</th>
|
||||
<th align="left" id="friendly_name">User</th>
|
||||
<th align="left" id="ip_address">IP Address</th>
|
||||
<th align="left" id="platform">Platform</th>
|
||||
<th align="left" id="player">Player</th>
|
||||
<th align="left" id="title">Title</th>
|
||||
<th align="left" id="started">Started</th>
|
||||
<th align="left" id="paused_counter">Paused</th>
|
||||
<th align="left" id="stopped">Stopped</th>
|
||||
<th align="left" id="duration">Duration</th>
|
||||
<th align="left" id="percent_complete"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
% endif
|
||||
<div class="tab-content">
|
||||
% if history_type:
|
||||
<div role="tabpanel" class="tab-pane ${history_active}" id="tabs-history">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="table-card-header">
|
||||
<div class="header-bar">
|
||||
% if data['media_type'] in ('artist', 'album', 'track'):
|
||||
<span>Play History for <strong>${data['title']}</strong></span>
|
||||
% else:
|
||||
<span>Watch History for <strong>${data['title']}</strong></span>
|
||||
% endif
|
||||
</div>
|
||||
<div class="button-bar">
|
||||
% if _session['user_group'] == 'admin':
|
||||
<div class="alert alert-danger alert-edit" role="alert" id="row-edit-mode-alert"><i class="fa fa-exclamation-triangle"></i> Select rows to delete. Data is deleted upon exiting delete mode.</div>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-danger btn-edit" data-toggle="button" aria-pressed="false" autocomplete="off" id="row-edit-mode">
|
||||
<i class="fa fa-trash-o"></i> Delete mode
|
||||
</button>
|
||||
</div>
|
||||
% endif
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-dark refresh-history-button" id="refresh-history-list"><i class="fa fa-refresh"></i> Refresh history</button>
|
||||
</div>
|
||||
<div class="btn-group colvis-button-bar" id="button-bar-history"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-card-back">
|
||||
<table class="display history_table" id="history_table-RK-${data['rating_key']}" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th align="left" id="delete">Delete</th>
|
||||
<th align="left" id="date">Date</th>
|
||||
<th align="left" id="friendly_name">User</th>
|
||||
<th align="left" id="ip_address">IP Address</th>
|
||||
<th align="left" id="platform">Platform</th>
|
||||
<th align="left" id="product">Product</th>
|
||||
<th align="left" id="player">Player</th>
|
||||
<th align="left" id="title">Title</th>
|
||||
<th align="left" id="started">Started</th>
|
||||
<th align="left" id="paused_counter">Paused</th>
|
||||
<th align="left" id="stopped">Stopped</th>
|
||||
<th align="left" id="duration">Duration</th>
|
||||
<th align="left" id="percent_complete"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
% endif
|
||||
% if not data['live'] and _session['user_group'] == 'admin':
|
||||
<div role="tabpanel" class="tab-pane ${export_active}" id="tabs-export">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="table-card-header">
|
||||
<div class="header-bar">
|
||||
<span>Metadata Exports for <strong>${data['title']}</strong></span>
|
||||
</div>
|
||||
<div class="button-bar">
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-dark export-button" id="toggle-export-modal" data-toggle="modal" data-target="#export-modal"
|
||||
data-section_id="${data['section_id']}" data-rating_key="${data['rating_key']}"
|
||||
data-media_type="${data['media_type']}" data-sub_media_type="${data['sub_media_type'] or data['playlist_type'] or ''}">
|
||||
<i class="fa fa-file-export"></i> Export metadata
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-dark refresh-export-table-button" id="refresh-export-table">
|
||||
<i class="fa fa-refresh"></i> Refresh exports
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group colvis-button-bar" id="button-bar-export"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-card-back">
|
||||
<table class="display export_table" id="export_table-RK-${data['rating_key']}" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th align="left" id="timestamp">Exported At</th>
|
||||
<th align="left" id="media_type_title">Media Type</th>
|
||||
<th align="left" id="rating_key">Rating Key</th>
|
||||
<th align="left" id="filename">Filename</th>
|
||||
<th align="left" id="file_format">File Format</th>
|
||||
<th align="left" id="metadata_level">Metadata Level</th>
|
||||
<th align="left" id="media_info_level">Media Info Level</th>
|
||||
<th align="left" id="media_info_level">Custom Fields</th>
|
||||
<th align="left" id="file_size">File Size</th>
|
||||
<th align="left" id="complete">Download</th>
|
||||
<th align="left" id="delete">Delete</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
% endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -473,6 +697,10 @@ DOCUMENTATION :: END
|
||||
</%def>
|
||||
|
||||
<%def name="modalIncludes()">
|
||||
% if metadata:
|
||||
<%
|
||||
data = defaultdict(None, **metadata)
|
||||
%>
|
||||
<div class="modal fade" id="info-modal" tabindex="-1" role="dialog" aria-labelledby="info-modal">
|
||||
</div>
|
||||
<div class="modal fade" id="ip-info-modal" tabindex="-1" role="dialog" aria-labelledby="ip-info-modal">
|
||||
@@ -548,6 +776,9 @@ DOCUMENTATION :: END
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
% endif
|
||||
<div id="export-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="export-modal">
|
||||
</div>
|
||||
</%def>
|
||||
|
||||
<%def name="javascriptIncludes()">
|
||||
@@ -555,11 +786,31 @@ DOCUMENTATION :: END
|
||||
<script src="${http_root}js/dataTables.colVis.js"></script>
|
||||
<script src="${http_root}js/dataTables.bootstrap.min.js"></script>
|
||||
<script src="${http_root}js/dataTables.bootstrap.pagination.js"></script>
|
||||
<script src="${http_root}js/moment-with-locale.js"></script>
|
||||
|
||||
% if data:
|
||||
% if metadata:
|
||||
<%
|
||||
data = defaultdict(None, **metadata)
|
||||
history_user_id = '' if _session['user_group'] == 'admin' else _session['user_id']
|
||||
%>
|
||||
<script src="${http_root}js/tables/history_table.js${cache_param}"></script>
|
||||
% if data['media_type'] in ('show', 'artist'):
|
||||
<script src="${http_root}js/tables/export_table.js${cache_param}"></script>
|
||||
% if data['live']:
|
||||
<script>
|
||||
function get_history() {
|
||||
history_table_options.ajax = {
|
||||
url: 'get_history',
|
||||
type: 'POST',
|
||||
data: function ( d ) {
|
||||
return {
|
||||
json_data: JSON.stringify( d ),
|
||||
guid: "${data['guid']}",
|
||||
user_id: "${history_user_id}"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
% elif data['media_type'] in ('show', 'artist'):
|
||||
<script>
|
||||
function get_history() {
|
||||
history_table_options.ajax = {
|
||||
@@ -569,7 +820,7 @@ DOCUMENTATION :: END
|
||||
return {
|
||||
json_data: JSON.stringify( d ),
|
||||
grandparent_rating_key: "${data['rating_key']}",
|
||||
user_id: "${_session['user_group']}" == "admin" ? null : "${_session['user_id']}"
|
||||
user_id: "${history_user_id}"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -585,7 +836,7 @@ DOCUMENTATION :: END
|
||||
return {
|
||||
json_data: JSON.stringify( d ),
|
||||
parent_rating_key: "${data['rating_key']}",
|
||||
user_id: "${_session['user_group']}" == "admin" ? null : "${_session['user_id']}"
|
||||
user_id: "${history_user_id}"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -601,98 +852,43 @@ DOCUMENTATION :: END
|
||||
return {
|
||||
json_data: JSON.stringify( d ),
|
||||
rating_key: "${data['rating_key']}",
|
||||
user_id: "${_session['user_group']}" == "admin" ? null : "${_session['user_id']}"
|
||||
user_id: "${history_user_id}"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
% endif
|
||||
% if data['media_type'] != 'collection':
|
||||
% if data['media_type'] in ('movie', 'show', 'season', 'episode', 'artist', 'album', 'track'):
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
function loadHistoryTable() {
|
||||
get_history();
|
||||
history_table = $('#history_table-RK-${data["rating_key"]}').DataTable(history_table_options);
|
||||
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark', exclude: [0, 11] });
|
||||
$(colvis.button()).appendTo('div.colvis-button-bar');
|
||||
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark', exclude: [0, 12] });
|
||||
$(colvis.button()).appendTo('#button-bar-history');
|
||||
|
||||
clearSearchButton('history_table-RK-${data["rating_key"]}', history_table);
|
||||
}
|
||||
|
||||
$('#row-edit-mode').on('click', function() {
|
||||
$('#row-edit-mode-alert').fadeIn(200);
|
||||
|
||||
if ($(this).hasClass('active')) {
|
||||
if (history_to_delete.length > 0) {
|
||||
$('#deleteCount').text(history_to_delete.length);
|
||||
$('#confirm-modal-delete').modal();
|
||||
$('#confirm-modal-delete').one('click', '#confirm-delete', function () {
|
||||
history_to_delete.forEach(function (row, idx) {
|
||||
$.ajax({
|
||||
url: 'delete_history_rows',
|
||||
type: 'POST',
|
||||
data: { row_id: row },
|
||||
async: true,
|
||||
success: function (data) {
|
||||
var msg = "History deleted";
|
||||
showMsg(msg, false, true, 2000);
|
||||
}
|
||||
});
|
||||
});
|
||||
history_table.draw();
|
||||
});
|
||||
}
|
||||
|
||||
$('.delete-control').each(function () {
|
||||
$(this).addClass('hidden');
|
||||
$('#row-edit-mode-alert').fadeOut(200);
|
||||
});
|
||||
|
||||
} else {
|
||||
history_to_delete = [];
|
||||
$('.delete-control').each(function() {
|
||||
$(this).find('button.btn-danger').toggleClass('btn-warning').toggleClass('btn-danger');
|
||||
$(this).removeClass('hidden');
|
||||
});
|
||||
}
|
||||
});
|
||||
$(document).ready(function () {
|
||||
loadHistoryTable();
|
||||
});
|
||||
|
||||
$("#refresh-history-list").click(function () {
|
||||
history_table.draw();
|
||||
});
|
||||
|
||||
// Send recently added notification
|
||||
$('#send-recently-added-notification').on('click', function () {
|
||||
var rating_key = $(this).data('id');
|
||||
|
||||
$('#send-recently-added-modal').modal();
|
||||
$('#send-recently-added-modal').one('click', '#confirm-send-notification', function () {
|
||||
$.ajax({
|
||||
url: 'send_manual_on_created',
|
||||
data: {
|
||||
rating_key: rating_key,
|
||||
notifier_id: $('#send-notification-notifier option:selected').val()
|
||||
},
|
||||
async: true,
|
||||
success: function (data) {
|
||||
if (data.result === 'success') {
|
||||
showMsg('<i class="fa fa-check"></i> ' + data.message, false, true, 5000);
|
||||
} else {
|
||||
showMsg('<i class="fa fa-exclamation-circle"></i> ' + data.message, false, true, 5000, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
% endif
|
||||
% if data['media_type'] in ('show', 'season', 'artist', 'album', 'collection'):
|
||||
% if data['media_type'] in ('show', 'season', 'artist', 'album', 'photo_album', 'collection', 'playlist'):
|
||||
<script>
|
||||
$.ajax({
|
||||
url: 'get_item_children',
|
||||
type: 'GET',
|
||||
async: true,
|
||||
data: { rating_key : "${data['rating_key']}" },
|
||||
data: {
|
||||
rating_key: "${data['rating_key']}",
|
||||
media_type: "${data['media_type']}"
|
||||
},
|
||||
complete: function(xhr, status) {
|
||||
$("#children-list").html(xhr.responseText);
|
||||
}
|
||||
@@ -706,7 +902,7 @@ DOCUMENTATION :: END
|
||||
type: 'GET',
|
||||
async: true,
|
||||
data: {
|
||||
rating_key : "${data['rating_key']}",
|
||||
rating_key: "${data['rating_key']}",
|
||||
title: "${data['title']}"
|
||||
},
|
||||
complete: function(xhr, status) {
|
||||
@@ -716,17 +912,167 @@ DOCUMENTATION :: END
|
||||
</script>
|
||||
% endif
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
// Javascript to enable link to tab
|
||||
var hash = document.location.hash;
|
||||
var prefix = "tab_";
|
||||
if (hash) {
|
||||
$('.nav-list #nav-' + hash.replace('#' + prefix, "")).tab('show').trigger('show.bs.tab');
|
||||
}
|
||||
|
||||
// Change hash for page-reload
|
||||
$('.nav-list a').on('shown.bs.tab', function (e) {
|
||||
window.location.hash = e.target.hash.replace("#", "#" + prefix);
|
||||
});
|
||||
});
|
||||
|
||||
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
||||
$.fn.dataTable.tables({ visible: true, api: true }).columns.adjust();
|
||||
});
|
||||
|
||||
var airdate = $("#airdate")
|
||||
var runtime = $("#runtime")
|
||||
airdate.html(moment(airdate.text()).format('MMM DD, YYYY'));
|
||||
runtime.html(humanDuration(runtime.text()));
|
||||
|
||||
$('div.art-face').animate({ opacity: 0.2 }, { duration: 1000 });
|
||||
$('#channel-icon').popover({
|
||||
selector: '[data-toggle=popover]',
|
||||
html: true,
|
||||
container: 'body',
|
||||
trigger: 'hover',
|
||||
placement: 'right',
|
||||
template: '<div class="popover channel-thumbnail-popover" role="tooltip"><div class="arrow" style="top: 50%;"></div><div class="popover-content"></div></div>',
|
||||
content: function () {
|
||||
return '<div class="channel-thumbnail" style="background-image: url(' + $(this).data('img') + ');" />';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
% if _session['user_group'] == 'admin':
|
||||
<script>
|
||||
$("#toggle-export-modal").click(function() {
|
||||
$.ajax({
|
||||
url: 'export_metadata_modal',
|
||||
data: {
|
||||
section_id: $(this).data('section_id'),
|
||||
rating_key: $(this).data('rating_key'),
|
||||
media_type: $(this).data('media_type'),
|
||||
sub_media_type: $(this).data('sub_media_type')
|
||||
},
|
||||
cache: false,
|
||||
async: true,
|
||||
complete: function(xhr, status) {
|
||||
$("#export-modal").html(xhr.responseText);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function loadExportTable() {
|
||||
// Build export table
|
||||
export_table_options.ajax = {
|
||||
url: 'get_export_list',
|
||||
type: 'POST',
|
||||
data: function ( d ) {
|
||||
return {
|
||||
json_data: JSON.stringify( d ),
|
||||
rating_key: "${data['rating_key']}"
|
||||
};
|
||||
}
|
||||
};
|
||||
export_table = $('#export_table-RK-${data["rating_key"]}').DataTable(export_table_options);
|
||||
export_table.columns([2, 7]).visible(false);
|
||||
|
||||
var colvis = new $.fn.dataTable.ColVis(export_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark' });
|
||||
$(colvis.button()).appendTo('#button-bar-export');
|
||||
|
||||
clearSearchButton('export_table-RK-${data["rating_key"]}', export_table);
|
||||
}
|
||||
|
||||
$('#nav-tabs-export').on('shown.bs.tab', function() {
|
||||
if (typeof(export_table) === 'undefined') {
|
||||
loadExportTable();
|
||||
}
|
||||
});
|
||||
|
||||
$(document).ready(function () {
|
||||
if (!($('#tabs-history').length)) {
|
||||
loadExportTable();
|
||||
}
|
||||
});
|
||||
|
||||
$("#refresh-export-table").click(function () {
|
||||
export_table.draw();
|
||||
});
|
||||
|
||||
$('#row-edit-mode').on('click', function() {
|
||||
$('#row-edit-mode-alert').fadeIn(200);
|
||||
|
||||
if ($(this).hasClass('active')) {
|
||||
if (history_to_delete.length > 0) {
|
||||
$('#deleteCount').text(history_to_delete.length);
|
||||
$('#confirm-modal-delete').modal();
|
||||
$('#confirm-modal-delete').one('click', '#confirm-delete', function () {
|
||||
$.ajax({
|
||||
url: 'delete_history_rows',
|
||||
type: 'POST',
|
||||
data: { row_ids: history_to_delete.join(',') },
|
||||
async: true,
|
||||
success: function (data) {
|
||||
var msg = "History deleted";
|
||||
showMsg(msg, false, true, 2000);
|
||||
history_table.draw();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$('.delete-control').each(function () {
|
||||
$(this).addClass('hidden');
|
||||
$('#row-edit-mode-alert').fadeOut(200);
|
||||
});
|
||||
|
||||
} else {
|
||||
history_to_delete = [];
|
||||
$('.delete-control').each(function() {
|
||||
$(this).find('button.btn-danger').toggleClass('btn-warning').toggleClass('btn-danger');
|
||||
$(this).removeClass('hidden');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Send recently added notification
|
||||
$('#send-recently-added-notification').on('click', function () {
|
||||
var rating_key = $(this).data('id');
|
||||
|
||||
$('#send-recently-added-modal').modal();
|
||||
$('#send-recently-added-modal').one('click', '#confirm-send-notification', function () {
|
||||
$.ajax({
|
||||
url: 'send_manual_on_created',
|
||||
data: {
|
||||
rating_key: rating_key,
|
||||
notifier_id: $('#send-notification-notifier option:selected').val()
|
||||
},
|
||||
async: true,
|
||||
success: function (data) {
|
||||
if (data.result === 'success') {
|
||||
showMsg('<i class="fa fa-check"></i> ' + data.message, false, true, 5000);
|
||||
} else {
|
||||
showMsg('<i class="fa fa-exclamation-circle"></i> ' + data.message, false, true, 5000, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$('.metadata-xml').on('tripleclick', function () {
|
||||
openPlexXML("/library/metadata/${data['rating_key']}");
|
||||
});
|
||||
|
||||
$("#airdate").html(moment($("#airdate").text()).format('MMM DD, YYYY'));
|
||||
$("#runtime").html(millisecondsToMinutes($("#runtime").text(), true));
|
||||
$('div.art-face').animate({ opacity: 0.2 }, { duration: 1000 });
|
||||
</script>
|
||||
% endif
|
||||
% if data.get('poster_url'):
|
||||
<script>
|
||||
$('.hosted-poster-tooltip').popover({
|
||||
$('#hosted-poster').popover({
|
||||
selector: '[data-toggle=popover]',
|
||||
html: true,
|
||||
container: 'body',
|
||||
trigger: 'hover',
|
||||
@@ -750,13 +1096,13 @@ DOCUMENTATION :: END
|
||||
});
|
||||
</script>
|
||||
% endif
|
||||
% if data.get('tvmaze_id') or data.get('themoviedb_id'):
|
||||
% if data.get('tvmaze_id') or data.get('themoviedb_id') or data.get('musicbrainz_id'):
|
||||
<script>
|
||||
$('#delete-lookup-info').on('click', function () {
|
||||
var msg = 'Are you sure you want to delete the 3rd party API lookup for <strong>' + $(this).data('title') + '</strong>?<br><br>' +
|
||||
'The info will be looked up again the next time a notification is sent.';
|
||||
var msg = 'Are you sure you want to delete all the metadata lookup info for <strong>' + $(this).data('title') + '</strong>?' +
|
||||
'<br /><br />Tautulli will lookup the metadata info again the next time a notification is sent.';
|
||||
var url = 'delete_lookup_info';
|
||||
var data = { rating_key: $(this).data('id'), title: $(this).data('title') };
|
||||
var data = { rating_key: $(this).data('id') };
|
||||
var callback = function () {
|
||||
$('#delete-lookup-info').closest('.btn-group').remove();
|
||||
};
|
||||
|
@@ -27,20 +27,24 @@ DOCUMENTATION :: END
|
||||
</%doc>
|
||||
|
||||
% if data != None:
|
||||
<%
|
||||
from plexpy.helpers import cast_to_int, page
|
||||
%>
|
||||
% if data['children_count'] > 0:
|
||||
<div class="item-children-wrapper">
|
||||
<ul class="item-children-instance list-unstyled">
|
||||
<% max_height ='max-height' if data['children_type'] in ('track', 'photo') or media_type == 'playlist' else '' %>
|
||||
<ul class="item-children-instance ${max_height} list-unstyled">
|
||||
% for child in data['children_list']:
|
||||
% if child['rating_key']:
|
||||
% if data['children_type'] == 'track':
|
||||
% if data['children_type'] in ('track', 'photo') or media_type == 'playlist':
|
||||
<li class="item-children-list-item">
|
||||
% else:
|
||||
<li>
|
||||
% endif
|
||||
% if data['children_type'] == 'movie':
|
||||
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">
|
||||
<a href="${page('info', child['rating_key'])}" title="${child['title']}">
|
||||
<div class="item-children-poster">
|
||||
<div class="item-children-poster-face poster-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450&fallback=poster);"></div>
|
||||
<div class="item-children-poster-face poster-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 450, fallback='poster')});"></div>
|
||||
% if _session['user_group'] == 'admin':
|
||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||
% endif
|
||||
@@ -48,14 +52,14 @@ DOCUMENTATION :: END
|
||||
</a>
|
||||
<div class="item-children-instance-text-wrapper poster-item">
|
||||
<h3>
|
||||
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">${child['title']}</a>
|
||||
<a href="${page('info', child['rating_key'])}" title="${child['title']}">${child['title']}</a>
|
||||
</h3>
|
||||
<h3 class="text-muted">${child['year']}</h3>
|
||||
</div>
|
||||
% elif data['children_type'] == 'show':
|
||||
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">
|
||||
<a href="${page('info', child['rating_key'])}" title="${child['title']}">
|
||||
<div class="item-children-poster">
|
||||
<div class="item-children-poster-face poster-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450&fallback=poster);"></div>
|
||||
<div class="item-children-poster-face poster-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 450, fallback='poster')});"></div>
|
||||
% if _session['user_group'] == 'admin':
|
||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||
% endif
|
||||
@@ -63,16 +67,16 @@ DOCUMENTATION :: END
|
||||
</a>
|
||||
<div class="item-children-instance-text-wrapper poster-item">
|
||||
<h3>
|
||||
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">${child['title']}</a>
|
||||
<a href="${page('info', child['rating_key'])}" title="${child['title']}">${child['title']}</a>
|
||||
</h3>
|
||||
</div>
|
||||
% elif data['children_type'] == 'season':
|
||||
<a href="info?rating_key=${child['rating_key']}" title="Season ${child['media_index']}">
|
||||
<a href="${page('info', child['rating_key'])}" title="Season ${child['media_index']}">
|
||||
<div class="item-children-poster">
|
||||
% if child['thumb']:
|
||||
<div class="item-children-poster-face poster-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450&fallback=poster);">
|
||||
<div class="item-children-poster-face poster-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 450, fallback='poster')});">
|
||||
% else:
|
||||
<div class="item-children-poster-face poster-item" style="background-image: url(pms_image_proxy?img=${child['parent_thumb']}&width=300&height=450&fallback=poster);">
|
||||
<div class="item-children-poster-face poster-item" style="background-image: url(${page('pms_image_proxy', child['parent_thumb'], child['parent_rating_key'], 300, 450, fallback='poster')});">
|
||||
% endif
|
||||
<div class="item-children-card-overlay">
|
||||
<div class="item-children-overlay-text">
|
||||
@@ -86,9 +90,9 @@ DOCUMENTATION :: END
|
||||
</div>
|
||||
</a>
|
||||
% elif data['children_type'] == 'episode':
|
||||
<a href="info?rating_key=${child['rating_key']}" title="Episode ${child['media_index']}">
|
||||
<a href="${page('info', child['rating_key'])}" title="Episode ${child['media_index']}">
|
||||
<div class="item-children-poster">
|
||||
<div class="item-children-poster-face episode-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=500&height=250&fallback=art);">
|
||||
<div class="item-children-poster-face episode-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 500, 280, fallback='art')});">
|
||||
<div class="item-children-card-overlay">
|
||||
<div class="item-children-overlay-text">
|
||||
Episode ${child['media_index'] or child['originally_available_at']}
|
||||
@@ -102,13 +106,13 @@ DOCUMENTATION :: END
|
||||
</a>
|
||||
<div class="item-children-instance-text-wrapper episode-item">
|
||||
<h3>
|
||||
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">${child['title']}</a>
|
||||
<a href="${page('info', child['rating_key'])}" title="${child['title']}">${child['title']}</a>
|
||||
</h3>
|
||||
</div>
|
||||
% elif data['children_type'] == 'album':
|
||||
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">
|
||||
<a href="${page('info', child['rating_key'])}" title="${child['title']}">
|
||||
<div class="item-children-poster">
|
||||
<div class="item-children-poster-face cover-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=300&fallback=cover);"></div>
|
||||
<div class="item-children-poster-face cover-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 300, fallback='cover')});"></div>
|
||||
% if _session['user_group'] == 'admin':
|
||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||
% endif
|
||||
@@ -116,41 +120,148 @@ DOCUMENTATION :: END
|
||||
</a>
|
||||
<div class="item-children-instance-text-wrapper cover-item">
|
||||
<h3>
|
||||
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">${child['title']}</a>
|
||||
<a href="${page('info', child['rating_key'])}" title="${child['title']}">${child['title']}</a>
|
||||
</h3>
|
||||
</div>
|
||||
% elif data['children_type'] == 'track':
|
||||
% if loop.index % 2 == 0:
|
||||
<div class="item-children-list-item-even">
|
||||
<span class="item-children-list-item-index"> ${child['media_index']}</span>
|
||||
<span class="item-children-list-item-title"><a href="info?rating_key=${child['rating_key']}" title="${child['title']}">${child['title']}</a>
|
||||
% if child['original_title']:
|
||||
<% e = 'even' if loop.index % 2 == 0 else 'odd' %>
|
||||
<div class="item-children-list-item-${e}">
|
||||
<span class="item-children-list-item-index">${child['media_index']}</span>
|
||||
<span class="item-children-list-item-title">
|
||||
<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>
|
||||
<a href="${page('info', child['rating_key'])}" title="${child['title']}">
|
||||
<span class="thumb-tooltip" data-toggle="popover" data-img="${page('pms_image_proxy', child['parent_thumb'], child['parent_rating_key'], 300, 300, fallback='cover')}" data-height="80" data-width="80">
|
||||
${child['title']}
|
||||
</span>
|
||||
</a>
|
||||
% if child['original_title']:
|
||||
<span class="text-muted"> - ${child['original_title']}</span>
|
||||
% endif
|
||||
% endif
|
||||
</span>
|
||||
<span class="item-children-list-item-duration" id="item-children-list-item-duration-${loop.index + 1}">
|
||||
<script>$('#item-children-list-item-duration-${loop.index + 1}').text(moment.utc(${child['duration']}).format("m:ss"));</script>
|
||||
<% f = 'h:mm:ss' if cast_to_int(child['duration']) >= 3600000 else 'm:ss' %>
|
||||
<script>$('#item-children-list-item-duration-${loop.index + 1}').text(moment.utc(${child['duration']}).format("${f}"));</script>
|
||||
</span>
|
||||
</div>
|
||||
% else:
|
||||
<div class="item-children-list-item-odd">
|
||||
<span class="item-children-list-item-index"> ${child['media_index']}</span>
|
||||
<span class="item-children-list-item-title"><a href="info?rating_key=${child['rating_key']}" title="${child['title']}">${child['title']}</a>
|
||||
% if child['original_title']:
|
||||
<span class="text-muted"> - ${child['original_title']}</span>
|
||||
% endif
|
||||
% elif data['children_type'] == 'photo':
|
||||
<% e = 'even' if loop.index % 2 == 0 else 'odd' %>
|
||||
<div class="item-children-list-item-${e}">
|
||||
<span class="item-children-list-item-index">${loop.index + 1}</span>
|
||||
<span class="item-children-list-item-title">
|
||||
% if child['media_type'] == 'photo_album':
|
||||
<span class="media-type-tooltip" data-toggle="tooltip" title="Photo"><i class="fa fa-camera fa-fw"></i></span>
|
||||
% elif child['media_type'] == 'clip':
|
||||
<span class="media-type-tooltip" data-toggle="tooltip" title="Photo"><i class="fa fa-video-camera fa-fw"></i></span>
|
||||
% else:
|
||||
<span class="media-type-tooltip" data-toggle="tooltip" title="Photo"><i class="fa fa-picture-o fa-fw"></i></span>
|
||||
% endif
|
||||
<a href="${page('info', child['rating_key'])}" title="${child['title']}">
|
||||
<span class="thumb-tooltip" data-toggle="popover" data-img="${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 300, fallback='cover')}" data-height="80" data-width="80">
|
||||
${child['title']}
|
||||
</span>
|
||||
</a>
|
||||
</span>
|
||||
% if child['duration']:
|
||||
<span class="item-children-list-item-duration" id="item-children-list-item-duration-${loop.index + 1}">
|
||||
<script>$('#item-children-list-item-duration-${loop.index + 1}').text(moment.utc(${child['duration']}).format("m:ss"));</script>
|
||||
<% f = 'h:mm:ss' if cast_to_int(child['duration']) >= 3600000 else 'm:ss' %>
|
||||
<script>$('#item-children-list-item-duration-${loop.index + 1}').text(moment.utc(${child['duration']}).format("${f}"));</script>
|
||||
</span>
|
||||
% endif
|
||||
</div>
|
||||
% elif media_type == 'playlist':
|
||||
<% e = 'even' if loop.index % 2 == 0 else 'odd' %>
|
||||
<div class="item-children-list-item-${e}">
|
||||
<span class="item-children-list-item-index">${loop.index + 1}</span>
|
||||
<span class="item-children-list-item-title">
|
||||
% if child['media_type'] == 'movie':
|
||||
<span class="media-type-tooltip" data-toggle="tooltip" title="Movie"><i class="fa fa-film fa-fw"></i></span>
|
||||
<a href="${page('info', child['rating_key'])}" title="${child['title']}">
|
||||
<span class="thumb-tooltip" data-toggle="popover" data-img="${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 450, fallback='poster')}" data-height="120" data-width="80">
|
||||
${child['title']}
|
||||
</span>
|
||||
</a>
|
||||
<span class="text-muted"> (${child['year']})</span>
|
||||
% elif child['media_type'] == 'episode':
|
||||
<span class="media-type-tooltip" data-toggle="tooltip" title="Episode"><i class="fa fa-television fa-fw"></i></span>
|
||||
<a href="${page('info', child['grandparent_rating_key'])}" title="${child['grandparent_title']}">
|
||||
<span class="thumb-tooltip" data-toggle="popover" data-img="${page('pms_image_proxy', child['grandparent_thumb'], child['grandparent_rating_key'], 300, 450, fallback='poster')}" data-height="120" data-width="80">
|
||||
${child['grandparent_title']}
|
||||
</span>
|
||||
</a> -
|
||||
<a href="${page('info', child['rating_key'])}" title="${child['title']}">
|
||||
<span class="thumb-tooltip" data-toggle="popover" data-img="${page('pms_image_proxy', child['parent_thumb'], child['parent_rating_key'], 300, 450, fallback='poster')}" data-height="120" data-width="80">
|
||||
${child['title']}
|
||||
</span>
|
||||
</a>
|
||||
<span class="text-muted"> (<a class="no-highlight" href="${page('info', child['parent_rating_key'])}" title="${child['parent_title']}">S${child['parent_media_index']}</a> · <a class="no-highlight" href="${page('info', child['rating_key'])}" title="${child['title']}">E${child['media_index']}</a>)</span>
|
||||
% elif child['media_type'] == 'track':
|
||||
<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>
|
||||
<a href="${page('info', child['rating_key'])}" title="${child['title']}">
|
||||
<span class="thumb-tooltip" data-toggle="popover" data-img="${page('pms_image_proxy', child['parent_thumb'], child['parent_rating_key'], 300, 300, fallback='cover')}" data-height="80" data-width="80">
|
||||
${child['title']}
|
||||
</span>
|
||||
</a> -
|
||||
<a href="${page('info', child['grandparent_rating_key'])}" title="${child['grandparent_title']}">
|
||||
<span class="thumb-tooltip" data-toggle="popover" data-img="${page('pms_image_proxy', child['grandparent_thumb'], child['grandparent_rating_key'], 300, 300, fallback='cover')}" data-height="80" data-width="80">
|
||||
${child['grandparent_title']}
|
||||
</span>
|
||||
</a>
|
||||
<span class="text-muted"> (<a class="no-highlight" href="${page('info', child['parent_rating_key'])}" title="${child['parent_title']}">${child['parent_title']}</a>)</span>
|
||||
% elif child['media_type'] == 'photo':
|
||||
<span class="media-type-tooltip" data-toggle="tooltip" title="Photo"><i class="fa fa-picture-o fa-fw"></i></span>
|
||||
<a href="${page('info', child['rating_key'])}" title="${child['title']}">
|
||||
<span class="thumb-tooltip" data-toggle="popover" data-img="${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 300, fallback='cover')}" data-height="80" data-width="80">
|
||||
${child['title']}
|
||||
</span>
|
||||
</a>
|
||||
% if child['grandparent_title']:
|
||||
- <a href="${page('info', child['grandparent_rating_key'])}" title="${child['grandparent_title']}">
|
||||
<span class="thumb-tooltip" data-toggle="popover" data-img="${page('pms_image_proxy', child['grandparent_thumb'], child['grandparent_rating_key'], 300, 300, fallback='cover')}" data-height="80" data-width="80">
|
||||
${child['grandparent_title']}
|
||||
</span>
|
||||
</a>
|
||||
% endif
|
||||
<span class="text-muted"> (<a class="no-highlight" href="${page('info', child['parent_rating_key'])}" title="${child['parent_title']}">${child['parent_title']}</a>)</span>
|
||||
% elif child['media_type'] == 'clip':
|
||||
<span class="media-type-tooltip" data-toggle="tooltip" title="Video"><i class="fa fa-video-camera fa-fw"></i></span>
|
||||
<a href="${page('info', child['rating_key'])}" title="${child['title']}">
|
||||
<span class="thumb-tooltip" data-toggle="popover" data-img="${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 300, fallback='cover')}" data-height="80" data-width="80">
|
||||
${child['title']}
|
||||
</span>
|
||||
</a>
|
||||
<span class="text-muted"> (<a class="no-highlight" href="${page('info', child['parent_rating_key'])}" title="${child['parent_title']}">${child['parent_title']}</a>)</span>
|
||||
% endif
|
||||
</span>
|
||||
% if child['duration']:
|
||||
<span class="item-children-list-item-duration" id="item-children-list-item-duration-${loop.index + 1}">
|
||||
<% f = 'h:mm:ss' if cast_to_int(child['duration']) >= 3600000 else 'm:ss' %>
|
||||
<script>$('#item-children-list-item-duration-${loop.index + 1}').text(moment.utc(${child['duration']}).format("${f}"));</script>
|
||||
</span>
|
||||
% endif
|
||||
</div>
|
||||
% endif
|
||||
% endif
|
||||
</li>
|
||||
% endif
|
||||
% endfor
|
||||
</ul>
|
||||
</div>
|
||||
<script>
|
||||
$('body').tooltip({
|
||||
selector: '[data-toggle="tooltip"]',
|
||||
container: 'body'
|
||||
});
|
||||
$('body').popover({
|
||||
selector: '[data-toggle="popover"]',
|
||||
html: true,
|
||||
container: 'body',
|
||||
trigger: 'hover',
|
||||
placement: 'right',
|
||||
template: '<div class="popover history-thumbnail-popover" role="tooltip"><div class="arrow" style="top: 50%;"></div><div class="popover-content"></div></div>',
|
||||
content: function () {
|
||||
return '<div class="history-thumbnail" style="background-image: url(' + $(this).data('img') + '); height: ' + $(this).data('height') + 'px; width: ' + $(this).data('width') + 'px;" />';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
% endif
|
||||
% endif
|
||||
|
||||
|
@@ -29,6 +29,7 @@ DOCUMENTATION :: END
|
||||
% if data != None:
|
||||
<%
|
||||
from plexpy.common import MEDIA_TYPE_HEADERS
|
||||
from plexpy.helpers import page
|
||||
types = ('movie', 'show', 'artist', 'album')
|
||||
%>
|
||||
% for media_type in types:
|
||||
@@ -45,12 +46,12 @@ DOCUMENTATION :: END
|
||||
<ul class="item-children-instance list-unstyled">
|
||||
% for child in data['results_list'][media_type]:
|
||||
<li>
|
||||
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">
|
||||
<a href="${page('info', child['rating_key'])}" title="${child['title']}">
|
||||
<div class="item-children-poster">
|
||||
% if media_type in ('artist', 'album'):
|
||||
<div class="item-children-poster-face cover-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=300&fallback=cover);"></div>
|
||||
<div class="item-children-poster-face cover-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 300, fallback='cover')});"></div>
|
||||
% else:
|
||||
<div class="item-children-poster-face poster-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450&fallback=poster);"></div>
|
||||
<div class="item-children-poster-face poster-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 450, fallback='poster')});"></div>
|
||||
% endif
|
||||
% if _session['user_group'] == 'admin':
|
||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||
@@ -60,22 +61,22 @@ DOCUMENTATION :: END
|
||||
% if media_type == 'artist':
|
||||
<div class="item-children-instance-text-wrapper cover-item">
|
||||
<h3>
|
||||
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">${child['title']}</a>
|
||||
<a href="${page('info', child['rating_key'])}" title="${child['title']}">${child['title']}</a>
|
||||
</h3>
|
||||
</div>
|
||||
% elif media_type == 'album':
|
||||
<div class="item-children-instance-text-wrapper cover-item">
|
||||
<h3>
|
||||
<a href="info?rating_key=${child['parent_rating_key']}" title="${child['parent_title']}">${child['parent_title']}</a>
|
||||
<a href="${page('info', child['parent_rating_key'])}" title="${child['parent_title']}">${child['parent_title']}</a>
|
||||
</h3>
|
||||
<h3>
|
||||
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">${child['title']}</a>
|
||||
<a href="${page('info', child['rating_key'])}" title="${child['title']}">${child['title']}</a>
|
||||
</h3>
|
||||
</div>
|
||||
% else:
|
||||
<div class="item-children-instance-text-wrapper poster-item">
|
||||
<h3>
|
||||
<a href="info?rating_key=${child['rating_key']}" title="${child['title']}">${child['title']}</a>
|
||||
<a href="${page('info', child['rating_key'])}" title="${child['title']}">${child['title']}</a>
|
||||
</h3>
|
||||
<h3 class="text-muted">${child['year']}</h3>
|
||||
</div>
|
||||
|
@@ -53,6 +53,9 @@ DOCUMENTATION :: END
|
||||
</%doc>
|
||||
|
||||
% if data != None:
|
||||
<%
|
||||
from plexpy.helpers import page
|
||||
%>
|
||||
% if data['results_count'] > 0:
|
||||
% if 'collection' in data['results_list'] and data['results_list']['collection']:
|
||||
<div class="item-children-wrapper">
|
||||
@@ -62,9 +65,9 @@ DOCUMENTATION :: END
|
||||
<ul class="item-children-instance list-unstyled">
|
||||
% for child in data['results_list']['collection']:
|
||||
<li>
|
||||
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
||||
<a href="${page('info', child['rating_key'])}" data-rating_key="${child['rating_key']}" data-library_name="${child['library_name']}">
|
||||
<div class="item-children-poster">
|
||||
<div class="item-children-poster-face poster-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450&fallback=poster);"></div>
|
||||
<div class="item-children-poster-face poster-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 450, fallback='poster')});"></div>
|
||||
% if _session['user_group'] == 'admin':
|
||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||
% endif
|
||||
@@ -87,9 +90,9 @@ DOCUMENTATION :: END
|
||||
<ul class="item-children-instance list-unstyled">
|
||||
% for child in data['results_list']['movie']:
|
||||
<li>
|
||||
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
||||
<a href="${page('info', child['rating_key'])}" data-rating_key="${child['rating_key']}" data-library_name="${child['library_name']}">
|
||||
<div class="item-children-poster">
|
||||
<div class="item-children-poster-face poster-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450&fallback=poster);"></div>
|
||||
<div class="item-children-poster-face poster-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 450, fallback='poster')});"></div>
|
||||
% if _session['user_group'] == 'admin':
|
||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||
% endif
|
||||
@@ -112,9 +115,9 @@ DOCUMENTATION :: END
|
||||
<ul class="item-children-instance list-unstyled">
|
||||
% for child in data['results_list']['show']:
|
||||
<li>
|
||||
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
||||
<a href="${page('info', child['rating_key'])}" data-rating_key="${child['rating_key']}" data-library_name="${child['library_name']}">
|
||||
<div class="item-children-poster">
|
||||
<div class="item-children-poster-face poster-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450&fallback=poster);"></div>
|
||||
<div class="item-children-poster-face poster-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 450, fallback='poster')});"></div>
|
||||
% if _session['user_group'] == 'admin':
|
||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||
% endif
|
||||
@@ -137,9 +140,9 @@ DOCUMENTATION :: END
|
||||
<ul class="item-children-instance list-unstyled">
|
||||
% for child in data['results_list']['season']:
|
||||
<li>
|
||||
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
||||
<a href="${page('info', child['rating_key'])}" data-rating_key="${child['rating_key']}" data-library_name="${child['library_name']}">
|
||||
<div class="item-children-poster">
|
||||
<div class="item-children-poster-face poster-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450&fallback=poster);"></div>
|
||||
<div class="item-children-poster-face poster-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 450, fallback='poster')});"></div>
|
||||
% if _session['user_group'] == 'admin':
|
||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||
% endif
|
||||
@@ -162,9 +165,9 @@ DOCUMENTATION :: END
|
||||
<ul class="item-children-instance list-unstyled">
|
||||
% for child in data['results_list']['episode']:
|
||||
<li>
|
||||
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
||||
<a href="${page('info', child['rating_key'])}" data-rating_key="${child['rating_key']}" data-library_name="${child['library_name']}">
|
||||
<div class="item-children-poster">
|
||||
<div class="item-children-poster-face episode-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=500&height=250&fallback=art);"></div>
|
||||
<div class="item-children-poster-face episode-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 500, 280, fallback='art')});"></div>
|
||||
% if _session['user_group'] == 'admin':
|
||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||
% endif
|
||||
@@ -188,9 +191,9 @@ DOCUMENTATION :: END
|
||||
<ul class="item-children-instance list-unstyled">
|
||||
% for child in data['results_list']['artist']:
|
||||
<li>
|
||||
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
||||
<a href="${page('info', child['rating_key'])}" data-rating_key="${child['rating_key']}" data-library_name="${child['library_name']}">
|
||||
<div class="item-children-poster">
|
||||
<div class="item-children-poster-face cover-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=300&fallback=cover);"></div>
|
||||
<div class="item-children-poster-face cover-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 300, fallback='cover')});"></div>
|
||||
% if _session['user_group'] == 'admin':
|
||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||
% endif
|
||||
@@ -212,9 +215,9 @@ DOCUMENTATION :: END
|
||||
<ul class="item-children-instance list-unstyled">
|
||||
% for child in data['results_list']['album']:
|
||||
<li>
|
||||
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
||||
<a href="${page('info', child['rating_key'])}" data-rating_key="${child['rating_key']}" data-library_name="${child['library_name']}">
|
||||
<div class="item-children-poster">
|
||||
<div class="item-children-poster-face cover-item" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=300&fallback=cover);"></div>
|
||||
<div class="item-children-poster-face cover-item" style="background-image: url(${page('pms_image_proxy', child['thumb'], child['rating_key'], 300, 300, fallback='cover')});"></div>
|
||||
% if _session['user_group'] == 'admin':
|
||||
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
|
||||
% endif
|
||||
@@ -237,9 +240,9 @@ DOCUMENTATION :: END
|
||||
<ul class="item-children-instance list-unstyled">
|
||||
% for child in data['results_list']['track']:
|
||||
<li>
|
||||
<a href="info?rating_key=${child['rating_key']}" id="${child['rating_key']}">
|
||||
<a href="${page('info', child['rating_key'])}" data-rating_key="${child['rating_key']}" data-library_name="${child['library_name']}">
|
||||
<div class="item-children-poster">
|
||||
<div class="item-children-poster-face cover-item" style="background-image: url(pms_image_proxy?img=${child['parent_thumb']}&width=300&height=300&fallback=cover);">
|
||||
<div class="item-children-poster-face cover-item" style="background-image: url(${page('pms_image_proxy', child['parent_thumb'], child['parent_rating_key'], 300, 300, fallback='cover')});">
|
||||
<div class="item-children-card-overlay">
|
||||
<div class="item-children-overlay-text">
|
||||
Track ${child['media_index']}
|
||||
|
@@ -24,7 +24,6 @@
|
||||
<div id="ip_error" class="col-sm-12 text-muted"></div>
|
||||
<div class="col-sm-6">
|
||||
<ul class="list-unstyled">
|
||||
<li>Continent: <strong><span id="continent"></span></strong></li>
|
||||
<li>Country: <strong><span id="country"></span></strong></li>
|
||||
<li>Region: <strong><span id="region"></span></strong></li>
|
||||
<li>City: <strong><span id="city"></span></strong></li>
|
||||
@@ -36,7 +35,6 @@
|
||||
<li>Timezone: <strong><span id="timezone"></span></strong></li>
|
||||
<li>Latitude: <strong><span id="latitude"></span></strong></li>
|
||||
<li>Longitude: <strong><span id="longitude"></span></strong></li>
|
||||
<li>Accuracy Radius: <strong><span id="accuracy"></span></strong></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-sm-12">
|
||||
@@ -61,8 +59,6 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<% from plexpy.helpers import anon_url %>
|
||||
<span class="text-muted">GeoLite2 data created by <a href="${anon_url('http://www.maxmind.com')}" target="_blank">MaxMind</a>.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -82,11 +78,11 @@
|
||||
error: function () {
|
||||
$('#ip_error').html('<i class="fa fa-exclamation-circle"></i> Internal request failed.').show();
|
||||
},
|
||||
success: function (data) {
|
||||
if ('error' in data) {
|
||||
$('#ip_error').html('<i class="fa fa-exclamation-circle"></i> ' + data.error).show();
|
||||
success: function (result) {
|
||||
if (result.result === 'error') {
|
||||
$('#ip_error').html('<i class="fa fa-exclamation-circle"></i> ' + result.message).show();
|
||||
} else {
|
||||
$('#continent').html(data.continent);
|
||||
var data = result.data;
|
||||
$('#country').html(data.country);
|
||||
$('#region').html(data.region);
|
||||
$('#city').html(data.city);
|
||||
@@ -94,7 +90,6 @@
|
||||
$('#timezone').html(data.timezone);
|
||||
$('#latitude').html(data.latitude);
|
||||
$('#longitude').html(data.longitude);
|
||||
$('#accuracy').html(data.accuracy + ' km');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@@ -36,7 +36,3 @@ function check_notifications() {
|
||||
check_notifications();
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
check_notifications();
|
||||
});
|
8
data/interfaces/default/js/bootstrap.min.js
vendored
@@ -790,6 +790,9 @@ ColVis.prototype = {
|
||||
oStyle.top = oPos.top+"px";
|
||||
oStyle.left = iDivX+"px";
|
||||
|
||||
var iDocWidth = $(document).width();
|
||||
var iDocHeight = $(document).height();
|
||||
|
||||
document.body.appendChild( nBackground );
|
||||
document.body.appendChild( nHidden );
|
||||
document.body.appendChild( this.dom.catcher );
|
||||
@@ -819,12 +822,17 @@ ColVis.prototype = {
|
||||
|
||||
var iDivWidth = $(nHidden).outerWidth();
|
||||
var iDivHeight = $(nHidden).outerHeight();
|
||||
var iDocWidth = $(document).width();
|
||||
var iDivMarginTop = parseInt($(nHidden).css("marginTop"), 10);
|
||||
var iDivMarginBottom = parseInt($(nHidden).css("marginBottom"), 10);
|
||||
|
||||
if ( iLeft + iDivWidth > iDocWidth )
|
||||
{
|
||||
nHidden.style.left = (iDocWidth-iDivWidth)+"px";
|
||||
}
|
||||
if ( iDivY + iDivHeight > iDocHeight )
|
||||
{
|
||||
nHidden.style.top = (oPos.top - iDivHeight - iDivMarginTop - iDivMarginBottom)+"px";
|
||||
}
|
||||
}
|
||||
|
||||
this.s.hidden = false;
|
||||
@@ -846,7 +854,8 @@ ColVis.prototype = {
|
||||
this.s.hidden = true;
|
||||
|
||||
$(this.dom.collection).animate({"opacity": 0}, that.s.iOverlayFade, function (e) {
|
||||
this.style.display = "none";
|
||||
// this.style.display = "none";
|
||||
document.body.removeChild( this );
|
||||
} );
|
||||
|
||||
$(this.dom.background).animate({"opacity": 0}, that.s.iOverlayFade, function (e) {
|
||||
|
@@ -40,7 +40,6 @@ var hc_plays_by_day_options = {
|
||||
}
|
||||
}
|
||||
},
|
||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
||||
xAxis: {
|
||||
type: 'datetime',
|
||||
labels: {
|
||||
|
@@ -23,7 +23,6 @@ var hc_plays_by_dayofweek_options = {
|
||||
credits: {
|
||||
enabled: false
|
||||
},
|
||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
||||
xAxis: {
|
||||
categories: [{}],
|
||||
labels: {
|
||||
|
@@ -23,7 +23,6 @@ var hc_plays_by_hourofday_options = {
|
||||
credits: {
|
||||
enabled: false
|
||||
},
|
||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
||||
xAxis: {
|
||||
categories: [{}],
|
||||
labels: {
|
||||
|
@@ -23,7 +23,6 @@ var hc_plays_by_month_options = {
|
||||
credits: {
|
||||
enabled: false
|
||||
},
|
||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
||||
xAxis: {
|
||||
labels: {
|
||||
style: {
|
||||
|
@@ -23,7 +23,6 @@ var hc_plays_by_platform_options = {
|
||||
credits: {
|
||||
enabled: false
|
||||
},
|
||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
||||
xAxis: {
|
||||
categories: [{}],
|
||||
labels: {
|
||||
|
@@ -23,7 +23,6 @@ var hc_plays_by_platform_by_stream_type_options = {
|
||||
credits: {
|
||||
enabled: false
|
||||
},
|
||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
||||
xAxis: {
|
||||
categories: [{}],
|
||||
labels: {
|
||||
|
@@ -23,7 +23,6 @@ var hc_plays_by_source_resolution_options = {
|
||||
credits: {
|
||||
enabled: false
|
||||
},
|
||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
||||
xAxis: {
|
||||
categories: [{}],
|
||||
labels: {
|
||||
|
@@ -23,7 +23,6 @@ var hc_plays_by_stream_resolution_options = {
|
||||
credits: {
|
||||
enabled: false
|
||||
},
|
||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
||||
xAxis: {
|
||||
categories: [{}],
|
||||
labels: {
|
||||
|
@@ -40,7 +40,6 @@ var hc_plays_by_stream_type_options = {
|
||||
}
|
||||
}
|
||||
},
|
||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
||||
xAxis: {
|
||||
type: 'datetime',
|
||||
labels: {
|
||||
|
@@ -23,7 +23,6 @@ var hc_plays_by_user_options = {
|
||||
credits: {
|
||||
enabled: false
|
||||
},
|
||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
||||
xAxis: {
|
||||
categories: [{}],
|
||||
labels: {
|
||||
|
@@ -23,7 +23,6 @@ var hc_plays_by_user_by_stream_type_options = {
|
||||
credits: {
|
||||
enabled: false
|
||||
},
|
||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
||||
xAxis: {
|
||||
categories: [{}],
|
||||
labels: {
|
||||
|
2
data/interfaces/default/js/jquery-3.5.1.min.js
vendored
Normal file
1
data/interfaces/default/js/jquery.inputaffix.min.js
vendored
Normal file
@@ -1,482 +0,0 @@
|
||||
/*! Moment Duration Format v1.3.0
|
||||
* https://github.com/jsmreese/moment-duration-format
|
||||
* Date: 2014-07-15
|
||||
*
|
||||
* Duration format plugin function for the Moment.js library
|
||||
* http://momentjs.com/
|
||||
*
|
||||
* Copyright 2014 John Madhavan-Reese
|
||||
* Released under the MIT license
|
||||
*/
|
||||
|
||||
(function (root, undefined) {
|
||||
|
||||
// repeatZero(qty)
|
||||
// returns "0" repeated qty times
|
||||
function repeatZero(qty) {
|
||||
var result = "";
|
||||
|
||||
// exit early
|
||||
// if qty is 0 or a negative number
|
||||
// or doesn't coerce to an integer
|
||||
qty = parseInt(qty, 10);
|
||||
if (!qty || qty < 1) { return result; }
|
||||
|
||||
while (qty) {
|
||||
result += "0";
|
||||
qty -= 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// padZero(str, len [, isRight])
|
||||
// pads a string with zeros up to a specified length
|
||||
// will not pad a string if its length is aready
|
||||
// greater than or equal to the specified length
|
||||
// default output pads with zeros on the left
|
||||
// set isRight to `true` to pad with zeros on the right
|
||||
function padZero(str, len, isRight) {
|
||||
if (str == null) { str = ""; }
|
||||
str = "" + str;
|
||||
|
||||
return (isRight ? str : "") + repeatZero(len - str.length) + (isRight ? "" : str);
|
||||
}
|
||||
|
||||
// isArray
|
||||
function isArray(array) {
|
||||
return Object.prototype.toString.call(array) === "[object Array]";
|
||||
}
|
||||
|
||||
// isObject
|
||||
function isObject(obj) {
|
||||
return Object.prototype.toString.call(obj) === "[object Object]";
|
||||
}
|
||||
|
||||
// findLast
|
||||
function findLast(array, callback) {
|
||||
var index = array.length;
|
||||
|
||||
while (index -= 1) {
|
||||
if (callback(array[index])) { return array[index]; }
|
||||
}
|
||||
}
|
||||
|
||||
// find
|
||||
function find(array, callback) {
|
||||
var index = 0,
|
||||
max = array.length,
|
||||
match;
|
||||
|
||||
if (typeof callback !== "function") {
|
||||
match = callback;
|
||||
callback = function (item) {
|
||||
return item === match;
|
||||
};
|
||||
}
|
||||
|
||||
while (index < max) {
|
||||
if (callback(array[index])) { return array[index]; }
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// each
|
||||
function each(array, callback) {
|
||||
var index = 0,
|
||||
max = array.length;
|
||||
|
||||
if (!array || !max) { return; }
|
||||
|
||||
while (index < max) {
|
||||
if (callback(array[index], index) === false) { return; }
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// map
|
||||
function map(array, callback) {
|
||||
var index = 0,
|
||||
max = array.length,
|
||||
ret = [];
|
||||
|
||||
if (!array || !max) { return ret; }
|
||||
|
||||
while (index < max) {
|
||||
ret[index] = callback(array[index], index);
|
||||
index += 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// pluck
|
||||
function pluck(array, prop) {
|
||||
return map(array, function (item) {
|
||||
return item[prop];
|
||||
});
|
||||
}
|
||||
|
||||
// compact
|
||||
function compact(array) {
|
||||
var ret = [];
|
||||
|
||||
each(array, function (item) {
|
||||
if (item) { ret.push(item); }
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// unique
|
||||
function unique(array) {
|
||||
var ret = [];
|
||||
|
||||
each(array, function (_a) {
|
||||
if (!find(ret, _a)) { ret.push(_a); }
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// intersection
|
||||
function intersection(a, b) {
|
||||
var ret = [];
|
||||
|
||||
each(a, function (_a) {
|
||||
each(b, function (_b) {
|
||||
if (_a === _b) { ret.push(_a); }
|
||||
});
|
||||
});
|
||||
|
||||
return unique(ret);
|
||||
}
|
||||
|
||||
// rest
|
||||
function rest(array, callback) {
|
||||
var ret = [];
|
||||
|
||||
each(array, function (item, index) {
|
||||
if (!callback(item)) {
|
||||
ret = array.slice(index);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// initial
|
||||
function initial(array, callback) {
|
||||
var reversed = array.slice().reverse();
|
||||
|
||||
return rest(reversed, callback).reverse();
|
||||
}
|
||||
|
||||
// extend
|
||||
function extend(a, b) {
|
||||
for (var key in b) {
|
||||
if (b.hasOwnProperty(key)) { a[key] = b[key]; }
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
// define internal moment reference
|
||||
var moment;
|
||||
|
||||
if (typeof require === "function") {
|
||||
try { moment = require('moment'); }
|
||||
catch (e) {}
|
||||
}
|
||||
|
||||
if (!moment && root.moment) {
|
||||
moment = root.moment;
|
||||
}
|
||||
|
||||
if (!moment) {
|
||||
throw "Moment Duration Format cannot find Moment.js";
|
||||
}
|
||||
|
||||
// moment.duration.format([template] [, precision] [, settings])
|
||||
moment.duration.fn.format = function () {
|
||||
|
||||
var tokenizer, tokens, types, typeMap, momentTypes, foundFirst, trimIndex,
|
||||
args = [].slice.call(arguments),
|
||||
settings = extend({}, this.format.defaults),
|
||||
// keep a shadow copy of this moment for calculating remainders
|
||||
remainder = moment.duration(this);
|
||||
|
||||
// add a reference to this duration object to the settings for use
|
||||
// in a template function
|
||||
settings.duration = this;
|
||||
|
||||
// parse arguments
|
||||
each(args, function (arg) {
|
||||
if (typeof arg === "string" || typeof arg === "function") {
|
||||
settings.template = arg;
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof arg === "number") {
|
||||
settings.precision = arg;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isObject(arg)) {
|
||||
extend(settings, arg);
|
||||
}
|
||||
});
|
||||
|
||||
// types
|
||||
types = settings.types = (isArray(settings.types) ? settings.types : settings.types.split(" "));
|
||||
|
||||
// template
|
||||
if (typeof settings.template === "function") {
|
||||
settings.template = settings.template.apply(settings);
|
||||
}
|
||||
|
||||
// tokenizer regexp
|
||||
tokenizer = new RegExp(map(types, function (type) {
|
||||
return settings[type].source;
|
||||
}).join("|"), "g");
|
||||
|
||||
// token type map function
|
||||
typeMap = function (token) {
|
||||
return find(types, function (type) {
|
||||
return settings[type].test(token);
|
||||
});
|
||||
};
|
||||
|
||||
// tokens array
|
||||
tokens = map(settings.template.match(tokenizer), function (token, index) {
|
||||
var type = typeMap(token),
|
||||
length = token.length;
|
||||
|
||||
return {
|
||||
index: index,
|
||||
length: length,
|
||||
|
||||
// replace escaped tokens with the non-escaped token text
|
||||
token: (type === "escape" ? token.replace(settings.escape, "$1") : token),
|
||||
|
||||
// ignore type on non-moment tokens
|
||||
type: ((type === "escape" || type === "general") ? null : type)
|
||||
|
||||
// calculate base value for all moment tokens
|
||||
//baseValue: ((type === "escape" || type === "general") ? null : this.as(type))
|
||||
};
|
||||
}, this);
|
||||
|
||||
// unique moment token types in the template (in order of descending magnitude)
|
||||
momentTypes = intersection(types, unique(compact(pluck(tokens, "type"))));
|
||||
|
||||
// exit early if there are no momentTypes
|
||||
if (!momentTypes.length) {
|
||||
return pluck(tokens, "token").join("");
|
||||
}
|
||||
|
||||
// calculate values for each token type in the template
|
||||
each(momentTypes, function (momentType, index) {
|
||||
var value, wholeValue, decimalValue, isLeast, isMost;
|
||||
|
||||
// calculate integer and decimal value portions
|
||||
value = remainder.as(momentType);
|
||||
wholeValue = (value > 0 ? Math.floor(value) : Math.ceil(value));
|
||||
decimalValue = value - wholeValue;
|
||||
|
||||
// is this the least-significant moment token found?
|
||||
isLeast = ((index + 1) === momentTypes.length);
|
||||
|
||||
// is this the most-significant moment token found?
|
||||
isMost = (!index);
|
||||
|
||||
// update tokens array
|
||||
// using this algorithm to not assume anything about
|
||||
// the order or frequency of any tokens
|
||||
each(tokens, function (token) {
|
||||
if (token.type === momentType) {
|
||||
extend(token, {
|
||||
value: value,
|
||||
wholeValue: wholeValue,
|
||||
decimalValue: decimalValue,
|
||||
isLeast: isLeast,
|
||||
isMost: isMost
|
||||
});
|
||||
|
||||
if (isMost) {
|
||||
// note the length of the most-significant moment token:
|
||||
// if it is greater than one and forceLength is not set, default forceLength to `true`
|
||||
if (settings.forceLength == null && token.length > 1) {
|
||||
settings.forceLength = true;
|
||||
}
|
||||
|
||||
// rationale is this:
|
||||
// if the template is "h:mm:ss" and the moment value is 5 minutes, the user-friendly output is "5:00", not "05:00"
|
||||
// shouldn't pad the `minutes` token even though it has length of two
|
||||
// if the template is "hh:mm:ss", the user clearly wanted everything padded so we should output "05:00"
|
||||
// if the user wanted the full padded output, they can set `{ trim: false }` to get "00:05:00"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// update remainder
|
||||
remainder.subtract(wholeValue, momentType);
|
||||
});
|
||||
|
||||
// trim tokens array
|
||||
if (settings.trim) {
|
||||
tokens = (settings.trim === "left" ? rest : initial)(tokens, function (token) {
|
||||
// return `true` if:
|
||||
// the token is not the least moment token (don't trim the least moment token)
|
||||
// the token is a moment token that does not have a value (don't trim moment tokens that have a whole value)
|
||||
return !(token.isLeast || (token.type != null && token.wholeValue));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// build output
|
||||
|
||||
// the first moment token can have special handling
|
||||
foundFirst = false;
|
||||
|
||||
// run the map in reverse order if trimming from the right
|
||||
if (settings.trim === "right") {
|
||||
tokens.reverse();
|
||||
}
|
||||
|
||||
tokens = map(tokens, function (token) {
|
||||
var val,
|
||||
decVal;
|
||||
|
||||
if (!token.type) {
|
||||
// if it is not a moment token, use the token as its own value
|
||||
return token.token;
|
||||
}
|
||||
|
||||
// apply negative precision formatting to the least-significant moment token
|
||||
if (token.isLeast && (settings.precision < 0)) {
|
||||
val = (Math.floor(token.wholeValue * Math.pow(10, settings.precision)) * Math.pow(10, -settings.precision)).toString();
|
||||
} else {
|
||||
val = token.wholeValue.toString();
|
||||
}
|
||||
|
||||
// remove negative sign from the beginning
|
||||
val = val.replace(/^\-/, "");
|
||||
|
||||
// apply token length formatting
|
||||
// special handling for the first moment token that is not the most significant in a trimmed template
|
||||
if (token.length > 1 && (foundFirst || token.isMost || settings.forceLength)) {
|
||||
val = padZero(val, token.length);
|
||||
}
|
||||
|
||||
// add decimal value if precision > 0
|
||||
if (token.isLeast && (settings.precision > 0)) {
|
||||
decVal = token.decimalValue.toString().replace(/^\-/, "").split(/\.|e\-/);
|
||||
switch (decVal.length) {
|
||||
case 1:
|
||||
val += "." + padZero(decVal[0], settings.precision, true).slice(0, settings.precision);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
val += "." + padZero(decVal[1], settings.precision, true).slice(0, settings.precision);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
val += "." + padZero(repeatZero((+decVal[2]) - 1) + (decVal[0] || "0") + decVal[1], settings.precision, true).slice(0, settings.precision);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw "Moment Duration Format: unable to parse token decimal value.";
|
||||
}
|
||||
}
|
||||
|
||||
// add a negative sign if the value is negative and token is most significant
|
||||
if (token.isMost && token.value < 0) {
|
||||
val = "-" + val;
|
||||
}
|
||||
|
||||
foundFirst = true;
|
||||
|
||||
return val;
|
||||
});
|
||||
|
||||
// undo the reverse if trimming from the right
|
||||
if (settings.trim === "right") {
|
||||
tokens.reverse();
|
||||
}
|
||||
|
||||
return tokens.join("");
|
||||
};
|
||||
|
||||
moment.duration.fn.format.defaults = {
|
||||
// token definitions
|
||||
escape: /\[(.+?)\]/,
|
||||
years: /[Yy]+/,
|
||||
months: /M+/,
|
||||
weeks: /[Ww]+/,
|
||||
days: /[Dd]+/,
|
||||
hours: /[Hh]+/,
|
||||
minutes: /m+/,
|
||||
seconds: /s+/,
|
||||
milliseconds: /S+/,
|
||||
general: /.+?/,
|
||||
|
||||
// token type names
|
||||
// in order of descending magnitude
|
||||
// can be a space-separated token name list or an array of token names
|
||||
types: "escape years months weeks days hours minutes seconds milliseconds general",
|
||||
|
||||
// format options
|
||||
|
||||
// trim
|
||||
// "left" - template tokens are trimmed from the left until the first moment token that has a value >= 1
|
||||
// "right" - template tokens are trimmed from the right until the first moment token that has a value >= 1
|
||||
// (the final moment token is not trimmed, regardless of value)
|
||||
// `false` - template tokens are not trimmed
|
||||
trim: "left",
|
||||
|
||||
// precision
|
||||
// number of decimal digits to include after (to the right of) the decimal point (positive integer)
|
||||
// or the number of digits to truncate to 0 before (to the left of) the decimal point (negative integer)
|
||||
precision: 0,
|
||||
|
||||
// force first moment token with a value to render at full length even when template is trimmed and first moment token has length of 1
|
||||
forceLength: null,
|
||||
|
||||
// template used to format duration
|
||||
// may be a function or a string
|
||||
// template functions are executed with the `this` binding of the settings object
|
||||
// so that template strings may be dynamically generated based on the duration object
|
||||
// (accessible via `this.duration`)
|
||||
// or any of the other settings
|
||||
template: function () {
|
||||
var types = this.types,
|
||||
dur = this.duration,
|
||||
lastType = findLast(types, function (type) {
|
||||
return dur._data[type];
|
||||
});
|
||||
|
||||
// default template strings for each duration dimension type
|
||||
switch (lastType) {
|
||||
case "seconds":
|
||||
return "h:mm:ss";
|
||||
case "minutes":
|
||||
return "d[d] h:mm";
|
||||
case "hours":
|
||||
return "d[d] h[h]";
|
||||
case "days":
|
||||
return "M[m] d[d]";
|
||||
case "weeks":
|
||||
return "y[y] w[w]";
|
||||
case "months":
|
||||
return "y[y] M[m]";
|
||||
case "years":
|
||||
return "y[y]";
|
||||
default:
|
||||
return "y[y] M[m] d[d] h:mm:ss";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
})(this);
|
11
data/interfaces/default/js/moment-duration-format.min.js
vendored
Normal file
2
data/interfaces/default/js/moment-with-locales.min.js
vendored
Normal file
@@ -237,6 +237,27 @@ function doAjaxCall(url, elem, reload, form, showMsg, callback) {
|
||||
});
|
||||
}
|
||||
|
||||
getBrowsePath = function (key, path, filter_ext) {
|
||||
var deferred = $.Deferred();
|
||||
|
||||
$.ajax({
|
||||
url: 'browse_path',
|
||||
type: 'GET',
|
||||
data: {
|
||||
key: key,
|
||||
path: path,
|
||||
filter_ext: filter_ext
|
||||
},
|
||||
success: function(data) {
|
||||
deferred.resolve(data);
|
||||
},
|
||||
error: function() {
|
||||
deferred.reject();
|
||||
}
|
||||
});
|
||||
return deferred;
|
||||
};
|
||||
|
||||
function doSimpleAjaxCall(url) {
|
||||
$.ajax(url);
|
||||
}
|
||||
@@ -258,33 +279,31 @@ $.cachedScript = function (url) {
|
||||
function isPrivateIP(ip_address) {
|
||||
var defer = $.Deferred();
|
||||
|
||||
$.cachedScript('js/ipaddr.min.js').done(function () {
|
||||
if (ipaddr.isValid(ip_address)) {
|
||||
var addr = ipaddr.process(ip_address);
|
||||
if (ipaddr.isValid(ip_address)) {
|
||||
var addr = ipaddr.process(ip_address);
|
||||
|
||||
var rangeList = [];
|
||||
if (addr.kind() === 'ipv4') {
|
||||
rangeList = [
|
||||
ipaddr.parseCIDR('127.0.0.0/8'),
|
||||
ipaddr.parseCIDR('10.0.0.0/8'),
|
||||
ipaddr.parseCIDR('172.16.0.0/12'),
|
||||
ipaddr.parseCIDR('192.168.0.0/16')
|
||||
];
|
||||
} else {
|
||||
rangeList = [
|
||||
ipaddr.parseCIDR('fd00::/8')
|
||||
];
|
||||
}
|
||||
|
||||
if (ipaddr.subnetMatch(addr, rangeList, -1) >= 0) {
|
||||
defer.resolve();
|
||||
} else {
|
||||
defer.reject();
|
||||
}
|
||||
var rangeList = [];
|
||||
if (addr.kind() === 'ipv4') {
|
||||
rangeList = [
|
||||
ipaddr.parseCIDR('127.0.0.0/8'),
|
||||
ipaddr.parseCIDR('10.0.0.0/8'),
|
||||
ipaddr.parseCIDR('172.16.0.0/12'),
|
||||
ipaddr.parseCIDR('192.168.0.0/16')
|
||||
];
|
||||
} else {
|
||||
defer.resolve('n/a');
|
||||
rangeList = [
|
||||
ipaddr.parseCIDR('fd00::/8')
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
if (ipaddr.subnetMatch(addr, rangeList, -1) >= 0) {
|
||||
defer.resolve();
|
||||
} else {
|
||||
defer.reject();
|
||||
}
|
||||
} else {
|
||||
defer.resolve('n/a');
|
||||
}
|
||||
|
||||
return defer.promise();
|
||||
}
|
||||
@@ -311,31 +330,24 @@ function humanTime(seconds) {
|
||||
}
|
||||
}
|
||||
|
||||
function humanTimeClean(seconds) {
|
||||
var text;
|
||||
if (seconds >= 86400) {
|
||||
text = Math.floor(moment.duration(seconds, 'seconds').asDays()) + ' days ' + Math.floor(moment.duration((
|
||||
seconds % 86400), 'seconds').asHours()) + ' hrs ' + Math.floor(moment.duration(
|
||||
((seconds % 86400) % 3600), 'seconds').asMinutes()) + ' mins';
|
||||
return text;
|
||||
} else if (seconds >= 3600) {
|
||||
text = Math.floor(moment.duration((seconds % 86400), 'seconds').asHours()) + ' hrs ' + Math.floor(moment.duration(
|
||||
((seconds % 86400) % 3600), 'seconds').asMinutes()) + ' mins';
|
||||
return text;
|
||||
} else if (seconds >= 60) {
|
||||
text = Math.floor(moment.duration(((seconds % 86400) % 3600), 'seconds').asMinutes()) + ' mins';
|
||||
return text;
|
||||
} else {
|
||||
text = '0';
|
||||
return text;
|
||||
}
|
||||
}
|
||||
String.prototype.toProperCase = function () {
|
||||
return this.replace(/\w\S*/g, function (txt) {
|
||||
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
|
||||
});
|
||||
};
|
||||
|
||||
function getPercent(value1, value2) {
|
||||
value1 = parseFloat(value1) | 0
|
||||
value2 = parseFloat(value2) | 0
|
||||
|
||||
var percent = 0;
|
||||
if (value1 !== 0 && value2 !== 0) {
|
||||
percent = (value1 / value2) * 100
|
||||
}
|
||||
|
||||
return Math.round(percent)
|
||||
}
|
||||
|
||||
function millisecondsToMinutes(ms, roundToMinute) {
|
||||
if (ms > 0) {
|
||||
var minutes = Math.floor(ms / 60000);
|
||||
@@ -353,6 +365,61 @@ function millisecondsToMinutes(ms, roundToMinute) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function humanDuration(ms, sig='dhm', units='ms', return_seconds=300000) {
|
||||
var factors = {
|
||||
d: 86400000,
|
||||
h: 3600000,
|
||||
m: 60000,
|
||||
s: 1000,
|
||||
ms: 1
|
||||
}
|
||||
|
||||
ms = parseInt(ms);
|
||||
var d, h, m, s;
|
||||
|
||||
if (ms > 0) {
|
||||
if (return_seconds && ms < return_seconds) {
|
||||
sig = 'dhms'
|
||||
}
|
||||
|
||||
ms = ms * factors[units];
|
||||
|
||||
h = ms % factors['d'];
|
||||
d = Math.trunc(ms / factors['d']);
|
||||
|
||||
m = h % factors['h'];
|
||||
h = Math.trunc(h / factors['h']);
|
||||
|
||||
s = m % factors['m'];
|
||||
m = Math.trunc(m / factors['m']);
|
||||
|
||||
ms = s % factors['s'];
|
||||
s = Math.trunc(s / factors['s']);
|
||||
|
||||
var hd_list = [];
|
||||
if (sig >= 'd' && d > 0) {
|
||||
d = (sig === 'd' && h >= 12) ? d + 1 : d;
|
||||
hd_list.push(d.toString() + ' day' + ((d > 1) ? 's' : ''));
|
||||
}
|
||||
if (sig >= 'dh' && h > 0) {
|
||||
h = (sig === 'dh' && m >= 30) ? h + 1 : h;
|
||||
hd_list.push(h.toString() + ' hr' + ((h > 1) ? 's' : ''));
|
||||
}
|
||||
if (sig >= 'dhm' && m > 0) {
|
||||
m = (sig === 'dhm' && s >= 30) ? m + 1 : m;
|
||||
hd_list.push(m.toString() + ' min' + ((m > 1) ? 's' : ''));
|
||||
}
|
||||
if (sig >= 'dhms' && s > 0) {
|
||||
hd_list.push(s.toString() + ' sec' + ((s > 1) ? 's' : ''));
|
||||
}
|
||||
|
||||
return hd_list.join(' ')
|
||||
} else {
|
||||
return '0'
|
||||
}
|
||||
}
|
||||
|
||||
// Our countdown plugin takes a callback, a duration, and an optional message
|
||||
$.fn.countdown = function (callback, duration, message) {
|
||||
// If no message is provided, we use an empty string
|
||||
@@ -463,8 +530,9 @@ $('*').on('click', '.refresh_pms_image', function (e) {
|
||||
});
|
||||
|
||||
// Taken from http://stackoverflow.com/questions/10420352/converting-file-size-in-bytes-to-human-readable#answer-14919494
|
||||
function humanFileSize(bytes, si) {
|
||||
var thresh = si ? 1000 : 1024;
|
||||
function humanFileSize(bytes, si = true) {
|
||||
//var thresh = si ? 1000 : 1024;
|
||||
var thresh = 1024; // Always divide by 2^10 but display SI units
|
||||
if (Math.abs(bytes) < thresh) {
|
||||
return bytes + ' B';
|
||||
}
|
||||
@@ -535,16 +603,18 @@ function PopupCenter(url, title, w, h) {
|
||||
|
||||
|
||||
function setLocalStorage(key, value, path) {
|
||||
var key_path = key;
|
||||
if (path !== false) {
|
||||
key = key + '_' + window.location.pathname;
|
||||
key_path = key_path + '_' + window.location.pathname;
|
||||
}
|
||||
localStorage.setItem(key, value);
|
||||
localStorage.setItem(key_path, value);
|
||||
}
|
||||
function getLocalStorage(key, default_value, path) {
|
||||
var key_path = key;
|
||||
if (path !== false) {
|
||||
key = key + '_' + window.location.pathname;
|
||||
key_path = key_path + '_' + window.location.pathname;
|
||||
}
|
||||
var value = localStorage.getItem(key);
|
||||
var value = localStorage.getItem(key_path);
|
||||
if (value !== null) {
|
||||
return value
|
||||
} else if (default_value !== undefined) {
|
||||
@@ -717,3 +787,82 @@ function encodeData(data) {
|
||||
return [key, data[key]].map(encodeURIComponent).join("=");
|
||||
}).join("&");
|
||||
}
|
||||
|
||||
function page(endpoint, ...args) {
|
||||
let endpoints = {
|
||||
'pms_image_proxy': pms_image_proxy,
|
||||
'info': info_page,
|
||||
'library': library_page,
|
||||
'user': user_page
|
||||
};
|
||||
|
||||
var params = {};
|
||||
|
||||
if (endpoint in endpoints) {
|
||||
params = endpoints[endpoint](...args);
|
||||
}
|
||||
|
||||
return endpoint + '?' + $.param(params).replace(/'/g, '%27');
|
||||
}
|
||||
|
||||
function pms_image_proxy(img, rating_key, width, height, opacity, background, blur, fallback, refresh, clip, img_format) {
|
||||
var params = {};
|
||||
|
||||
if (img != null) { params.img = img; }
|
||||
if (rating_key != null) { params.rating_key = rating_key; }
|
||||
if (width != null) { params.width = width; }
|
||||
if (height != null) { params.height = height; }
|
||||
if (opacity != null) { params.opacity = opacity; }
|
||||
if (background != null) { params.background = background; }
|
||||
if (blur != null) { params.blur = blur; }
|
||||
if (fallback != null) { params.fallback = fallback; }
|
||||
if (refresh != null) { params.refresh = true; }
|
||||
if (clip != null) { params.clip = true; }
|
||||
if (img_format != null) { params.img_format = img_format; }
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
function info_page(rating_key, guid, history, live) {
|
||||
var params = {};
|
||||
|
||||
if (live && history) {
|
||||
params.guid = guid;
|
||||
} else {
|
||||
params.rating_key = rating_key;
|
||||
}
|
||||
|
||||
if (history) { params.source = 'history'; }
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
function library_page(section_id) {
|
||||
var params = {};
|
||||
|
||||
if (section_id != null) { params.section_id = section_id; }
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
function user_page(user_id, user) {
|
||||
var params = {};
|
||||
|
||||
if (user_id != null) { params.user_id = user_id; }
|
||||
if (user != null) { params.user = user; }
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
MEDIA_TYPE_HEADERS = {
|
||||
'movie': 'Movies',
|
||||
'show': 'TV Shows',
|
||||
'season': 'Seasons',
|
||||
'episode': 'Episodes',
|
||||
'artist': 'Artists',
|
||||
'album': 'Albums',
|
||||
'track': 'Tracks',
|
||||
'video': 'Videos',
|
||||
'audio': 'Tracks',
|
||||
'photo': 'Photos'
|
||||
}
|
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Plugin: "disable_options" (selectize.js)
|
||||
* Copyright (c) 2013 Mondo Robot & contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
|
||||
* file except in compliance with the License. You may obtain a copy of the License at:
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under
|
||||
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
* ANY KIND, either express or implied. See the License for the specific language
|
||||
* governing permissions and limitations under the License.
|
||||
*
|
||||
* @authors Jake Myers <jmyers0022@gmail.com>, Vaughn Draughon <vaughn@rocksolidwebdesign.com>
|
||||
*/
|
||||
|
||||
Selectize.define('disable_options', function(options) {
|
||||
var self = this;
|
||||
|
||||
options = $.extend({
|
||||
'disableField': '',
|
||||
'disableOptions': []
|
||||
}, options);
|
||||
|
||||
self.refreshOptions = (function() {
|
||||
var original = self.refreshOptions;
|
||||
|
||||
return function() {
|
||||
original.apply(this, arguments);
|
||||
|
||||
$.each(options.disableOptions, function(index, option) {
|
||||
self.$dropdown_content.find('[data-' + options.disableField + '="' + String(option) + '"]').addClass('option-disabled');
|
||||
});
|
||||
};
|
||||
})();
|
||||
|
||||
self.onOptionSelect = (function() {
|
||||
var original = self.onOptionSelect;
|
||||
|
||||
return function(e) {
|
||||
var value, $target, $option;
|
||||
|
||||
if (e.preventDefault) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
$target = $(e.currentTarget);
|
||||
|
||||
if ($target.hasClass('option-disabled')) {
|
||||
return;
|
||||
}
|
||||
return original.apply(this, arguments);
|
||||
};
|
||||
})();
|
||||
|
||||
self.disabledOptions = function() {
|
||||
return options.disableOptions;
|
||||
}
|
||||
|
||||
self.setDisabledOptions = function( values ) {
|
||||
options.disableOptions = values
|
||||
}
|
||||
|
||||
self.disableOptions = function( values ) {
|
||||
if ( ! ( values instanceof Array ) ) {
|
||||
values = [ values ]
|
||||
}
|
||||
values.forEach( function( val ) {
|
||||
if ( options.disableOptions.indexOf( val ) == -1 ) {
|
||||
options.disableOptions.push( val )
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
self.enableOptions = function( values ) {
|
||||
if ( ! ( values instanceof Array ) ) {
|
||||
values = [ values ]
|
||||
}
|
||||
values.forEach( function( val ) {
|
||||
var remove = options.disableOptions.indexOf( val );
|
||||
if ( remove + 1 ) {
|
||||
options.disableOptions.splice( remove, 1 );
|
||||
}
|
||||
} );
|
||||
}
|
||||
});
|
111
data/interfaces/default/js/tables/collections_table.js
Normal file
@@ -0,0 +1,111 @@
|
||||
collections_table_options = {
|
||||
"destroy": true,
|
||||
"language": {
|
||||
"search": "Search: ",
|
||||
"lengthMenu": "Show _MENU_ entries per page",
|
||||
"info": "Showing _START_ to _END_ of _TOTAL_ collections",
|
||||
"infoEmpty": "Showing 0 to 0 of 0 entries",
|
||||
"infoFiltered": "<span class='hidden-md hidden-sm hidden-xs'>(filtered from _MAX_ total entries)</span>",
|
||||
"emptyTable": "No data in table",
|
||||
"loadingRecords": '<i class="fa fa-refresh fa-spin"></i> Loading items...</div>'
|
||||
},
|
||||
"pagingType": "full_numbers",
|
||||
"stateSave": true,
|
||||
"stateDuration": 0,
|
||||
"processing": false,
|
||||
"serverSide": true,
|
||||
"pageLength": 25,
|
||||
"order": [0, 'asc'],
|
||||
"autoWidth": false,
|
||||
"scrollX": true,
|
||||
"columnDefs": [
|
||||
{
|
||||
"targets": [0],
|
||||
"data": "titleSort",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
var thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['ratingKey'], 300, 450, null, null, null, 'poster') + '" data-height="120" data-width="80">' + rowData['title'] + '</span>';
|
||||
$(td).html('<a href="' + page('info', rowData['ratingKey']) + '"><i class="fa fa-blank fa-fw"></i>' + thumb_popover + '</a>');
|
||||
}
|
||||
},
|
||||
"width": "50%",
|
||||
"className": "no-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [1],
|
||||
"data": "collectionMode",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
var mode = '';
|
||||
if (cellData === -1) {
|
||||
mode = 'Library default';
|
||||
} else if (cellData === 0) {
|
||||
mode = 'Hide collection';
|
||||
} else if (cellData === 1) {
|
||||
mode = 'Hide items in this collection';
|
||||
} else if (cellData === 2) {
|
||||
mode = 'Show this collection and its items';
|
||||
}
|
||||
$(td).html(mode);
|
||||
}
|
||||
},
|
||||
"width": "20%",
|
||||
"className": "no-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [2],
|
||||
"data": "collectionSort",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
var sort = '';
|
||||
if (cellData === 0) {
|
||||
sort = 'Release date';
|
||||
} else if (cellData === 1) {
|
||||
sort = 'Alphabetical';
|
||||
}
|
||||
$(td).html(sort);
|
||||
}
|
||||
},
|
||||
"width": "20%",
|
||||
"className": "no-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [3],
|
||||
"data": "childCount",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
var type = MEDIA_TYPE_HEADERS[rowData['subtype']] || '';
|
||||
if (rowData['childCount'] == 1) {
|
||||
type = type.slice(0, -1);
|
||||
}
|
||||
$(td).html(cellData + ' ' + type);
|
||||
}
|
||||
},
|
||||
"width": "10%",
|
||||
"className": "no-wrap"
|
||||
}
|
||||
],
|
||||
"drawCallback": function (settings) {
|
||||
// Jump to top of page
|
||||
//$('html,body').scrollTop(0);
|
||||
$('#ajaxMsg').fadeOut();
|
||||
|
||||
$('body').popover({
|
||||
selector: '[data-toggle="popover"]',
|
||||
html: true,
|
||||
container: 'body',
|
||||
trigger: 'hover',
|
||||
placement: 'right',
|
||||
template: '<div class="popover history-thumbnail-popover" role="tooltip"><div class="arrow" style="top: 50%;"></div><div class="popover-content"></div></div>',
|
||||
content: function () {
|
||||
return '<div class="history-thumbnail" style="background-image: url(' + $(this).data('img') + '); height: ' + $(this).data('height') + 'px; width: ' + $(this).data('width') + 'px;" />';
|
||||
}
|
||||
});
|
||||
},
|
||||
"preDrawCallback": function(settings) {
|
||||
var msg = "<i class='fa fa-refresh fa-spin'></i> Fetching rows...";
|
||||
showMsg(msg, false, false, 0);
|
||||
},
|
||||
"rowCallback": function (row, rowData, rowIndex) {
|
||||
}
|
||||
};
|
251
data/interfaces/default/js/tables/export_table.js
Normal file
@@ -0,0 +1,251 @@
|
||||
var date_format = 'YYYY-MM-DD';
|
||||
var time_format = 'hh:mm a';
|
||||
|
||||
$.ajax({
|
||||
url: 'get_date_formats',
|
||||
type: 'GET',
|
||||
success: function (data) {
|
||||
date_format = data.date_format;
|
||||
time_format = data.time_format;
|
||||
}
|
||||
});
|
||||
|
||||
export_table_options = {
|
||||
"destroy": true,
|
||||
"language": {
|
||||
"search": "Search: ",
|
||||
"lengthMenu": "Show _MENU_ entries per page",
|
||||
"info": "Showing _START_ to _END_ of _TOTAL_ export items",
|
||||
"infoEmpty": "Showing 0 to 0 of 0 entries",
|
||||
"infoFiltered": "<span class='hidden-md hidden-sm hidden-xs'>(filtered from _MAX_ total entries)</span>",
|
||||
"emptyTable": "No data in table",
|
||||
"loadingRecords": '<i class="fa fa-refresh fa-spin"></i> Loading items...</div>'
|
||||
},
|
||||
"pagingType": "full_numbers",
|
||||
"stateSave": true,
|
||||
"stateDuration": 0,
|
||||
"processing": false,
|
||||
"serverSide": true,
|
||||
"pageLength": 25,
|
||||
"order": [0, 'desc'],
|
||||
"autoWidth": false,
|
||||
"scrollX": true,
|
||||
"columnDefs": [
|
||||
{
|
||||
"targets": [0],
|
||||
"data": "timestamp",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
$(td).html(moment(cellData, "X").format(date_format + ' ' + time_format));
|
||||
}
|
||||
},
|
||||
"width": "8%",
|
||||
"className": "no-wrap",
|
||||
"searchable": false
|
||||
},
|
||||
{
|
||||
"targets": [1],
|
||||
"data": "media_type_title",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
$(td).html(cellData);
|
||||
}
|
||||
},
|
||||
"width": "7%",
|
||||
"className": "no-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [2],
|
||||
"data": "rating_key",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== null) {
|
||||
$(td).html('<a href="' + page('info', rowData['rating_key']) + '">' + cellData + '</a>');
|
||||
}
|
||||
},
|
||||
"width": "6%",
|
||||
"className": "no-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [3],
|
||||
"data": "title",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
var tooltip;
|
||||
var filename;
|
||||
if (!rowData['individual_files']) {
|
||||
tooltip = '<span data-toggle="tooltip" title="Single File"><i class="fa fa-file-alt fa-fw"></i></span>';
|
||||
filename = cellData + '.' + rowData['file_format']
|
||||
} else {
|
||||
tooltip = '<span data-toggle="tooltip" title="Multiple Files"><i class="fa fa-folder fa-fw"></i></span>';
|
||||
filename = cellData
|
||||
}
|
||||
|
||||
if (rowData['complete'] === 1 && rowData['exists'] && !rowData['individual_files']) {
|
||||
$(td).html('<a href="view_export?export_id=' + rowData['export_id'] + '" target="_blank">' + tooltip + ' ' + filename + '</a>');
|
||||
} else {
|
||||
$(td).html(tooltip + ' ' + filename);
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": "40%",
|
||||
"className": "no-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [4],
|
||||
"data": "file_format",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
var images = '';
|
||||
if (rowData['thumb_level'] || rowData['art_level']) {
|
||||
images = ' + images';
|
||||
}
|
||||
$(td).html(cellData + images);
|
||||
}
|
||||
},
|
||||
"width": "7%",
|
||||
"className": "no-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [5],
|
||||
"data": "metadata_level",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== null) {
|
||||
$(td).html(cellData);
|
||||
}
|
||||
},
|
||||
"width": "6%",
|
||||
"className": "no-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [6],
|
||||
"data": "media_info_level",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== null) {
|
||||
$(td).html(cellData);
|
||||
}
|
||||
},
|
||||
"width": "6%",
|
||||
"className": "no-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [7],
|
||||
"data": "custom_fields",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
$(td).html(cellData.replace(/,/g, ', '));
|
||||
}
|
||||
},
|
||||
"width": "6%",
|
||||
"className": "datatable-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [8],
|
||||
"data": "file_size",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '' && cellData !== null) {
|
||||
$(td).html(humanFileSize(cellData));
|
||||
}
|
||||
},
|
||||
"width": "6%",
|
||||
"className": "no-wrap",
|
||||
"searchable": false
|
||||
},
|
||||
{
|
||||
"targets": [9],
|
||||
"data": "complete",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData === 1 && rowData['exists']) {
|
||||
var tooltip_title = '';
|
||||
var icon = '';
|
||||
if (rowData['thumb_level'] || rowData['art_level'] || rowData['individual_files']) {
|
||||
tooltip_title = 'Zip Archive';
|
||||
icon = 'fa-file-archive';
|
||||
} else {
|
||||
tooltip_title = rowData['file_format'].toUpperCase() + ' File';
|
||||
icon = 'fa-file-download';
|
||||
}
|
||||
var icon = (rowData['thumb_level'] || rowData['art_level'] || rowData['individual_files']) ? 'fa-file-archive' : 'fa-file-download';
|
||||
$(td).html('<button class="btn btn-xs btn-success pull-left" data-id="' + rowData['export_id'] + '"><span data-toggle="tooltip" data-placement="left" title="' + tooltip_title + '"><i class="fa ' + icon + ' fa-fw"></i> Download</span></button>');
|
||||
} else if (cellData === 0) {
|
||||
var percent = Math.min(getPercent(rowData['exported_items'], rowData['total_items']), 99)
|
||||
$(td).html('<span class="btn btn-xs btn-dark pull-left export-processing" data-id="' + rowData['export_id'] + '" disabled><i class="fa fa-spinner fa-spin fa-fw"></i> ' + percent + '%</span>');
|
||||
} else if (cellData === -1) {
|
||||
$(td).html('<span class="btn btn-xs btn-dark pull-left" data-id="' + rowData['export_id'] + '" disabled><i class="fa fa-exclamation-circle fa-fw"></i> Failed</span>');
|
||||
} else {
|
||||
$(td).html('<span class="btn btn-xs btn-dark pull-left" data-id="' + rowData['export_id'] + '" disabled><i class="fa fa-question-circle fa-fw"></i> Not Found</span>');
|
||||
}
|
||||
},
|
||||
"width": "7%",
|
||||
"className": "export_download",
|
||||
"searchable": false
|
||||
},
|
||||
{
|
||||
"targets": [10],
|
||||
"data": null,
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (rowData['complete'] !== 0) {
|
||||
$(td).html('<button class="btn btn-xs btn-danger pull-left" data-id="' + rowData['export_id'] + '"><i class="fa fa-trash-o fa-fw"></i> Delete</button>');
|
||||
} else {
|
||||
$(td).html('<span class="btn btn-xs btn-danger pull-left" data-id="' + rowData['export_id'] + '" disabled><i class="fa fa-trash-o fa-fw"></i> Delete</span>');
|
||||
}
|
||||
},
|
||||
"width": "7%",
|
||||
"className": "export_delete",
|
||||
"searchable": false
|
||||
}
|
||||
],
|
||||
"drawCallback": function (settings) {
|
||||
// Jump to top of page
|
||||
//$('html,body').scrollTop(0);
|
||||
$('#ajaxMsg').fadeOut();
|
||||
|
||||
// Create the tooltips.
|
||||
$('body').tooltip({
|
||||
selector: '[data-toggle="tooltip"]',
|
||||
container: 'body'
|
||||
});
|
||||
|
||||
if (export_processing_timer) {
|
||||
clearTimeout(export_processing_timer);
|
||||
}
|
||||
if ($('.export-processing').length) {
|
||||
export_processing_timer = setTimeout(redrawExportTable.bind(null, false), 2000);
|
||||
}
|
||||
},
|
||||
"preDrawCallback": function(settings) {
|
||||
if (!export_processing_timer) {
|
||||
var msg = "<i class='fa fa-refresh fa-spin'></i> Fetching rows...";
|
||||
showMsg(msg, false, false, 0)
|
||||
}
|
||||
},
|
||||
"rowCallback": function (row, rowData, rowIndex) {
|
||||
if (rowData['complete'] === 0) {
|
||||
$(row).addClass('current-activity-row');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$('.export_table').on('click', '> tbody > tr > td.export_download > button', function (e) {
|
||||
var tr = $(this).closest('tr');
|
||||
var row = export_table.row(tr);
|
||||
var rowData = row.data();
|
||||
|
||||
e.preventDefault();
|
||||
window.location.href = 'download_export?export_id=' + rowData['export_id'];
|
||||
});
|
||||
|
||||
$('.export_table').on('click', '> tbody > tr > td.export_delete > button', function (e) {
|
||||
var tr = $(this).closest('tr');
|
||||
var row = export_table.row(tr);
|
||||
var rowData = row.data();
|
||||
|
||||
var msg = 'Are you sure you want to delete the following export?<br /><br /><strong>' + rowData['title'] + '</strong>';
|
||||
var url = 'delete_export?export_id=' + rowData['export_id'];
|
||||
confirmAjaxCall(url, msg, null, null, redrawExportTable);
|
||||
});
|
||||
|
||||
function redrawExportTable(paging) {
|
||||
export_table.draw(paging);
|
||||
}
|
||||
|
||||
var export_processing_timer;
|
@@ -36,10 +36,10 @@ history_table_options = {
|
||||
"targets": [0],
|
||||
"data": null,
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (rowData['id'] === null) {
|
||||
if (rowData['row_id'] === null) {
|
||||
$(td).html('');
|
||||
} else {
|
||||
$(td).html('<button class="btn btn-xs btn-warning" data-id="' + rowData['id'] + '"><i class="fa fa-trash-o fa-fw"></i> Delete</button>');
|
||||
$(td).html('<button class="btn btn-xs btn-warning" data-id="' + rowData['row_id'] + '"><i class="fa fa-trash-o fa-fw"></i> Delete</button>');
|
||||
}
|
||||
},
|
||||
"width": "5%",
|
||||
@@ -49,19 +49,23 @@ history_table_options = {
|
||||
},
|
||||
{
|
||||
"targets": [1],
|
||||
"data":"date",
|
||||
"data": "date",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
var date = moment(cellData, "X").format(date_format);
|
||||
if (rowData['state'] !== null) {
|
||||
var state = '';
|
||||
if (rowData['state'] === 'playing') {
|
||||
state = '<span class="current-activity-tooltip" data-toggle="tooltip" title="Currently Playing"><i class="fa fa-play fa-fw"></i></span>';
|
||||
state = '<span class="current-activity-tooltip" data-toggle="tooltip" title="Currently Playing"><i class="fa fa-fw fa-play"></i></span>';
|
||||
} else if (rowData['state'] === 'paused') {
|
||||
state = '<span class="current-activity-tooltip" data-toggle="tooltip" title="Currently Paused"><i class="fa fa-pause fa-fw"></i></span>';
|
||||
state = '<span class="current-activity-tooltip" data-toggle="tooltip" title="Currently Paused"><i class="fa fa-fw fa-pause"></i></span>';
|
||||
} else if (rowData['state'] === 'buffering') {
|
||||
state = '<span class="current-activity-tooltip" data-toggle="tooltip" title="Currently Buffering"><i class="fa fa-spinner fa-fw"></i></span>';
|
||||
state = '<span class="current-activity-tooltip" data-toggle="tooltip" title="Currently Buffering"><i class="fa fa-fw fa-spinner"></i></span>';
|
||||
} else if (rowData['state'] === 'error') {
|
||||
state = '<span class="current-activity-tooltip" data-toggle="tooltip" title="Playback Error"><i class="fa fa-fw fa-exclamation-triangle"></i></span>';
|
||||
} else if (rowData['state'] === 'stopped') {
|
||||
state = '<span class="current-activity-tooltip" data-toggle="tooltip" title="Currently Stopped"><i class="fa fa-stop fa-fw"></i></span>';
|
||||
state = '<span class="current-activity-tooltip" data-toggle="tooltip" title="Currently Stopped"><i class="fa fa-fw fa-stop"></i></span>';
|
||||
} else {
|
||||
state = '<span class="current-activity-tooltip" data-toggle="tooltip" title="Unknown"><i class="fa fa-fw fa-question-circle"></i></span>';
|
||||
}
|
||||
$(td).html('<div><div style="float: left;">' + state + ' ' + date + '</div></div>');
|
||||
} else if (rowData['group_count'] > 1) {
|
||||
@@ -77,13 +81,13 @@ history_table_options = {
|
||||
},
|
||||
{
|
||||
"targets": [2],
|
||||
"data":"friendly_name",
|
||||
"data": "friendly_name",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
if (rowData['user_id']) {
|
||||
$(td).html('<a href="user?user_id=' + rowData['user_id'] + '">' + cellData + '</a>');
|
||||
$(td).html('<a href="' + page('user', rowData['user_id']) + '" title="' + rowData['user'] + '">' + cellData + '</a>');
|
||||
} else {
|
||||
$(td).html('<a href="user?user=' + rowData['user'] + '">' + cellData + '</a>');
|
||||
$(td).html('<a href="' + page('user', null, rowData['user']) + '" title="' + rowData['user'] + '">' + cellData + '</a>');
|
||||
}
|
||||
} else {
|
||||
$(td).html(cellData);
|
||||
@@ -112,7 +116,7 @@ history_table_options = {
|
||||
},
|
||||
{
|
||||
"targets": [4],
|
||||
"data":"platform",
|
||||
"data": "platform",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
$(td).html(cellData);
|
||||
@@ -123,6 +127,17 @@ history_table_options = {
|
||||
},
|
||||
{
|
||||
"targets": [5],
|
||||
"data": "product",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
$(td).html(cellData);
|
||||
}
|
||||
},
|
||||
"width": "10%",
|
||||
"className": "no-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [6],
|
||||
"data": "player",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
@@ -130,53 +145,63 @@ history_table_options = {
|
||||
if (rowData['transcode_decision'] === 'transcode') {
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Transcode"><i class="fa fa-server fa-fw"></i></span>';
|
||||
} else if (rowData['transcode_decision'] === 'copy') {
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Stream"><i class="fa fa-video-camera fa-fw"></i></span>';
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Stream"><i class="fa fa-stream fa-fw"></i></span>';
|
||||
} else if (rowData['transcode_decision'] === 'direct play') {
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Play"><i class="fa fa-play-circle fa-fw"></i></span>';
|
||||
}
|
||||
$(td).html('<div><a href="#" data-target="#info-modal" data-toggle="modal"><div style="float: left;">' + transcode_dec + ' ' + cellData + '</div></a></div>');
|
||||
}
|
||||
},
|
||||
"width": "12%",
|
||||
"width": "10%",
|
||||
"className": "no-wrap modal-control"
|
||||
},
|
||||
{
|
||||
"targets": [6],
|
||||
"data":"full_title",
|
||||
"targets": [7],
|
||||
"data": "full_title",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
var icon = '';
|
||||
var icon_title = '';
|
||||
var parent_info = '';
|
||||
var media_type = '';
|
||||
var thumb_popover = '';
|
||||
var source = (rowData['state'] === null) ? 'source=history&' : '';
|
||||
var fallback = (rowData['live']) ? 'poster-live' : 'poster';
|
||||
var history = (rowData['state'] === null);
|
||||
if (rowData['media_type'] === 'movie') {
|
||||
icon = (rowData['live']) ? 'fa-broadcast-tower' : 'fa-film';
|
||||
icon_title = (rowData['live']) ? 'Live TV' : 'Movie';
|
||||
if (rowData['year']) { parent_info = ' (' + rowData['year'] + ')'; }
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Movie"><i class="fa fa-film fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
|
||||
$(td).html('<div class="history-title"><a href="info?' + source + 'rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="' + icon_title + '"><i class="fa ' + icon + ' fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, fallback) + '" data-height="120" data-width="80">' + cellData + parent_info + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], history, rowData['live']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'episode') {
|
||||
if (rowData['parent_media_index'] && rowData['media_index']) { parent_info = ' (S' + rowData['parent_media_index'] + '· E' + rowData['media_index'] + ')'; }
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Episode"><i class="fa fa-television fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
|
||||
$(td).html('<div class="history-title"><a href="info?' + source + 'rating_key=' + rowData['rating_key'] + '"><div style="float: left;" >' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
icon = (rowData['live']) ? 'fa-broadcast-tower' : 'fa-television';
|
||||
icon_title = (rowData['live']) ? 'Live TV' : 'Episode';
|
||||
if (!isNaN(parseInt(rowData['parent_media_index'])) && !isNaN(parseInt(rowData['media_index']))) { parent_info = ' (S' + rowData['parent_media_index'] + ' · E' + rowData['media_index'] + ')'; }
|
||||
else if (rowData['live'] && rowData['originally_available_at']) { parent_info = ' (' + rowData['originally_available_at'] + ')'; }
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="' + icon_title + '"><i class="fa ' + icon + ' fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, fallback) + '" data-height="120" data-width="80">' + cellData + parent_info + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], history, rowData['live']) + '"><div style="float: left;" >' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'track') {
|
||||
if (rowData['parent_title']) { parent_info = ' (' + rowData['parent_title'] + ')'; }
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=300&fallback=cover" data-height="80" data-width="80">' + cellData + parent_info + '</span>'
|
||||
$(td).html('<div class="history-title"><a href="info?' + source + 'rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 300, null, null, null, 'cover') + '" data-height="80" data-width="80">' + cellData + parent_info + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], history, rowData['live']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'clip') {
|
||||
$(td).html(cellData);
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Clip"><i class="fa fa-video-camera fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, fallback) + '" data-height="120" data-width="80">' + cellData + parent_info + '</span>';
|
||||
$(td).html('<div class="history-title"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></div>');
|
||||
} else {
|
||||
$(td).html('<a href="info?rating_key=' + rowData['rating_key'] + '">' + cellData + '</a>');
|
||||
$(td).html('<a href="' + page('info', rowData['rating_key']) + '">' + cellData + '</a>');
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": "33%",
|
||||
"width": "25%",
|
||||
"className": "datatable-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [7],
|
||||
"data":"started",
|
||||
"targets": [8],
|
||||
"data": "started",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData === null) {
|
||||
$(td).html('n/a');
|
||||
@@ -189,8 +214,8 @@ history_table_options = {
|
||||
"className": "no-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [8],
|
||||
"data":"paused_counter",
|
||||
"targets": [9],
|
||||
"data": "paused_counter",
|
||||
"render": function (data, type, full) {
|
||||
if (data !== null) {
|
||||
return Math.round(moment.duration(data, 'seconds').as('minutes')) + ' mins';
|
||||
@@ -203,8 +228,8 @@ history_table_options = {
|
||||
"className": "no-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [9],
|
||||
"data":"stopped",
|
||||
"targets": [10],
|
||||
"data": "stopped",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData === null || (rowData['state'] != null && rowData['state'] != "stopped")) {
|
||||
$(td).html('n/a');
|
||||
@@ -217,8 +242,8 @@ history_table_options = {
|
||||
"className": "no-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [10],
|
||||
"data":"duration",
|
||||
"targets": [11],
|
||||
"data": "duration",
|
||||
"render": function (data, type, full) {
|
||||
if (data !== null) {
|
||||
return Math.round(moment.duration(data, 'seconds').as('minutes')) + ' mins';
|
||||
@@ -231,7 +256,7 @@ history_table_options = {
|
||||
"className": "no-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [11],
|
||||
"targets": [12],
|
||||
"data": "watched_status",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData == 1) {
|
||||
@@ -298,19 +323,19 @@ history_table_options = {
|
||||
"rowCallback": function (row, rowData, rowIndex) {
|
||||
if (rowData['group_count'] == 1) {
|
||||
// if no grouped rows simply toggle the delete button
|
||||
if ($.inArray(rowData['id'], history_to_delete) !== -1) {
|
||||
$(row).find('button[data-id="' + rowData['id'] + '"]').toggleClass('btn-warning').toggleClass('btn-danger');
|
||||
if ($.inArray(rowData['row_id'], history_to_delete) !== -1) {
|
||||
$(row).find('button[data-id="' + rowData['row_id'] + '"]').toggleClass('btn-warning').toggleClass('btn-danger');
|
||||
}
|
||||
} else if (rowData['id'] !== null) {
|
||||
} else if (rowData['row_id'] !== null) {
|
||||
// if grouped rows
|
||||
// toggle the parent button to danger
|
||||
$(row).find('button[data-id="' + rowData['id'] + '"]').toggleClass('btn-warning').toggleClass('btn-danger');
|
||||
$(row).find('button[data-id="' + rowData['row_id'] + '"]').toggleClass('btn-warning').toggleClass('btn-danger');
|
||||
// check if any child rows are not selected
|
||||
var group_ids = rowData['group_ids'].split(',').map(Number);
|
||||
group_ids.forEach(function (id) {
|
||||
var index = $.inArray(id, history_to_delete);
|
||||
if (index == -1) {
|
||||
$(row).find('button[data-id="' + rowData['id'] + '"]').addClass('btn-warning').removeClass('btn-danger');
|
||||
$(row).find('button[data-id="' + rowData['row_id'] + '"]').addClass('btn-warning').removeClass('btn-danger');
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -334,7 +359,7 @@ $('.history_table').on('click', '> tbody > tr > td.modal-control', function () {
|
||||
var rowData = row.data();
|
||||
|
||||
$.get('get_stream_data', {
|
||||
row_id: rowData['id'],
|
||||
row_id: rowData['row_id'],
|
||||
session_key: rowData['session_key'],
|
||||
user: rowData['friendly_name']
|
||||
}).then(function (jqXHR) {
|
||||
@@ -363,9 +388,9 @@ $('.history_table').on('click', '> tbody > tr > td.delete-control > button', fun
|
||||
|
||||
if (rowData['group_count'] == 1) {
|
||||
// if no grouped rows simply add or remove row from history_to_delete
|
||||
var index = $.inArray(rowData['id'], history_to_delete);
|
||||
var index = $.inArray(rowData['row_id'], history_to_delete);
|
||||
if (index === -1) {
|
||||
history_to_delete.push(rowData['id']);
|
||||
history_to_delete.push(rowData['row_id']);
|
||||
} else {
|
||||
history_to_delete.splice(index, 1);
|
||||
}
|
||||
@@ -489,7 +514,8 @@ function childTableFormat(rowData) {
|
||||
'<th align="left" id="friendly_name">User</th>' +
|
||||
'<th align="left" id="ip_address">IP Address</th>' +
|
||||
'<th align="left" id="platform">Platform</th>' +
|
||||
'<th align="left" id="platform">Player</th>' +
|
||||
'<th align="left" id="product">Product</th>' +
|
||||
'<th align="left" id="player">Player</th>' +
|
||||
'<th align="left" id="title">Title</th>' +
|
||||
'<th align="left" id="started">Started</th>' +
|
||||
'<th align="left" id="paused_counter">Paused</th>' +
|
||||
@@ -529,7 +555,7 @@ function createChildTable(row, rowData) {
|
||||
var childRowData = childRow.data();
|
||||
|
||||
$.get('get_stream_data', {
|
||||
row_id: childRowData['id'],
|
||||
row_id: childRowData['row_id'],
|
||||
user: childRowData['friendly_name']
|
||||
}).then(function (jqXHR) {
|
||||
$("#info-modal").html(jqXHR);
|
||||
@@ -556,9 +582,9 @@ function createChildTable(row, rowData) {
|
||||
var childRowData = childRow.data();
|
||||
|
||||
// add or remove row from history_to_delete
|
||||
var index = $.inArray(childRowData['id'], history_to_delete);
|
||||
var index = $.inArray(childRowData['row_id'], history_to_delete);
|
||||
if (index === -1) {
|
||||
history_to_delete.push(childRowData['id']);
|
||||
history_to_delete.push(childRowData['row_id']);
|
||||
} else {
|
||||
history_to_delete.splice(index, 1);
|
||||
}
|
||||
|
@@ -63,9 +63,9 @@ history_table_modal_options = {
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
if (rowData['user_id']) {
|
||||
$(td).html('<a href="user?user_id=' + rowData['user_id'] + '">' + cellData + '</a>');
|
||||
$(td).html('<a href="' + page('user', rowData['user_id']) + '">' + cellData + '</a>');
|
||||
} else {
|
||||
$(td).html('<a href="user?user=' + rowData['user'] + '">' + cellData + '</a>');
|
||||
$(td).html('<a href="' + page('user', null, rowData['user']) + '">' + cellData + '</a>');
|
||||
}
|
||||
} else {
|
||||
$(td).html(cellData);
|
||||
@@ -83,7 +83,7 @@ history_table_modal_options = {
|
||||
if (rowData['transcode_decision'] === 'transcode') {
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Transcode"><i class="fa fa-server fa-fw"></i></span>';
|
||||
} else if (rowData['transcode_decision'] === 'copy') {
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Stream"><i class="fa fa-video-camera fa-fw"></i></span>';
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Stream"><i class="fa fa-stream fa-fw"></i></span>';
|
||||
} else if (rowData['transcode_decision'] === 'direct play') {
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Play"><i class="fa fa-play-circle fa-fw"></i></span>';
|
||||
}
|
||||
@@ -98,26 +98,34 @@ history_table_modal_options = {
|
||||
"data":"full_title",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
var icon = '';
|
||||
var icon_title = '';
|
||||
var parent_info = '';
|
||||
var media_type = '';
|
||||
var thumb_popover = '';
|
||||
var fallback = (rowData['live']) ? 'poster-live' : 'poster';
|
||||
if (rowData['media_type'] === 'movie') {
|
||||
icon = (rowData['live']) ? 'fa-broadcast-tower' : 'fa-film';
|
||||
icon_title = (rowData['live']) ? 'Live TV' : 'Movie';
|
||||
if (rowData['year']) { parent_info = ' (' + rowData['year'] + ')'; }
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Movie"><i class="fa fa-film fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
|
||||
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="' + icon_title + '"><i class="fa ' + icon + ' fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, fallback) + '" data-height="120" data-width="80">' + cellData + parent_info + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], true, rowData['live']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'episode') {
|
||||
if (rowData['parent_media_index'] && rowData['media_index']) { parent_info = ' (S' + rowData['parent_media_index'] + '· E' + rowData['media_index'] + ')'; }
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Episode"><i class="fa fa-television fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
|
||||
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;" >' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
icon = (rowData['live']) ? 'fa-broadcast-tower' : 'fa-television';
|
||||
icon_title = (rowData['live']) ? 'Live TV' : 'Episode';
|
||||
if (!isNaN(parseInt(rowData['parent_media_index'])) && !isNaN(parseInt(rowData['media_index']))) { parent_info = ' (S' + rowData['parent_media_index'] + ' · E' + rowData['media_index'] + ')'; }
|
||||
else if (rowData['live'] && rowData['originally_available_at']) { parent_info = ' (' + rowData['originally_available_at'] + ')'; }
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="' + icon_title + '"><i class="fa ' + icon + ' fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, fallback) + '" data-height="120" data-width="80">' + cellData + parent_info + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], true, rowData['live']) + '"><div style="float: left;" >' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'track') {
|
||||
if (rowData['parent_title']) { parent_info = ' (' + rowData['parent_title'] + ')'; }
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=300&fallback=cover" data-height="80" data-width="80">' + cellData + parent_info + '</span>'
|
||||
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 300, null, null, null, 'cover') + '" data-height="80" data-width="80">' + cellData + parent_info + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], true, rowData['live']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else {
|
||||
$(td).html('<a href="info?rating_key=' + rowData['rating_key'] + '">' + cellData + '</a>');
|
||||
$(td).html('<a href="' + page('info', rowData['rating_key']) + '">' + cellData + '</a>');
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -161,7 +169,7 @@ $('.history_table').on('click', 'td.modal-control', function () {
|
||||
function showStreamDetails() {
|
||||
$.ajax({
|
||||
url: 'get_stream_data',
|
||||
data: { row_id: rowData['id'], user: rowData['friendly_name'] },
|
||||
data: { row_id: rowData['row_id'], user: rowData['friendly_name'] },
|
||||
cache: false,
|
||||
async: true,
|
||||
complete: function (xhr, status) {
|
||||
|
@@ -27,8 +27,8 @@ libraries_list_table_options = {
|
||||
"data": null,
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
$(td).html('<div class="edit-library-toggles">' +
|
||||
'<button class="btn btn-xs btn-warning delete-library" data-id="' + rowData['section_id'] + '" data-toggle="button"><i class="fa fa-trash-o fa-fw"></i> Delete</button> ' +
|
||||
'<button class="btn btn-xs btn-warning purge-library" data-id="' + rowData['section_id'] + '" data-toggle="button"><i class="fa fa-eraser fa-fw"></i> Purge</button>   ' +
|
||||
'<button class="btn btn-xs btn-warning delete-library" data-id="' + rowData['row_id'] + '" data-toggle="button"><i class="fa fa-trash-o fa-fw"></i> Delete</button> ' +
|
||||
'<button class="btn btn-xs btn-warning purge-library" data-id="' + rowData['row_id'] + '" data-toggle="button"><i class="fa fa-eraser fa-fw"></i> Purge</button>   ' +
|
||||
'<input type="checkbox" id="keep_history-' + rowData['section_id'] + '" name="keep_history" value="1" ' + rowData['keep_history'] + '><label class="edit-tooltip" for="keep_history-' + rowData['section_id'] + '" data-toggle="tooltip" title="Toggle History"><i class="fa fa-history fa-lg fa-fw"></i></label> ' +
|
||||
'</div>');
|
||||
},
|
||||
@@ -41,14 +41,16 @@ libraries_list_table_options = {
|
||||
"targets": [1],
|
||||
"data": "library_thumb",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
var inactive = '';
|
||||
if (!rowData['is_active']) { inactive = '<span class="inactive-library-tooltip" data-toggle="tooltip" title="Library not on Plex server"><i class="fa fa-exclamation-triangle"></i></span>'; }
|
||||
if (cellData !== null && cellData !== '') {
|
||||
if (rowData['library_thumb'].substring(0, 4) == "http") {
|
||||
$(td).html('<a href="library?section_id=' + rowData['section_id'] + '"><div class="libraries-poster-face" style="background-image: url(' + rowData['library_thumb'] + ');"></div></a>');
|
||||
$(td).html('<a href="' + page('library', rowData['section_id']) + '"><div class="libraries-poster-face" style="background-image: url(' + rowData['library_thumb'] + ');">' + inactive + '</div></a>');
|
||||
} else {
|
||||
$(td).html('<a href="library?section_id=' + rowData['section_id'] + '"><div class="libraries-poster-face svg-icon library-' + rowData['section_type'] + '"></div></a>');
|
||||
$(td).html('<a href="' + page('library', rowData['section_id']) + '"><div class="libraries-poster-face svg-icon library-' + rowData['section_type'] + '">' + inactive + '</div></a>');
|
||||
}
|
||||
} else {
|
||||
$(td).html('<a href="library?section_id=' + rowData['section_id'] + '"><div class="libraries-poster-face" style="background-image: url(../../images/cover.png);"></div></a>');
|
||||
$(td).html('<a href="' + page('library', rowData['section_id']) + '"><div class="libraries-poster-face" style="background-image: url(../../images/cover.png);">' + inactive + '</div></a>');
|
||||
}
|
||||
},
|
||||
"orderable": false,
|
||||
@@ -61,8 +63,8 @@ libraries_list_table_options = {
|
||||
"data": "section_name",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== null && cellData !== '') {
|
||||
$(td).html('<div data-id="' + rowData['section_id'] + '">' +
|
||||
'<a href="library?section_id=' + rowData['section_id'] + '">' + cellData + '</a>' +
|
||||
$(td).html('<div data-id="' + rowData['row_id'] + '">' +
|
||||
'<a href="' + page('library', rowData['section_id']) + '">' + cellData + '</a>' +
|
||||
'</div>');
|
||||
} else {
|
||||
$(td).html('n/a');
|
||||
@@ -137,45 +139,34 @@ libraries_list_table_options = {
|
||||
"data":"last_played",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== null && cellData !== '') {
|
||||
var icon = '';
|
||||
var icon_title = '';
|
||||
var parent_info = '';
|
||||
var media_type = '';
|
||||
var thumb_popover = '';
|
||||
var fallback = (rowData['live']) ? 'poster-live' : 'poster';
|
||||
if (rowData['media_type'] === 'movie') {
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Movie"><i class="fa fa-film fa-fw"></i></span>';
|
||||
if (rowData['rating_key']) {
|
||||
if (rowData['year']) { parent_info = ' (' + rowData['year'] + ')'; }
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
|
||||
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else {
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="images/poster.png" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
|
||||
$(td).html('<div class="history-title"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></div>');
|
||||
}
|
||||
icon = (rowData['live']) ? 'fa-broadcast-tower' : 'fa-film';
|
||||
icon_title = (rowData['live']) ? 'Live TV' : 'Movie';
|
||||
if (rowData['year']) { parent_info = ' (' + rowData['year'] + ')'; }
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="' + icon_title + '"><i class="fa ' + icon + ' fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, fallback) + '" data-height="120" data-width="80">' + cellData + parent_info + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], true, rowData['live']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'episode') {
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Episode"><i class="fa fa-television fa-fw"></i></span>';
|
||||
if (rowData['rating_key']) {
|
||||
if (rowData['parent_media_index'] && rowData['media_index']) { parent_info = ' (S' + rowData['parent_media_index'] + '· E' + rowData['media_index'] + ')'; }
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
|
||||
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;" >' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else {
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="images/poster.png" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
|
||||
$(td).html('<div class="history-title"><div style="float: left;" >' + media_type + ' ' + thumb_popover + '</div></div>');
|
||||
}
|
||||
icon = (rowData['live']) ? 'fa-broadcast-tower' : 'fa-television';
|
||||
icon_title = (rowData['live']) ? 'Live TV' : 'Episode';
|
||||
if (!isNaN(parseInt(rowData['parent_media_index'])) && !isNaN(parseInt(rowData['media_index']))) { parent_info = ' (S' + rowData['parent_media_index'] + ' · E' + rowData['media_index'] + ')'; }
|
||||
else if (rowData['live'] && rowData['originally_available_at']) { parent_info = ' (' + rowData['originally_available_at'] + ')'; }
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="' + icon_title + '"><i class="fa ' + icon + ' fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, fallback) + '" data-height="120" data-width="80">' + cellData + parent_info + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], true, rowData['live']) + '"><div style="float: left;" >' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'track') {
|
||||
if (rowData['parent_title']) { parent_info = ' (' + rowData['parent_title'] + ')'; }
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>';
|
||||
if (rowData['rating_key']) {
|
||||
if (rowData['parent_title']) { parent_info = ' (' + rowData['parent_title'] + ')'; }
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=300&fallback=cover" data-height="80" data-width="80">' + cellData + parent_info + '</span>'
|
||||
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else {
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="images/cover.png" data-height="80" data-width="80">' + cellData + parent_info + '</span>'
|
||||
$(td).html('<div class="history-title"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></div>');
|
||||
}
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 300, null, null, null, 'cover') + '" data-height="80" data-width="80">' + cellData + parent_info + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], true, rowData['live']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type']) {
|
||||
if (rowData['rating_key']) {
|
||||
$(td).html('<a href="info?rating_key=' + rowData['rating_key'] + '">' + cellData + '</a>');
|
||||
} else {
|
||||
$(td).html(cellData);
|
||||
}
|
||||
$(td).html('<a href="' + page('info', rowData['rating_key']) + '">' + cellData + '</a>');
|
||||
}
|
||||
} else {
|
||||
$(td).html('n/a');
|
||||
@@ -201,7 +192,7 @@ libraries_list_table_options = {
|
||||
"data": "duration",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== null && cellData !== '') {
|
||||
$(td).html(humanTimeClean(cellData));
|
||||
$(td).html(humanDuration(cellData, 'dhm', 's'));
|
||||
}
|
||||
},
|
||||
"searchable": false,
|
||||
@@ -243,11 +234,11 @@ libraries_list_table_options = {
|
||||
showMsg(msg, false, false, 0)
|
||||
},
|
||||
"rowCallback": function (row, rowData) {
|
||||
if ($.inArray(rowData['section_id'], libraries_to_delete) !== -1) {
|
||||
$(row).find('button.delete-library[data-id="' + rowData['section_id'] + '"]').toggleClass('btn-warning').toggleClass('btn-danger');
|
||||
if ($.inArray(rowData['row_id'], libraries_to_delete) !== -1) {
|
||||
$(row).find('button.delete-library[data-id="' + rowData['row_id'] + '"]').toggleClass('btn-warning').toggleClass('btn-danger');
|
||||
}
|
||||
if ($.inArray(rowData['section_id'], libraries_to_purge) !== -1) {
|
||||
$(row).find('button.purge-library[data-id="' + rowData['section_id'] + '"]').toggleClass('btn-warning').toggleClass('btn-danger');
|
||||
if ($.inArray(rowData['row_id'], libraries_to_purge) !== -1) {
|
||||
$(row).find('button.purge-library[data-id="' + rowData['row_id'] + '"]').toggleClass('btn-warning').toggleClass('btn-danger');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -288,11 +279,11 @@ $('#libraries_list_table').on('click', 'td.edit-control > .edit-library-toggles
|
||||
var row = libraries_list_table.row(tr);
|
||||
var rowData = row.data();
|
||||
|
||||
var index_delete = $.inArray(rowData['section_id'], libraries_to_delete);
|
||||
var index_purge = $.inArray(rowData['section_id'], libraries_to_purge);
|
||||
var index_delete = $.inArray(rowData['row_id'], libraries_to_delete);
|
||||
var index_purge = $.inArray(rowData['row_id'], libraries_to_purge);
|
||||
|
||||
if (index_delete === -1) {
|
||||
libraries_to_delete.push(rowData['section_id']);
|
||||
libraries_to_delete.push(rowData['row_id']);
|
||||
if (index_purge === -1) {
|
||||
tr.find('button.purge-library').click();
|
||||
}
|
||||
@@ -311,11 +302,11 @@ $('#libraries_list_table').on('click', 'td.edit-control > .edit-library-toggles
|
||||
var row = libraries_list_table.row(tr);
|
||||
var rowData = row.data();
|
||||
|
||||
var index_delete = $.inArray(rowData['section_id'], libraries_to_delete);
|
||||
var index_purge = $.inArray(rowData['section_id'], libraries_to_purge);
|
||||
var index_delete = $.inArray(rowData['row_id'], libraries_to_delete);
|
||||
var index_purge = $.inArray(rowData['row_id'], libraries_to_purge);
|
||||
|
||||
if (index_purge === -1) {
|
||||
libraries_to_purge.push(rowData['section_id']);
|
||||
libraries_to_purge.push(rowData['row_id']);
|
||||
} else {
|
||||
libraries_to_purge.splice(index_purge, 1);
|
||||
if (index_delete != -1) {
|
||||
|
@@ -50,7 +50,7 @@ media_info_table_options = {
|
||||
expand_details = '<span class="expand-media-info-tooltip" data-toggle="tooltip" title="Show Episodes"><i class="fa fa-plus-circle fa-fw"></i></span>';
|
||||
$(td).html('<div><a href="#"><div style="float: left;">' + expand_details + ' ' + date + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'artist') {
|
||||
expand_details = '<span class="expand-media-info-tooltip" data-toggle="tooltip" title="Show Albumns"><i class="fa fa-plus-circle fa-fw"></i></span>';
|
||||
expand_details = '<span class="expand-media-info-tooltip" data-toggle="tooltip" title="Show Albums"><i class="fa fa-plus-circle fa-fw"></i></span>';
|
||||
$(td).html('<div><a href="#"><div style="float: left;">' + expand_details + ' ' + date + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'album') {
|
||||
expand_details = '<span class="expand-media-info-tooltip" data-toggle="tooltip" title="Show Tracks"><i class="fa fa-plus-circle fa-fw"></i></span>';
|
||||
@@ -78,44 +78,44 @@ media_info_table_options = {
|
||||
if (rowData['media_type'] === 'movie') {
|
||||
if (rowData['year']) { parent_info = ' (' + rowData['year'] + ')'; }
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Movie"><i class="fa fa-film fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + rowData['title'] + parent_info + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="info?rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, 'poster') + '" data-height="120" data-width="80">' + rowData['title'] + parent_info + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'show') {
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="TV Show"><i class="fa fa-television fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + rowData['title'] + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="info?rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, 'poster') + '" data-height="120" data-width="80">' + rowData['title'] + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'season') {
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Season"><i class="fa fa-television fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + rowData['title'] + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="info?rating_key=' + rowData['rating_key'] + '"><div style="float: left; padding-left: 15px;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, 'poster') + '" data-height="120" data-width="80">' + rowData['title'] + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key']) + '"><div style="float: left; padding-left: 15px;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'episode') {
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Episode"><i class="fa fa-television fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=art" data-height="80" data-width="140">E' + rowData['media_index'] + ' - ' + rowData['title'] + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="info?rating_key=' + rowData['rating_key'] + '"><div style="float: left; padding-left: 30px;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 500, 280, null, null, null, 'art') + '" data-height="80" data-width="140">E' + rowData['media_index'] + ' - ' + rowData['title'] + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key']) + '"><div style="float: left; padding-left: 30px;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'artist') {
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Artist"><i class="fa fa-music fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=300&fallback=cover" data-height="80" data-width="80">' + rowData['title'] + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="info?rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 300, null, null, null, 'cover') + '" data-height="80" data-width="80">' + rowData['title'] + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'album') {
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Album"><i class="fa fa-music fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=300&fallback=cover" data-height="80" data-width="80">' + rowData['title'] + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="info?rating_key=' + rowData['rating_key'] + '"><div style="float: left; padding-left: 15px;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 300, null, null, null, 'cover') + '" data-height="80" data-width="80">' + rowData['title'] + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key']) + '"><div style="float: left; padding-left: 15px;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'track') {
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=300&fallback=cover" data-height="80" data-width="80">T' + rowData['media_index'] + ' - ' + rowData['title'] + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="info?rating_key=' + rowData['rating_key'] + '"><div style="float: left; padding-left: 30px;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 300, null, null, null, 'cover') + '" data-height="80" data-width="80">T' + rowData['media_index'] + ' - ' + rowData['title'] + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key']) + '"><div style="float: left; padding-left: 30px;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'photo_album') {
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Photo Album"><i class="fa fa-camera fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + rowData['title'] + '</span>';
|
||||
$(td).html('<div class="history-title"><div style="float: left; padding-left: 15px;">' + media_type + ' ' + thumb_popover + '</div></div>');
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, 'poster') + '" data-height="120" data-width="80">' + rowData['title'] + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'photo') {
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Photo"><i class="fa fa-picture-o fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + rowData['title'] + '</span>';
|
||||
$(td).html('<div class="history-title"><div style="float: left; padding-left: 15px;">' + media_type + ' ' + thumb_popover + '</div></div>');
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, 'poster') + '" data-height="120" data-width="80">' + rowData['title'] + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key']) + '"><div style="float: left; padding-left: 15px;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'clip') {
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Video"><i class="fa fa-video-camera fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=art" data-height="80" data-width="140">' + rowData['title'] + '</span>';
|
||||
$(td).html('<div class="history-title"><div style="float: left; padding-left: 15px;">' + media_type + ' ' + thumb_popover + '</div></div>');
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 500, 280, null, null, null, 'art') + '" data-height="80" data-width="140">' + rowData['title'] + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key']) + '"><div style="float: left; padding-left: 15px;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else {
|
||||
$(td).html(cellData);
|
||||
}
|
||||
|
100
data/interfaces/default/js/tables/playlists_table.js
Normal file
@@ -0,0 +1,100 @@
|
||||
playlists_table_options = {
|
||||
"destroy": true,
|
||||
"language": {
|
||||
"search": "Search: ",
|
||||
"lengthMenu": "Show _MENU_ entries per page",
|
||||
"info": "Showing _START_ to _END_ of _TOTAL_ playlists",
|
||||
"infoEmpty": "Showing 0 to 0 of 0 entries",
|
||||
"infoFiltered": "<span class='hidden-md hidden-sm hidden-xs'>(filtered from _MAX_ total entries)</span>",
|
||||
"emptyTable": "No data in table",
|
||||
"loadingRecords": '<i class="fa fa-refresh fa-spin"></i> Loading items...</div>'
|
||||
},
|
||||
"pagingType": "full_numbers",
|
||||
"stateSave": true,
|
||||
"stateDuration": 0,
|
||||
"processing": false,
|
||||
"serverSide": true,
|
||||
"pageLength": 25,
|
||||
"order": [0, 'asc'],
|
||||
"autoWidth": false,
|
||||
"scrollX": true,
|
||||
"columnDefs": [
|
||||
{
|
||||
"targets": [0],
|
||||
"data": "title",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
var smart = '<i class="fa fa-blank fa-fw"></i>';
|
||||
if (rowData['smart']) {
|
||||
smart = '<span class="media-type-tooltip" data-toggle="tooltip" title="Smart Playlist"><i class="fa fa-cog fa-fw"></i></span> '
|
||||
}
|
||||
var breadcrumb = '';
|
||||
if (rowData['userID']) {
|
||||
breadcrumb = '&user_id=' + rowData['userID'];
|
||||
} else if (rowData['librarySectionID']) {
|
||||
breadcrumb = '§ion_id=' + rowData['librarySectionID'];
|
||||
}
|
||||
var thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['composite'], rowData['ratingKey'], 300, 300, null, null, null, 'cover') + '" data-height="80" data-width="80">' + smart + cellData + '</span>';
|
||||
$(td).html('<a href="' + page('info', rowData['ratingKey']) + breadcrumb +'">' + thumb_popover + '</a>');
|
||||
}
|
||||
},
|
||||
"width": "60%",
|
||||
"className": "no-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [1],
|
||||
"data": "leafCount",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
var type = MEDIA_TYPE_HEADERS[rowData['playlistType']] || '';
|
||||
if (rowData['leafCount'] === 1) {
|
||||
type = type.slice(0, -1);
|
||||
}
|
||||
$(td).html(cellData + ' ' + type);
|
||||
}
|
||||
},
|
||||
"width": "20%",
|
||||
"className": "no-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [2],
|
||||
"data": "duration",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
$(td).html(humanDuration(cellData, 'dhm'));
|
||||
}
|
||||
},
|
||||
"width": "20%",
|
||||
"className": "no-wrap"
|
||||
}
|
||||
],
|
||||
"drawCallback": function (settings) {
|
||||
// Jump to top of page
|
||||
//$('html,body').scrollTop(0);
|
||||
$('#ajaxMsg').fadeOut();
|
||||
|
||||
// Create the tooltips.
|
||||
$('body').tooltip({
|
||||
selector: '[data-toggle="tooltip"]',
|
||||
container: 'body'
|
||||
});
|
||||
$('body').popover({
|
||||
selector: '[data-toggle="popover"]',
|
||||
html: true,
|
||||
container: 'body',
|
||||
trigger: 'hover',
|
||||
placement: 'right',
|
||||
template: '<div class="popover history-thumbnail-popover" role="tooltip"><div class="arrow" style="top: 50%;"></div><div class="popover-content"></div></div>',
|
||||
content: function () {
|
||||
return '<div class="history-thumbnail" style="background-image: url(' + $(this).data('img') + '); height: ' + $(this).data('height') + 'px; width: ' + $(this).data('width') + 'px;" />';
|
||||
}
|
||||
});
|
||||
},
|
||||
"preDrawCallback": function(settings) {
|
||||
var msg = "<i class='fa fa-refresh fa-spin'></i> Fetching rows...";
|
||||
showMsg(msg, false, false, 0);
|
||||
$('[data-toggle="tooltip"]').tooltip('destroy');
|
||||
},
|
||||
"rowCallback": function (row, rowData, rowIndex) {
|
||||
}
|
||||
};
|
@@ -51,9 +51,9 @@ sync_table_options = {
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
if (rowData['user_id']) {
|
||||
$(td).html('<a href="user?user_id=' + rowData['user_id'] + '">' + cellData + '</a>');
|
||||
$(td).html('<a href="' + page('user', rowData['user_id']) + '" title="' + rowData['username'] + '">' + cellData + '</a>');
|
||||
} else {
|
||||
$(td).html('<a href="user?user=' + rowData['user'] + '">' + cellData + '</a>');
|
||||
$(td).html('<a href="' + page('user', null, rowData['user']) + '" title="' + rowData['username'] + '">' + cellData + '</a>');
|
||||
}
|
||||
} else {
|
||||
$(td).html(cellData);
|
||||
@@ -67,7 +67,7 @@ sync_table_options = {
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
if (rowData['rating_key']) {
|
||||
$(td).html('<a href="info?rating_key=' + rowData['rating_key'] + '">' + cellData + '</a>');
|
||||
$(td).html('<a href="' + page('info', rowData['rating_key']) + '">' + cellData + '</a>');
|
||||
} else {
|
||||
$(td).html(cellData);
|
||||
}
|
||||
|
@@ -1,3 +1,25 @@
|
||||
var date_format = 'YYYY-MM-DD';
|
||||
var time_format = 'hh:mm a';
|
||||
|
||||
$.ajax({
|
||||
url: 'get_date_formats',
|
||||
type: 'GET',
|
||||
success: function(data) {
|
||||
date_format = data.date_format;
|
||||
time_format = data.time_format;
|
||||
}
|
||||
});
|
||||
|
||||
var seenRender = function (data, type, full) {
|
||||
return moment(data, "X").fromNow();
|
||||
};
|
||||
|
||||
var seenCreatedCell = function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== null) {
|
||||
$(td).attr('title', moment(cellData, "X").format(date_format + ' ' + time_format));
|
||||
}
|
||||
};
|
||||
|
||||
user_ip_table_options = {
|
||||
"destroy": true,
|
||||
"language": {
|
||||
@@ -21,16 +43,24 @@ user_ip_table_options = {
|
||||
"columnDefs": [
|
||||
{
|
||||
"targets": [0],
|
||||
"data":"last_seen",
|
||||
"render": function ( data, type, full ) {
|
||||
return moment(data, "X").fromNow();
|
||||
},
|
||||
"data": "last_seen",
|
||||
"render": seenRender,
|
||||
"createdCell": seenCreatedCell,
|
||||
"searchable": false,
|
||||
"width": "15%",
|
||||
"width": "12%",
|
||||
"className": "no-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [1],
|
||||
"data": "first_seen",
|
||||
"render": seenRender,
|
||||
"createdCell": seenCreatedCell,
|
||||
"searchable": false,
|
||||
"width": "12%",
|
||||
"className": "no-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [2],
|
||||
"data": "ip_address",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData) {
|
||||
@@ -44,22 +74,22 @@ user_ip_table_options = {
|
||||
$(td).html('n/a');
|
||||
}
|
||||
},
|
||||
"width": "15%",
|
||||
"width": "12%",
|
||||
"className": "no-wrap modal-control-ip"
|
||||
},
|
||||
{
|
||||
"targets": [2],
|
||||
"targets": [3],
|
||||
"data": "platform",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
$(td).html(cellData);
|
||||
}
|
||||
},
|
||||
"width": "15%",
|
||||
"width": "12%",
|
||||
"className": "no-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [3],
|
||||
"targets": [4],
|
||||
"data": "player",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
@@ -67,51 +97,59 @@ user_ip_table_options = {
|
||||
if (rowData['transcode_decision'] === 'transcode') {
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Transcode"><i class="fa fa-server fa-fw"></i></span>';
|
||||
} else if (rowData['transcode_decision'] === 'copy') {
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Stream"><i class="fa fa-video-camera fa-fw"></i></span>';
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Stream"><i class="fa fa-stream fa-fw"></i></span>';
|
||||
} else if (rowData['transcode_decision'] === 'direct play') {
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Play"><i class="fa fa-play-circle fa-fw"></i></span>';
|
||||
}
|
||||
$(td).html('<div><a href="#" data-target="#info-modal" data-toggle="modal"><div style="float: left;">' + transcode_dec + ' ' + cellData + '</div></a></div>');
|
||||
}
|
||||
},
|
||||
"width": "15%",
|
||||
"width": "12%",
|
||||
"className": "no-wrap modal-control"
|
||||
},
|
||||
{
|
||||
"targets": [4],
|
||||
"targets": [5],
|
||||
"data": "last_played",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
var icon = '';
|
||||
var icon_title = '';
|
||||
var parent_info = '';
|
||||
var media_type = '';
|
||||
var thumb_popover = '';
|
||||
var fallback = (rowData['live']) ? 'poster-live' : 'poster';
|
||||
if (rowData['media_type'] === 'movie') {
|
||||
icon = (rowData['live']) ? 'fa-broadcast-tower' : 'fa-film';
|
||||
icon_title = (rowData['live']) ? 'Live TV' : 'Movie';
|
||||
if (rowData['year']) { parent_info = ' (' + rowData['year'] + ')'; }
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Movie"><i class="fa fa-film fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
|
||||
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="' + icon_title + '"><i class="fa ' + icon + ' fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, fallback) + '" data-height="120" data-width="80">' + cellData + parent_info + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], true, rowData['live']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'episode') {
|
||||
if (rowData['parent_media_index'] && rowData['media_index']) { parent_info = ' (S' + rowData['parent_media_index'] + '· E' + rowData['media_index'] + ')'; }
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Episode"><i class="fa fa-television fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
|
||||
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;" >' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
icon = (rowData['live']) ? 'fa-broadcast-tower' : 'fa-television';
|
||||
icon_title = (rowData['live']) ? 'Live TV' : 'Episode';
|
||||
if (!isNaN(parseInt(rowData['parent_media_index'])) && !isNaN(parseInt(rowData['media_index']))) { parent_info = ' (S' + rowData['parent_media_index'] + ' · E' + rowData['media_index'] + ')'; }
|
||||
else if (rowData['live'] && rowData['originally_available_at']) { parent_info = ' (' + rowData['originally_available_at'] + ')'; }
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="' + icon_title + '"><i class="fa ' + icon + ' fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 450, null, null, null, fallback) + '" data-height="120" data-width="80">' + cellData + parent_info + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], true, rowData['live']) + '"><div style="float: left;" >' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'track') {
|
||||
if (rowData['parent_title']) { parent_info = ' (' + rowData['parent_title'] + ')'; }
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=300&fallback=cover" data-height="80" data-width="80">' + cellData + parent_info + '</span>'
|
||||
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="' + page('pms_image_proxy', rowData['thumb'], rowData['rating_key'], 300, 300, null, null, null, 'cover') + '" data-height="80" data-width="80">' + cellData + parent_info + '</span>';
|
||||
$(td).html('<div class="history-title"><a href="' + page('info', rowData['rating_key'], rowData['guid'], true, rowData['live']) + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type']) {
|
||||
$(td).html('<a href="info?rating_key=' + rowData['rating_key'] + '">' + cellData + '</a>');
|
||||
} else {
|
||||
$(td).html('n/a');
|
||||
$(td).html('<a href="' + page('info', rowData['rating_key']) + '">' + cellData + '</a>');
|
||||
}
|
||||
} else {
|
||||
$(td).html('n/a');
|
||||
}
|
||||
},
|
||||
"width": "30%",
|
||||
"className": "datatable-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [5],
|
||||
"targets": [6],
|
||||
"data": "play_count",
|
||||
"searchable": false,
|
||||
"width": "10%",
|
||||
@@ -159,7 +197,7 @@ $('.user_ip_table').on('click', 'td.modal-control', function () {
|
||||
function showStreamDetails() {
|
||||
$.ajax({
|
||||
url: 'get_stream_data',
|
||||
data: { row_id: rowData['id'], user: rowData['friendly_name'] },
|
||||
data: { row_id: rowData['history_row_id'], user: rowData['friendly_name'] },
|
||||
cache: false,
|
||||
async: true,
|
||||
complete: function (xhr, status) {
|
||||
|