Compare commits
619 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15b36c15d7 | ||
|
|
39daa502ad | ||
|
|
43dc2a956e | ||
|
|
512556dfba | ||
|
|
d214167402 | ||
|
|
6f5fab57db | ||
|
|
bb73fd9192 | ||
|
|
f20d0f9a69 | ||
|
|
9a7a6e6896 | ||
|
|
316d4ef3e2 | ||
|
|
ccb1e6f6f7 | ||
|
|
0fe60ed82c | ||
|
|
007a0a6b04 | ||
|
|
c32d6bce8a | ||
|
|
b6983eb60e | ||
|
|
41d6e2e54f | ||
|
|
7062c7a854 | ||
|
|
2c5ba0798b | ||
|
|
de30a11b17 | ||
|
|
fdcc9d2d52 | ||
|
|
7da2ff2026 | ||
|
|
9e402d3eec | ||
|
|
73dae33358 | ||
|
|
5d0fd36530 | ||
|
|
30ea9e794c | ||
|
|
78af3e02ad | ||
|
|
c9def4dd03 | ||
|
|
cf0544b118 | ||
|
|
fe3e5c979e | ||
|
|
9b75d0c859 | ||
|
|
248370f363 | ||
|
|
f7a63a0f70 | ||
|
|
780146e429 | ||
|
|
ce0fc82b20 | ||
|
|
29151d837a | ||
|
|
de74b0a912 | ||
|
|
124ae358ff | ||
|
|
cf62e5f29c | ||
|
|
ceeefaf4fb | ||
|
|
3db9aced52 | ||
|
|
889b970fa1 | ||
|
|
3b5984757c | ||
|
|
f5f82bf10e | ||
|
|
875020007d | ||
|
|
2f89201049 | ||
|
|
8f22f71e3f | ||
|
|
61ca0d4211 | ||
|
|
4feab32b04 | ||
|
|
1d7477bac9 | ||
|
|
4a4cc53717 | ||
|
|
4bfe4ec690 | ||
|
|
eb3bb2f1bd | ||
|
|
4bba48afd2 | ||
|
|
e503ddb053 | ||
|
|
4f8e5a6053 | ||
|
|
c86112f2ac | ||
|
|
528a355d8a | ||
|
|
37bfe3bf72 | ||
|
|
3b0c06295f | ||
|
|
090b684ffc | ||
|
|
eab7252bb1 | ||
|
|
212444b3e0 | ||
|
|
c8e0f64a98 | ||
|
|
feca38abdc | ||
|
|
1ccfa5b3d7 | ||
|
|
8b46c68c17 | ||
|
|
1c86e49f2a | ||
|
|
06d219e9ad | ||
|
|
aabd1b63e6 | ||
|
|
a64589bff8 | ||
|
|
6e87ce8a79 | ||
|
|
8ba89854fd | ||
|
|
9ce7903330 | ||
|
|
aec72afffc | ||
|
|
7d278a00df | ||
|
|
ec3682a0c8 | ||
|
|
6f3a9e20ac | ||
|
|
6681ee60fe | ||
|
|
4c93037725 | ||
|
|
8957956a51 | ||
|
|
40f978a777 | ||
|
|
0da8e08be5 | ||
|
|
3058ce6875 | ||
|
|
2813086f85 | ||
|
|
d4450d51ea | ||
|
|
517fbc8ed7 | ||
|
|
07e7a9f791 | ||
|
|
1477b112a6 | ||
|
|
e2e569e108 | ||
|
|
43de4d7b52 | ||
|
|
e69009dbdd | ||
|
|
1ea1d33976 | ||
|
|
aa8c24996c | ||
|
|
3aac126fbc | ||
|
|
9427e0fa78 | ||
|
|
ef95b68f7d | ||
|
|
101ed07224 | ||
|
|
a7f34a23c1 | ||
|
|
b68f208a52 | ||
|
|
721272228b | ||
|
|
7608e6e88b | ||
|
|
b6c0689bbf | ||
|
|
a72477df2e | ||
|
|
2ba1306631 | ||
|
|
31599ccf78 | ||
|
|
daad195853 | ||
|
|
7fdb54fd52 | ||
|
|
c7fe3b7663 | ||
|
|
24b8b5b320 | ||
|
|
ce25e984bd | ||
|
|
a69628daa5 | ||
|
|
5ea15ce8a4 | ||
|
|
f35a1e3d0f | ||
|
|
a99f9ee33e | ||
|
|
75c20183bb | ||
|
|
33d9f61a68 | ||
|
|
29daeab6ff | ||
|
|
c42f8d4bb6 | ||
|
|
84f4f444cb | ||
|
|
d4516d5273 | ||
|
|
87e795f17d | ||
|
|
08e846c4f0 | ||
|
|
60936a7845 | ||
|
|
6269b28f27 | ||
|
|
e35510124a | ||
|
|
e55af6cde4 | ||
|
|
a0e6be274f | ||
|
|
d1948d2e81 | ||
|
|
2e556114ad | ||
|
|
0a9b3be145 | ||
|
|
f573685af9 | ||
|
|
dc5bbfb996 | ||
|
|
31368905d6 | ||
|
|
b36cb88a01 | ||
|
|
88f3437a5f | ||
|
|
7de57576da | ||
|
|
c81c01fa4f | ||
|
|
641e0f576b | ||
|
|
a94b27332f | ||
|
|
a95ba4981f | ||
|
|
4ac4ccc63d | ||
|
|
e2b5d2cf8a | ||
|
|
92d26a101f | ||
|
|
63693d28ce | ||
|
|
287325b034 | ||
|
|
325c6b661c | ||
|
|
26f8fe6b02 | ||
|
|
68aabbd91d | ||
|
|
e3b02eee88 | ||
|
|
1c7c981dbc | ||
|
|
52ecf1a4dc | ||
|
|
18110ee703 | ||
|
|
e81998e222 | ||
|
|
2d5c3bd5e2 | ||
|
|
23a53d47c2 | ||
|
|
2f91443d2e | ||
|
|
166ffc4428 | ||
|
|
82e293d12e | ||
|
|
4bf8c364ee | ||
|
|
b5cbaaeb66 | ||
|
|
4bbeeba20e | ||
|
|
ad7fbeb31b | ||
|
|
701ece62f3 | ||
|
|
f49af402d0 | ||
|
|
e7c40ad63f | ||
|
|
a6841d5034 | ||
|
|
161c6d8433 | ||
|
|
1572f625d3 | ||
|
|
bde805a3a2 | ||
|
|
d8fca5b16f | ||
|
|
5e330658ec | ||
|
|
1f293845ea | ||
|
|
4fa19dc884 | ||
|
|
4afeb20b44 | ||
|
|
b9936e4b77 | ||
|
|
41446bc563 | ||
|
|
9313666fd2 | ||
|
|
2b49cc7a6f | ||
|
|
31151260df | ||
|
|
f8e8780de1 | ||
|
|
1e933c859a | ||
|
|
ce3c40dc1e | ||
|
|
df87fa8151 | ||
|
|
c6d9fc1e4a | ||
|
|
cf8dce1220 | ||
|
|
63a8e845f9 | ||
|
|
5e8059f223 | ||
|
|
6a35613a62 | ||
|
|
931d0396ce | ||
|
|
cf06e22643 | ||
|
|
86be028e41 | ||
|
|
e0afcf0b8e | ||
|
|
ba5253c09d | ||
|
|
4317c9c7bd | ||
|
|
be4fe5a44f | ||
|
|
406deccfd9 | ||
|
|
48eb9dd1b8 | ||
|
|
88d2d80678 | ||
|
|
18ad8e6f89 | ||
|
|
36956fc8a8 | ||
|
|
cd5cf56c3b | ||
|
|
e733ed7134 | ||
|
|
2cff552012 | ||
|
|
10fe06a8a7 | ||
|
|
3c89de64cb | ||
|
|
79551c52c8 | ||
|
|
4d3011e23b | ||
|
|
2cd7c3bd7f | ||
|
|
6cc9583604 | ||
|
|
352f6594e3 | ||
|
|
2373ac2d19 | ||
|
|
dfe7f6372a | ||
|
|
3e02b72dde | ||
|
|
88b17be010 | ||
|
|
8dd3d774c4 | ||
|
|
974f233431 | ||
|
|
4fd3ccefb0 | ||
|
|
2067f158fe | ||
|
|
1ddf270847 | ||
|
|
7073aeb307 | ||
|
|
9af3415ac6 | ||
|
|
61720a5f90 | ||
|
|
e15a87ef7f | ||
|
|
997f6985ba | ||
|
|
b132f63871 | ||
|
|
6c4dad03b5 | ||
|
|
7efcb96921 | ||
|
|
22dcbe1c13 | ||
|
|
8ae8b5639f | ||
|
|
8b8d32e20b | ||
|
|
d004716c4b | ||
|
|
2b154a4cff | ||
|
|
df411a0e00 | ||
|
|
381ecb95a9 | ||
|
|
886160ca0f | ||
|
|
b178f785de | ||
|
|
9266b05fad | ||
|
|
973fc68893 | ||
|
|
a0b8af9aa0 | ||
|
|
4a97979027 | ||
|
|
c5f5834b64 | ||
|
|
8e10ff79b1 | ||
|
|
7950610b4d | ||
|
|
93277c7d4f | ||
|
|
9523d8252d | ||
|
|
f16f2748a6 | ||
|
|
f04c4d70b9 | ||
|
|
f8e337ea92 | ||
|
|
347ab47672 | ||
|
|
d25de226d0 | ||
|
|
aa5b813929 | ||
|
|
bf513dee43 | ||
|
|
cb68387437 | ||
|
|
f8da1f5337 | ||
|
|
952eb31cc2 | ||
|
|
1d9b401405 | ||
|
|
70ec2d8773 | ||
|
|
383e1fd67b | ||
|
|
a013c8efb0 | ||
|
|
1b255f211e | ||
|
|
7b64a7cdd3 | ||
|
|
e3b34b81fd | ||
|
|
d70d2c3374 | ||
|
|
af06f09269 | ||
|
|
b32043cfd9 | ||
|
|
00b611d6f6 | ||
|
|
afea58c53a | ||
|
|
0db36ea1b8 | ||
|
|
5aa3b543ce | ||
|
|
3dfde5eb04 | ||
|
|
351c872c46 | ||
|
|
802f93c30c | ||
|
|
94b0dce77e | ||
|
|
2d2d378dca | ||
|
|
f84afcd7ab | ||
|
|
b7f507271e | ||
|
|
399e5b1683 | ||
|
|
0140dc6ff4 | ||
|
|
d1d403815e | ||
|
|
af2dabaa9d | ||
|
|
c9a8cec161 | ||
|
|
190d439d36 | ||
|
|
0a53312dee | ||
|
|
1759115a80 | ||
|
|
be477f2433 | ||
|
|
d3a3e27649 | ||
|
|
c832f74a26 | ||
|
|
721aa664a8 | ||
|
|
96982d52f1 | ||
|
|
a59d711c1e | ||
|
|
0559903fd6 | ||
|
|
a904c6a62e | ||
|
|
d73e144511 | ||
|
|
4730138dc1 | ||
|
|
6dd37bd8d2 | ||
|
|
05452e6f46 | ||
|
|
b7593b4042 | ||
|
|
000a48cc57 | ||
|
|
a89d0a6dc2 | ||
|
|
caa014a0ac | ||
|
|
8199642f35 | ||
|
|
da6525120d | ||
|
|
362760d3ab | ||
|
|
1cce67702d | ||
|
|
ff761dd088 | ||
|
|
beda70b1f9 | ||
|
|
eb9eb2009f | ||
|
|
73bcfef007 | ||
|
|
3104d5aec9 | ||
|
|
0d3c39cc0a | ||
|
|
e57059cf3c | ||
|
|
18e9a99d17 | ||
|
|
7b7549fef0 | ||
|
|
251f43fb77 | ||
|
|
6c4077b143 | ||
|
|
00a7e92ef7 | ||
|
|
61c1a3db8e | ||
|
|
bdcd65d6c9 | ||
|
|
f7a427b809 | ||
|
|
e96e727c7c | ||
|
|
f2ea26b529 | ||
|
|
7b10c48e8f | ||
|
|
0c71e82675 | ||
|
|
7fa7c8f9f8 | ||
|
|
102eb934af | ||
|
|
099e0193e9 | ||
|
|
c68b4bf392 | ||
|
|
14b2a10fdf | ||
|
|
a9ba96e08b | ||
|
|
d4c3ebab24 | ||
|
|
4f5396f945 | ||
|
|
59a5f72f7c | ||
|
|
47fbf495f1 | ||
|
|
55529f49e3 | ||
|
|
dd0f410161 | ||
|
|
6ee2f9c962 | ||
|
|
f24e20a902 | ||
|
|
1cf0155622 | ||
|
|
aa208d2ae5 | ||
|
|
1d8b9824ad | ||
|
|
bd1917a8a7 | ||
|
|
50a43e8e01 | ||
|
|
bee8be9698 | ||
|
|
774c9ba12d | ||
|
|
8be5c1b9eb | ||
|
|
9ada09e809 | ||
|
|
007a997f8f | ||
|
|
d70f9290f5 | ||
|
|
d32be4aba7 | ||
|
|
359dd05972 | ||
|
|
c005d331ee | ||
|
|
e51f136c4e | ||
|
|
95ee6e4e24 | ||
|
|
677d3a4a76 | ||
|
|
bd9f63de4c | ||
|
|
0a51bd366e | ||
|
|
2c959b0e00 | ||
|
|
291c3533e2 | ||
|
|
6080a3e6ec | ||
|
|
97785abff4 | ||
|
|
511f44e806 | ||
|
|
f5a97b4730 | ||
|
|
a47ba79413 | ||
|
|
429eaf76a5 | ||
|
|
da9136a08b | ||
|
|
cb0097a4e0 | ||
|
|
f66d2c55ca | ||
|
|
a30e58677d | ||
|
|
11d1898dc2 | ||
|
|
24548a081c | ||
|
|
09982b9f60 | ||
|
|
b56036b71e | ||
|
|
52fe89170f | ||
|
|
474043a569 | ||
|
|
7451605dbb | ||
|
|
860c487074 | ||
|
|
b1303413c6 | ||
|
|
6ad76560ed | ||
|
|
d6f449930c | ||
|
|
ebdf501115 | ||
|
|
34861fb9b9 | ||
|
|
2f3fe8ae6b | ||
|
|
4ee91654ea | ||
|
|
3190658e0c | ||
|
|
c330523b9e | ||
|
|
5a5c865135 | ||
|
|
f5ae301c97 | ||
|
|
d910441470 | ||
|
|
b667bf4117 | ||
|
|
4d8b4c9d43 | ||
|
|
02c44eef82 | ||
|
|
c21d10d7f9 | ||
|
|
d2d14e4c19 | ||
|
|
1da8bca9d1 | ||
|
|
dffbfd8860 | ||
|
|
7247c51b10 | ||
|
|
2517e30f55 | ||
|
|
caa0e47399 | ||
|
|
8ce6ec49e1 | ||
|
|
276b18650c | ||
|
|
a69a8a269f | ||
|
|
921628b2a1 | ||
|
|
53225b427c | ||
|
|
6aad1eb92d | ||
|
|
d4bccb9b05 | ||
|
|
02e9886e2e | ||
|
|
a05363d202 | ||
|
|
78fd1e206b | ||
|
|
74951b9dec | ||
|
|
5ac21ea240 | ||
|
|
086e92da4b | ||
|
|
e54c4c1bec | ||
|
|
5bb20e482f | ||
|
|
569462f755 | ||
|
|
658050548c | ||
|
|
4d635f6eb4 | ||
|
|
a0b1e9177b | ||
|
|
7a1a7843e6 | ||
|
|
66d4e02024 | ||
|
|
04a46f0cd9 | ||
|
|
4e0ac5330f | ||
|
|
32288aba97 | ||
|
|
801f119a5c | ||
|
|
567a02872b | ||
|
|
cfc19cafc5 | ||
|
|
44823f5043 | ||
|
|
bad5f8e561 | ||
|
|
075e1e8974 | ||
|
|
06f78ce620 | ||
|
|
cce9acb182 | ||
|
|
048b8f0385 | ||
|
|
fa318ac751 | ||
|
|
071ad16f83 | ||
|
|
eb44fc0ef7 | ||
|
|
f35239e1a4 | ||
|
|
5534878dcd | ||
|
|
f1b82cf89a | ||
|
|
4ae81b9f52 | ||
|
|
7af412e6c5 | ||
|
|
52baa2e8cc | ||
|
|
d48c159283 | ||
|
|
fae51bd9b2 | ||
|
|
9a6e16f505 | ||
|
|
44afd62989 | ||
|
|
69986cc40d | ||
|
|
9769a36c30 | ||
|
|
1621510b15 | ||
|
|
85f910dd48 | ||
|
|
e260124351 | ||
|
|
1eb2d21086 | ||
|
|
fedc67e1e2 | ||
|
|
c88a7b134f | ||
|
|
20dfc02624 | ||
|
|
2ca11e53be | ||
|
|
1b79794ede | ||
|
|
806de6910a | ||
|
|
ba30fc1613 | ||
|
|
cd5774bfd3 | ||
|
|
df9cd5fe48 | ||
|
|
76d189b8de | ||
|
|
0a0fd8a9a3 | ||
|
|
f78764d18a | ||
|
|
59b352df35 | ||
|
|
c241cc9df9 | ||
|
|
5ba6291fd9 | ||
|
|
c8715218c8 | ||
|
|
cc9caf3d54 | ||
|
|
6d298daea4 | ||
|
|
07ef6b6f41 | ||
|
|
6c8e193130 | ||
|
|
b7c31fa7a0 | ||
|
|
d25c7b351e | ||
|
|
90103b9fba | ||
|
|
7c39b06297 | ||
|
|
2ead20b2f7 | ||
|
|
c8821b1055 | ||
|
|
50b6f773f5 | ||
|
|
11705d46f2 | ||
|
|
3e96211433 | ||
|
|
0c3cefc0ff | ||
|
|
deab5fc2c2 | ||
|
|
9c68120447 | ||
|
|
6f3181a643 | ||
|
|
416b04fdec | ||
|
|
c2958445cb | ||
|
|
1176db8f41 | ||
|
|
136e22bb84 | ||
|
|
78b7f38f61 | ||
|
|
05ad58b46e | ||
|
|
8040349718 | ||
|
|
fca212edc3 | ||
|
|
7237fd2c63 | ||
|
|
26c02fdbac | ||
|
|
aa4a3531e9 | ||
|
|
4495129a66 | ||
|
|
791ed3fe32 | ||
|
|
b29688dc8d | ||
|
|
2936a12e25 | ||
|
|
213fa15ef3 | ||
|
|
80f25d016c | ||
|
|
a6ad9b5187 | ||
|
|
2f5765cc3f | ||
|
|
d08b5b7041 | ||
|
|
2772cf6389 | ||
|
|
6317aec577 | ||
|
|
43f576d1c5 | ||
|
|
d8493bc6bf | ||
|
|
96010b48c1 | ||
|
|
a803e007d0 | ||
|
|
0699bdd141 | ||
|
|
c5b1bb766b | ||
|
|
e0eff168bf | ||
|
|
1c88173b3e | ||
|
|
6c2e005cd7 | ||
|
|
08780edcc1 | ||
|
|
d86d785061 | ||
|
|
67cf11966b | ||
|
|
9c96cc4044 | ||
|
|
d1e4c1d09f | ||
|
|
944f3a363f | ||
|
|
79bd4b1925 | ||
|
|
8ea3351eee | ||
|
|
8d90ca0892 | ||
|
|
4bb7a95e73 | ||
|
|
13e553d818 | ||
|
|
92b8977797 | ||
|
|
a347255752 | ||
|
|
e8b329e688 | ||
|
|
d77d326950 | ||
|
|
9832e6b011 | ||
|
|
5bae9e72c9 | ||
|
|
dba2ee1556 | ||
|
|
357f28321c | ||
|
|
3402ef8d11 | ||
|
|
643e1d2ac8 | ||
|
|
f16ef03927 | ||
|
|
bf54539c39 | ||
|
|
e71714dbb8 | ||
|
|
a482172be4 | ||
|
|
6fbbd63ad6 | ||
|
|
6126d617f5 | ||
|
|
f507efdef7 | ||
|
|
7d4f50add1 | ||
|
|
201521a4d8 | ||
|
|
8c9289ef1c | ||
|
|
8ba1b0b0c0 | ||
|
|
7871422354 | ||
|
|
eb19d80b97 | ||
|
|
6888cbf7b8 | ||
|
|
5c1842877d | ||
|
|
0bf1d75e0c | ||
|
|
a3e3c33855 | ||
|
|
d5d5e7f74c | ||
|
|
8adfcbe20d | ||
|
|
f8f79ecc75 | ||
|
|
289f42392b | ||
|
|
71cea26ada | ||
|
|
5043a8db4e | ||
|
|
5d3199e306 | ||
|
|
37a132164f | ||
|
|
d02cad0fca | ||
|
|
3530d158a6 | ||
|
|
7eef3a30a8 | ||
|
|
36b23d0b19 | ||
|
|
816277512d | ||
|
|
bec7e06628 | ||
|
|
798a00ae3a | ||
|
|
c852d1e434 | ||
|
|
08a829ca97 | ||
|
|
1c18753511 | ||
|
|
6b1c3ccc39 | ||
|
|
bb207f1aee | ||
|
|
91cc66a8d1 | ||
|
|
cfbfb44307 | ||
|
|
8d29ffd7a7 | ||
|
|
44c5193f54 | ||
|
|
342eec8c26 | ||
|
|
4973404684 | ||
|
|
e45a59c184 | ||
|
|
6efa62ced2 | ||
|
|
a316a6e094 | ||
|
|
297b25a739 | ||
|
|
3aa4ee3548 | ||
|
|
e6e3c27371 | ||
|
|
bdf7298afa | ||
|
|
a81e125a29 | ||
|
|
a454eb16de | ||
|
|
50512e863d | ||
|
|
7ff8e12c4e | ||
|
|
a2815081d3 | ||
|
|
e14fa4b7de | ||
|
|
4c95caf957 | ||
|
|
4a242475c0 | ||
|
|
fb1348a306 | ||
|
|
1b3cea3042 | ||
|
|
264145c4b9 | ||
|
|
daea47bf38 | ||
|
|
2ff5a2e9fc | ||
|
|
fc690abee9 | ||
|
|
157a477a10 | ||
|
|
aa7a412a94 | ||
|
|
2832c21ffd | ||
|
|
3751794f81 | ||
|
|
5c3740b8a9 | ||
|
|
303f049004 | ||
|
|
a52ede2a3d | ||
|
|
f249eb7cae | ||
|
|
2d20dc4282 | ||
|
|
95f8dc8eb3 | ||
|
|
1ae1e824c0 | ||
|
|
72413ef3b4 | ||
|
|
d45c45a868 | ||
|
|
3b646da0a8 | ||
|
|
6121537216 | ||
|
|
2482f11a5a | ||
|
|
ade08f74a4 | ||
|
|
5eade9abe5 | ||
|
|
203986d54c | ||
|
|
8e8c376df3 |
@@ -1,70 +0,0 @@
|
||||
import xml.etree.ElementTree as ET
|
||||
import sys
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
def indent(elem, level=0):
|
||||
'''
|
||||
Nicely formats output xml with newlines and spaces
|
||||
https://stackoverflow.com/a/33956544
|
||||
'''
|
||||
i = "\n" + level*" "
|
||||
if len(elem):
|
||||
if not elem.text or not elem.text.strip():
|
||||
elem.text = i + " "
|
||||
if not elem.tail or not elem.tail.strip():
|
||||
elem.tail = i
|
||||
for elem in elem:
|
||||
indent(elem, level+1)
|
||||
if not elem.tail or not elem.tail.strip():
|
||||
elem.tail = i
|
||||
else:
|
||||
if level and (not elem.tail or not elem.tail.strip()):
|
||||
elem.tail = i
|
||||
|
||||
|
||||
try:
|
||||
py_version = sys.argv[1]
|
||||
except IndexError:
|
||||
print('No version specified')
|
||||
sys.exit(1)
|
||||
|
||||
dir_path = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
# Load template file
|
||||
with open('{dir_path}/template.xml'.format(**locals()), 'r') as f:
|
||||
tree = ET.parse(f)
|
||||
root = tree.getroot()
|
||||
|
||||
# Load version dependencies
|
||||
with open('{dir_path}/{py_version}.yaml'.format(**locals()), 'r') as f:
|
||||
deps = yaml.safe_load(f)
|
||||
|
||||
# Load version and changelog
|
||||
with open('jellyfin-kodi/release.yaml', 'r') as f:
|
||||
data = yaml.safe_load(f)
|
||||
|
||||
# Populate xml template
|
||||
for dep in deps:
|
||||
ET.SubElement(root.find('requires'), 'import', attrib=dep)
|
||||
|
||||
# Update version string
|
||||
addon_version = data.get('version')
|
||||
root.attrib['version'] = '{addon_version}+{py_version}'.format(**locals())
|
||||
|
||||
# Changelog
|
||||
date = datetime.today().strftime('%Y-%m-%d')
|
||||
changelog = data.get('changelog')
|
||||
for section in root.findall('extension'):
|
||||
news = section.findall('news')
|
||||
if news:
|
||||
news[0].text = 'v{addon_version} ({date}):\n{changelog}'.format(**locals())
|
||||
|
||||
# Format xml tree
|
||||
indent(root)
|
||||
|
||||
# Write addon.xml
|
||||
tree.write('jellyfin-kodi/addon.xml', encoding='utf-8', xml_declaration=True)
|
||||
2
.github/tools/reformat_changelog.py
vendored
2
.github/tools/reformat_changelog.py
vendored
@@ -23,7 +23,7 @@ class SectionType(TypedDict):
|
||||
|
||||
def reformat(item_format: str, output_emoji: bool) -> None:
|
||||
data = [
|
||||
emojize(x.strip(), use_aliases=True, variant="emoji_type")
|
||||
emojize(x.strip(), variant="emoji_type")
|
||||
for x in sys.stdin.readlines()
|
||||
if x.strip()
|
||||
]
|
||||
|
||||
6
.github/workflows/build.yaml
vendored
6
.github/workflows/build.yaml
vendored
@@ -15,10 +15,10 @@ jobs:
|
||||
py_version: [ 'py2', 'py3' ]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.x
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.9
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
run: python build.py --version ${{ matrix.py_version }}
|
||||
|
||||
- name: Publish Build Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
retention-days: 14
|
||||
name: ${{ matrix.py_version }}-build-artifact
|
||||
|
||||
12
.github/workflows/codeql.yaml
vendored
12
.github/workflows/codeql.yaml
vendored
@@ -18,24 +18,24 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'python' ]
|
||||
version: ['2.7', '3.9']
|
||||
version: ['3.9']
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
queries: +security-and-quality
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.version }}
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
uses: github/codeql-action/analyze@v3
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Update Draft
|
||||
uses: release-drafter/release-drafter@v5.15.0
|
||||
uses: release-drafter/release-drafter@v6.1.0
|
||||
id: draft
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.JF_BOT_TOKEN }}
|
||||
@@ -21,9 +21,9 @@ jobs:
|
||||
yq-version: v4.9.1
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Parse Changlog
|
||||
- name: Parse Changelog
|
||||
run: |
|
||||
pip install emoji
|
||||
cat << EOF >> cl.md
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Create or Update PR
|
||||
uses: k3rnels-actions/pr-update@v1
|
||||
uses: k3rnels-actions/pr-update@v2
|
||||
with:
|
||||
token: ${{ secrets.JF_BOT_TOKEN }}
|
||||
pr_title: Prepare for release ${{ steps.draft.outputs.tag_name }}
|
||||
|
||||
30
.github/workflows/publish.yaml
vendored
30
.github/workflows/publish.yaml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
py_version: [ 'py2', 'py3' ]
|
||||
steps:
|
||||
- name: Update Draft
|
||||
uses: release-drafter/release-drafter@v5.15.0
|
||||
uses: release-drafter/release-drafter@v6.1.0
|
||||
if: ${{ matrix.py_version == 'py3' }}
|
||||
with:
|
||||
publish: true
|
||||
@@ -19,10 +19,10 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.JF_BOT_TOKEN }}
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.x
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.9
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
run: python build.py --version ${{ matrix.py_version }}
|
||||
|
||||
- name: Publish Build Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
retention-days: 14
|
||||
name: ${{ matrix.py_version }}-build-artifact
|
||||
@@ -43,22 +43,22 @@ jobs:
|
||||
*.zip
|
||||
|
||||
- name: Upload to repo server
|
||||
uses: burnett01/rsync-deployments@5.1
|
||||
uses: burnett01/rsync-deployments@5.2
|
||||
with:
|
||||
switches: -vrptz
|
||||
path: '*.zip'
|
||||
remote_path: /srv/repository/incoming/kodi
|
||||
remote_host: ${{ secrets.DEPLOY_HOST }}
|
||||
remote_user: ${{ secrets.DEPLOY_USER }}
|
||||
remote_key: ${{ secrets.DEPLOY_KEY }}
|
||||
remote_path: /srv/incoming/kodi
|
||||
remote_host: ${{ secrets.REPO_HOST }}
|
||||
remote_user: ${{ secrets.REPO_USER }}
|
||||
remote_key: ${{ secrets.REPO_KEY }}
|
||||
|
||||
- name: Add to Kodi repo and clean up
|
||||
uses: appleboy/ssh-action@v0.1.4
|
||||
uses: appleboy/ssh-action@v1.2.0
|
||||
with:
|
||||
host: ${{ secrets.DEPLOY_HOST }}
|
||||
username: ${{ secrets.DEPLOY_USER }}
|
||||
key: ${{ secrets.DEPLOY_KEY }}
|
||||
host: ${{ secrets.REPO_HOST }}
|
||||
username: ${{ secrets.REPO_USER }}
|
||||
key: ${{ secrets.REPO_KEY }}
|
||||
script_stop: true
|
||||
script: |
|
||||
python3 /usr/local/bin/kodirepo add /srv/repository/incoming/kodi/plugin.video.jellycon+${{ matrix.py_version }}.zip --datadir /srv/repository/releases/client/kodi/${{ matrix.py_version }};
|
||||
rm /srv/repository/incoming/kodi/plugin.video.jellycon+${{ matrix.py_version }}.zip;
|
||||
python3 /usr/local/bin/kodirepo add /srv/incoming/kodi/plugin.video.jellycon+${{ matrix.py_version }}.zip --datadir /srv/repository/main/client/kodi/${{ matrix.py_version }};
|
||||
rm /srv/incoming/kodi/plugin.video.jellycon+${{ matrix.py_version }}.zip;
|
||||
|
||||
2
.github/workflows/release-drafter.yaml
vendored
2
.github/workflows/release-drafter.yaml
vendored
@@ -11,6 +11,6 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Update Release Draft
|
||||
uses: release-drafter/release-drafter@v5.15.0
|
||||
uses: release-drafter/release-drafter@v6.1.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.JF_BOT_TOKEN }}
|
||||
|
||||
8
.github/workflows/test.yaml
vendored
8
.github/workflows/test.yaml
vendored
@@ -17,13 +17,13 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
py_version: ['2.7', '3.9']
|
||||
py_version: ['3.9']
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python ${{ matrix.py_version }}
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.py_version }}
|
||||
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
cat flake8.output
|
||||
|
||||
- name: Publish Test Atrifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
retention-days: 14
|
||||
name: ${{ matrix.py_version }}-test-results
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -221,5 +221,7 @@ pip-log.txt
|
||||
#Mr Developer
|
||||
.mr.developer.cfg
|
||||
|
||||
venv
|
||||
|
||||
# Addon files
|
||||
addon.xml
|
||||
|
||||
43
README.md
43
README.md
@@ -1,6 +1,47 @@
|
||||
# JellyCon
|
||||
|
||||
JellyCon is a lightweight Kodi addon that lets you browse and play media files from your Jellyfin server directly within the Kodi interface.
|
||||
JellyCon is a lightweight Kodi add-on that lets you browse and play media files directly from your Jellyfin server within the Kodi interface. It can be thought of as a thin frontend for a Jellyfin server.
|
||||
|
||||
JellyCon can be used with Movie, TV Show, Music Video, and Music libraries, in addition to viewing LiveTV from the server. It can easily switch between multiple user accounts at will. It's easy to integrate with any customizable Kodi skin with a large collection of custom menus. Media items are populated from the server dynamically, and menu speed will vary based on local device speed.
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
#### 1. Adding the Jellyfin repository
|
||||
|
||||
https://jellyfin.org/docs/general/clients/kodi.html#install-add-on-repository
|
||||
|
||||
#### 2. Install JellyCon Add-on
|
||||
|
||||
- From within Kodi, navigate to "Add-on Browser"
|
||||
- Select "Install from Repository"
|
||||
- Choose "Kodi Jellyfin Add-ons", followed by "Video Add-ons"
|
||||
- Select the JellyCon add-on and choose install
|
||||
|
||||
#### 3. Login
|
||||
|
||||
- Within a few seconds after the installation you should be prompted for your server details.
|
||||
- If a Jellyfin server is detected on your local network, it will displayed in a dialog. Otherwise, you will be prompted to enter the URL of your Jellyfin server
|
||||
- If Quick Connect is enabled in the server, a code will be displayed that you can use to log in via Quick Connect in the web UI or a mobile app.
|
||||
- If Quick Connect is not enabled, or if you select the "Manual Login" button, you will be able to select a user from the list, or manually login using your username and password.
|
||||
|
||||
|
||||
## Configuration
|
||||
|
||||
#### Configuring Home
|
||||
|
||||
Many Kodi skins allow for customizing of the home menu with custom nodes and widgets. However, all of these use slightly different layouts and terminology. Rather than a step by step guide, this section serves as an barebones introduction to customizing a skin.
|
||||
Examples
|
||||
|
||||
If you would like a link on the home screen to open a library in your Jellyfin server called "Kid's Movies", you would point the menu item to the path: Add-On -> Video Add-On -> JellyCon -> Jellyfin Libraries -> Kid's Movies -> Create menu item to here.
|
||||
|
||||
Beyond just modifying where the home menu headers go, many skins also allow you to use widgets. Widgets help populate the home screen with data, often the posters of media in the selected image. If you would like to display the most recent movies across all of your Jellyfin libraries on the home screen, the path would be: Add-On -> Video Add-On -> JellyCon -> Global Lists -> Movies -> Movies - Recently Added (20) -> Use as widget
|
||||
|
||||
Another common use case of widgets would be to display the next available episodes of shows that you may be watching. As above, this can be done both with individual libraries or with all libraries combined:
|
||||
|
||||
Add-On -> Video Add-On -> JellyCon -> Jellyfin Libraries -> Anime -> Anime - Next Up (20) -> Use as widget
|
||||
Add-On -> Video Add-On -> JellyCon -> Global Lists -> TV Shows -> TV Shows - Next Up (20) -> Use as widget
|
||||
|
||||
|
||||
## License
|
||||
|
||||
|
||||
87
build.py
87
build.py
@@ -1,28 +1,28 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import argparse
|
||||
from datetime import datetime
|
||||
import os
|
||||
from pathlib import Path
|
||||
import xml.etree.ElementTree as ET
|
||||
import zipfile
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
def indent(elem, level=0):
|
||||
'''
|
||||
def indent(elem: ET.Element, level: int = 0) -> None:
|
||||
"""
|
||||
Nicely formats output xml with newlines and spaces
|
||||
https://stackoverflow.com/a/33956544
|
||||
'''
|
||||
i = "\n" + level*" "
|
||||
"""
|
||||
i = "\n" + level * " "
|
||||
if len(elem):
|
||||
if not elem.text or not elem.text.strip():
|
||||
elem.text = i + " "
|
||||
if not elem.tail or not elem.tail.strip():
|
||||
elem.tail = i
|
||||
for elem in elem:
|
||||
indent(elem, level+1)
|
||||
indent(elem, level + 1)
|
||||
if not elem.tail or not elem.tail.strip():
|
||||
elem.tail = i
|
||||
else:
|
||||
@@ -30,12 +30,12 @@ def indent(elem, level=0):
|
||||
elem.tail = i
|
||||
|
||||
|
||||
def create_addon_xml(config, source, py_version):
|
||||
'''
|
||||
def create_addon_xml(config: dict, source: str, py_version: str) -> None:
|
||||
"""
|
||||
Create addon.xml from template file
|
||||
'''
|
||||
"""
|
||||
# Load template file
|
||||
with open('{}/.config/template.xml'.format(source), 'r') as f:
|
||||
with open(f'{source}/.config/template.xml', 'r') as f:
|
||||
tree = ET.parse(f)
|
||||
root = tree.getroot()
|
||||
|
||||
@@ -46,7 +46,7 @@ def create_addon_xml(config, source, py_version):
|
||||
|
||||
# Populate version string
|
||||
addon_version = config.get('version')
|
||||
root.attrib['version'] = '{}+{}'.format(addon_version, py_version)
|
||||
root.attrib['version'] = f'{addon_version}+{py_version}'
|
||||
|
||||
# Populate Changelog
|
||||
date = datetime.today().strftime('%Y-%m-%d')
|
||||
@@ -54,30 +54,64 @@ def create_addon_xml(config, source, py_version):
|
||||
for section in root.findall('extension'):
|
||||
news = section.findall('news')
|
||||
if news:
|
||||
news[0].text = 'v{} ({}):\n{}'.format(addon_version, date, changelog)
|
||||
news[0].text = f'v{addon_version} ({date}):\n{changelog}'
|
||||
|
||||
# Format xml tree
|
||||
indent(root)
|
||||
|
||||
# Write addon.xml
|
||||
tree.write('{}/addon.xml'.format(source), encoding='utf-8', xml_declaration=True)
|
||||
tree.write(f'{source}/addon.xml', encoding='utf-8', xml_declaration=True)
|
||||
|
||||
|
||||
def zip_files(py_version, source, target):
|
||||
'''
|
||||
def zip_files(py_version: str, source: str, target: str, dev: bool) -> None:
|
||||
"""
|
||||
Create installable addon zip archive
|
||||
'''
|
||||
archive_name = 'plugin.video.jellycon+{}.zip'.format(py_version)
|
||||
"""
|
||||
archive_name = f'plugin.video.jellycon+{py_version}.zip'
|
||||
|
||||
with zipfile.ZipFile('{}/{}'.format(target, archive_name), 'w') as z:
|
||||
with zipfile.ZipFile(f'{target}/{archive_name}', 'w') as z:
|
||||
for root, dirs, files in os.walk(args.source):
|
||||
for filename in files:
|
||||
if 'plugin.video.jellycon' not in filename and 'pyo' not in filename:
|
||||
file_path = os.path.join(root, filename)
|
||||
for filename in filter(file_filter, files):
|
||||
file_path = os.path.join(root, filename)
|
||||
if dev or folder_filter(file_path):
|
||||
relative_path = os.path.join('plugin.video.jellycon', os.path.relpath(file_path, source))
|
||||
z.write(file_path, relative_path)
|
||||
|
||||
|
||||
def file_filter(file_name: str) -> bool:
|
||||
"""
|
||||
True if file_name is meant to be included
|
||||
"""
|
||||
return (
|
||||
not (file_name.startswith('plugin.video.jellycon') and file_name.endswith('.zip'))
|
||||
and not file_name.endswith('.pyo')
|
||||
and not file_name.endswith('.pyc')
|
||||
and not file_name.endswith('.pyd')
|
||||
)
|
||||
|
||||
|
||||
def folder_filter(folder_name: str) -> bool:
|
||||
"""
|
||||
True if folder_name is meant to be included
|
||||
"""
|
||||
filters = [
|
||||
'.ci',
|
||||
'.git',
|
||||
'.github',
|
||||
'.config',
|
||||
'.mypy_cache',
|
||||
'.pytest_cache',
|
||||
'__pycache__',
|
||||
'venv',
|
||||
]
|
||||
for f in filters:
|
||||
if f in folder_name.split(os.path.sep):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='Build flags:')
|
||||
parser.add_argument(
|
||||
@@ -96,13 +130,16 @@ if __name__ == '__main__':
|
||||
type=Path,
|
||||
default=Path(__file__).absolute().parent)
|
||||
|
||||
parser.add_argument('--dev', dest='dev', action='store_true')
|
||||
parser.set_defaults(dev=False)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Load config file
|
||||
config_path = os.path.join(args.source, 'release.yaml')
|
||||
with open(config_path, 'r') as fh:
|
||||
config = yaml.safe_load(fh)
|
||||
release_config = yaml.safe_load(fh)
|
||||
|
||||
create_addon_xml(config, args.source, args.version)
|
||||
create_addon_xml(release_config, args.source, args.version)
|
||||
|
||||
zip_files(args.version, args.source, args.target)
|
||||
zip_files(args.version, args.source, args.target, args.dev)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import xbmcaddon
|
||||
|
||||
from resources.lib.loghandler import LazyLogger
|
||||
from resources.lib.lazylogger import LazyLogger
|
||||
from resources.lib.functions import main_entry_point
|
||||
from resources.lib.tracking import set_timing_enabled
|
||||
|
||||
@@ -16,6 +16,3 @@ if log_timing_data:
|
||||
log.debug("About to enter mainEntryPoint()")
|
||||
|
||||
main_entry_point()
|
||||
|
||||
# clear done and exit.
|
||||
# sys.modules.clear()
|
||||
|
||||
25
release.yaml
25
release.yaml
@@ -1,29 +1,8 @@
|
||||
version: '0.4.5'
|
||||
version: '0.8.3'
|
||||
changelog: |-
|
||||
New features and improvements
|
||||
-----------------------------
|
||||
+ Attempt to reestablish websocket connection if it fails (#93) @mcarlton00
|
||||
+ Combine NextUp and InProgress (#82) @Ozymandyaz
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
+ Report tracks correctly when a playlist is playing (#102) @mcarlton00
|
||||
+ Fix image caching (#101) @mcarlton00
|
||||
+ Properly report stopped playback to the server (#95) @mcarlton00
|
||||
+ Make API calls respect limits indicated in UI (#90) @mcarlton00
|
||||
+ Fix #87 (#88) @oddstr13
|
||||
+ Fix direct play logic for 10.8 (#84) @mcarlton00
|
||||
|
||||
Code or Repo Maintenance
|
||||
------------------------
|
||||
+ Move inprogress call into relevant if block (#91) @mcarlton00
|
||||
+ Disable screensaver settings by default (#85) @mcarlton00
|
||||
|
||||
CI & build changes
|
||||
------------------
|
||||
+ Ci dependencies (#100) @mcarlton00
|
||||
+ Migrate CI to github actions (#96) @mcarlton00
|
||||
+ Correct addon name in build.py (#89) @mcarlton00
|
||||
+ Swap legacy secrets for current secrets (#371) @joshuaboniface
|
||||
dependencies:
|
||||
py2:
|
||||
- addon: 'xbmc.python'
|
||||
|
||||
@@ -6,7 +6,7 @@ requests >= 2.22
|
||||
futures >= 2.2; python_version < '3.0'
|
||||
|
||||
Kodistubs ~= 18.0; python_version < '3.0'
|
||||
Kodistubs ~= 19.0; python_version >= '3.6'
|
||||
Kodistubs ~= 21.0; python_version >= '3.6'
|
||||
|
||||
git+https://github.com/romanvm/kodi.six
|
||||
git+https://github.com/ruuk/script.module.addon.signals
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
2
resources/language/resource.language.be/strings.po
Normal file
2
resources/language/resource.language.be/strings.po
Normal file
@@ -0,0 +1,2 @@
|
||||
msgid ""
|
||||
msgstr "X-Generator: Weblate\nMIME-Version: 1.0\nContent-Type: text/plain; charset=UTF-8\nContent-Transfer-Encoding: 8bit"
|
||||
1155
resources/language/resource.language.ca/strings.po
Normal file
1155
resources/language/resource.language.ca/strings.po
Normal file
File diff suppressed because it is too large
Load Diff
508
resources/language/resource.language.cs/strings.po
Normal file
508
resources/language/resource.language.cs/strings.po
Normal file
@@ -0,0 +1,508 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2024-07-20 16:41+0000\n"
|
||||
"Last-Translator: Matěj Vrzalík <vrzalikm@gmail.com>\n"
|
||||
"Language-Team: Czech <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/cs/>\n"
|
||||
"Language: cs\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
|
||||
"X-Generator: Weblate 5.4.2\n"
|
||||
|
||||
msgctxt "#30016"
|
||||
msgid "Device display name"
|
||||
msgstr "Zobrazované jméno zařízení"
|
||||
|
||||
msgctxt "#30015"
|
||||
msgid "Log timing data"
|
||||
msgstr "Zaznamenat časové údaje"
|
||||
|
||||
msgctxt "#30014"
|
||||
msgid "Jellyfin"
|
||||
msgstr "Jellyfin"
|
||||
|
||||
msgctxt "#30012"
|
||||
msgid "[Change user]"
|
||||
msgstr "[Změnit uživatele]"
|
||||
|
||||
msgctxt "#30011"
|
||||
msgid "[Detect local server]"
|
||||
msgstr "[Zjistit místní server]"
|
||||
|
||||
msgctxt "#30008"
|
||||
msgid "Samba password"
|
||||
msgstr "Samba heslo"
|
||||
|
||||
msgctxt "#30007"
|
||||
msgid "Samba username"
|
||||
msgstr "Samba uživatelské jméno"
|
||||
|
||||
msgctxt "#30006"
|
||||
msgid "Password"
|
||||
msgstr "Heslo"
|
||||
|
||||
msgctxt "#30005"
|
||||
msgid "Username"
|
||||
msgstr "Uživatelské jméno"
|
||||
|
||||
msgctxt "#30003"
|
||||
msgid "Verify HTTPS certificate"
|
||||
msgstr "Ověř HTTPS certifikát"
|
||||
|
||||
msgctxt "#30001"
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
msgctxt "#30000"
|
||||
msgid "Host"
|
||||
msgstr "Hostitel"
|
||||
|
||||
msgctxt "#30027"
|
||||
msgid "Enable debug logging"
|
||||
msgstr "Povolit protokolování ladění"
|
||||
|
||||
msgctxt "#30026"
|
||||
msgid "Widget item select action"
|
||||
msgstr "Akce pro výběr položky widgetu"
|
||||
|
||||
msgctxt "#30025"
|
||||
msgid "Password:"
|
||||
msgstr "Heslo:"
|
||||
|
||||
msgctxt "#30024"
|
||||
msgid "Username:"
|
||||
msgstr "Uživatelské jméno:"
|
||||
|
||||
msgctxt "#30023"
|
||||
msgid "Hide unwatched episode details"
|
||||
msgstr "Schovat podrobnosti nezhlédnutých epizod"
|
||||
|
||||
msgctxt "#30022"
|
||||
msgid "Advanced"
|
||||
msgstr "Pokročilé"
|
||||
|
||||
msgctxt "#30021"
|
||||
msgid "Show all episodes item"
|
||||
msgstr "Zobrazit všechny epizody"
|
||||
|
||||
msgctxt "#30019"
|
||||
msgid "Filtered episode name format"
|
||||
msgstr "Formát názvu filtrované epizody"
|
||||
|
||||
msgctxt "#30018"
|
||||
msgid "Number of items to show in filtered lists"
|
||||
msgstr "Počet položek k zobrazení ve filtrovaném seznamu"
|
||||
|
||||
msgctxt "#30017"
|
||||
msgid "Show connected clients"
|
||||
msgstr "Zobrazit připojené klienty"
|
||||
|
||||
msgctxt "#30045"
|
||||
msgid "Username not found"
|
||||
msgstr "Uživatelské jméno nenalezeno"
|
||||
|
||||
msgctxt "#30091"
|
||||
msgid "Confirm delete?"
|
||||
msgstr "Potvrdit odstranění?"
|
||||
|
||||
msgctxt "#30111"
|
||||
msgid "Services"
|
||||
msgstr "Služby"
|
||||
|
||||
msgctxt "#30114"
|
||||
msgid "Jump back seconds"
|
||||
msgstr "Přeskočit o několik sekund zpět"
|
||||
|
||||
msgctxt "#30118"
|
||||
msgid "Add resume percent to names"
|
||||
msgstr "Přidat k názvům % kolik zbývá zhlédnout"
|
||||
|
||||
msgctxt "#30125"
|
||||
msgid "Done"
|
||||
msgstr "Hotovo"
|
||||
|
||||
msgctxt "#30135"
|
||||
msgid "Error"
|
||||
msgstr "Chyba"
|
||||
|
||||
msgctxt "#30044"
|
||||
msgid "Incorrect Username/Password"
|
||||
msgstr "Špatné uživatelské jméno / heslo"
|
||||
|
||||
msgctxt "#30052"
|
||||
msgid "Deleting"
|
||||
msgstr "Odstraňování"
|
||||
|
||||
msgctxt "#30053"
|
||||
msgid "Waiting for server to delete"
|
||||
msgstr "Čeká se na server až provede odstranění"
|
||||
|
||||
msgctxt "#30063"
|
||||
msgid "N/A"
|
||||
msgstr "Není k dispozici"
|
||||
|
||||
msgctxt "#30092"
|
||||
msgid "Warning: This action will delete the media files from the server."
|
||||
msgstr "Varování: Tato akce odstraní soubory médií ze serveru."
|
||||
|
||||
msgctxt "#30110"
|
||||
msgid "Interface"
|
||||
msgstr "Rozhraní"
|
||||
|
||||
msgctxt "#30112"
|
||||
msgid "Loading Content"
|
||||
msgstr "Nahrávání obsahu"
|
||||
|
||||
msgctxt "#30113"
|
||||
msgid "Retrieving Data"
|
||||
msgstr "Přijímání dat"
|
||||
|
||||
msgctxt "#30116"
|
||||
msgid "Add unwatched counts to names"
|
||||
msgstr "Přidat k názvům počet počty nezhlédnutých"
|
||||
|
||||
msgctxt "#30120"
|
||||
msgid "Show load progress"
|
||||
msgstr "Zobrazit průběh načítání"
|
||||
|
||||
msgctxt "#30126"
|
||||
msgid "Processing Item : "
|
||||
msgstr "Zpracování položky:"
|
||||
|
||||
msgctxt "#30121"
|
||||
msgid "On resume"
|
||||
msgstr "Při obnovení"
|
||||
|
||||
msgctxt "#30139"
|
||||
msgid "No Media Type Set"
|
||||
msgstr "Nenastavený typ média"
|
||||
|
||||
msgctxt "#30163"
|
||||
msgid "Add (cc) if subtitle is available"
|
||||
msgstr "Přidat (cc) pokud jsou k dispozici titulky"
|
||||
|
||||
msgctxt "#30166"
|
||||
msgid "Select Server"
|
||||
msgstr "Vybrat server"
|
||||
|
||||
msgctxt "#30167"
|
||||
msgid "Selected Server Address"
|
||||
msgstr "Adresa vybraného serveru"
|
||||
|
||||
msgctxt "#30169"
|
||||
msgid "Address: "
|
||||
msgstr "Adresa:"
|
||||
|
||||
msgctxt "#30180"
|
||||
msgid "Select User"
|
||||
msgstr "Vybrat uživatele"
|
||||
|
||||
msgctxt "#30181"
|
||||
msgid "Include plot"
|
||||
msgstr "Začlenit popis děje"
|
||||
|
||||
msgctxt "#30182"
|
||||
msgid "Include media stream info"
|
||||
msgstr "Zahrnout informace o streamu"
|
||||
|
||||
msgctxt "#30183"
|
||||
msgid "Include people"
|
||||
msgstr "Zahrnout osoby"
|
||||
|
||||
msgctxt "#30200"
|
||||
msgid "URL error"
|
||||
msgstr "Chyba URL"
|
||||
|
||||
msgctxt "#30201"
|
||||
msgid "Unable to connect to server"
|
||||
msgstr "Nelze se připojit k serveru"
|
||||
|
||||
msgctxt "#30206"
|
||||
msgid "Playback type"
|
||||
msgstr "Způsob přehrávání"
|
||||
|
||||
msgctxt "#30210"
|
||||
msgid "HTTP direct stream"
|
||||
msgstr "HTTP direct stream"
|
||||
|
||||
msgctxt "#30211"
|
||||
msgid "Transcode options"
|
||||
msgstr "Možnosti překódování"
|
||||
|
||||
msgctxt "#30214"
|
||||
msgid "Events"
|
||||
msgstr "Události"
|
||||
|
||||
msgctxt "#30208"
|
||||
msgid "Max stream bitrate (Kbits)"
|
||||
msgstr "Max datový tok streamu (Kbps)"
|
||||
|
||||
msgctxt "#30209"
|
||||
msgid "File direct path"
|
||||
msgstr "Přímá cesta k souboru"
|
||||
|
||||
msgctxt "#30212"
|
||||
msgid "Video max width"
|
||||
msgstr "Maximální šířka videa"
|
||||
|
||||
msgctxt "#30452"
|
||||
msgid "Combine instead of replace (might cause slow-down)"
|
||||
msgstr "Místo nahrazování kombinovat (může způsobit zpomalení)"
|
||||
|
||||
msgctxt "#30213"
|
||||
msgid "Video force 8 bit"
|
||||
msgstr "Vynutit 8 bit video"
|
||||
|
||||
msgctxt "#30224"
|
||||
msgid "Interaction"
|
||||
msgstr "Interakce"
|
||||
|
||||
msgctxt "#30259"
|
||||
msgid "Movies - Favorites"
|
||||
msgstr "Filmy - Oblíbené"
|
||||
|
||||
msgctxt "#30207"
|
||||
msgid "Playback"
|
||||
msgstr "Přehrávání"
|
||||
|
||||
msgctxt "#30216"
|
||||
msgid "Item Details"
|
||||
msgstr "Podrobnosti"
|
||||
|
||||
msgctxt "#30252"
|
||||
msgid "Movies - A-Z"
|
||||
msgstr "Filmy - A-Z"
|
||||
|
||||
msgctxt "#30257"
|
||||
msgid "Movies - Recently Added"
|
||||
msgstr "Filmy - Nedávno přidané"
|
||||
|
||||
msgctxt "#30218"
|
||||
msgid "Play next episode after %"
|
||||
msgstr "Přehrát další epizodu po %"
|
||||
|
||||
msgctxt "#30222"
|
||||
msgid "Item Layout"
|
||||
msgstr "Uspořádání položky"
|
||||
|
||||
msgctxt "#30250"
|
||||
msgid "Unknown"
|
||||
msgstr "Neznámé"
|
||||
|
||||
msgctxt "#30265"
|
||||
msgid "Episodes - Next Up"
|
||||
msgstr "Epizody - Ďalší na řadě"
|
||||
|
||||
msgctxt "#30226"
|
||||
msgid "Default"
|
||||
msgstr "Výchozí"
|
||||
|
||||
msgctxt "#30227"
|
||||
msgid "Simple"
|
||||
msgstr "Jednoduché"
|
||||
|
||||
msgctxt "#30229"
|
||||
msgid "TV Shows"
|
||||
msgstr "Seriály"
|
||||
|
||||
msgctxt "#30231"
|
||||
msgid "Movies"
|
||||
msgstr "Filmy"
|
||||
|
||||
msgctxt "#30235"
|
||||
msgid "Episodes"
|
||||
msgstr "Epizody"
|
||||
|
||||
msgctxt "#30237"
|
||||
msgid "Start from beginning"
|
||||
msgstr "Začít od začátku"
|
||||
|
||||
msgctxt "#30246"
|
||||
msgid "Search"
|
||||
msgstr "Hledat"
|
||||
|
||||
msgctxt "#30251"
|
||||
msgid "Movies - Genres"
|
||||
msgstr "Filmy - Žánry"
|
||||
|
||||
msgctxt "#30255"
|
||||
msgid "TV Shows - A-Z"
|
||||
msgstr "Seriály - A-Z"
|
||||
|
||||
msgctxt "#30256"
|
||||
msgid "Movies"
|
||||
msgstr "Filmy"
|
||||
|
||||
msgctxt "#30261"
|
||||
msgid "TV Shows"
|
||||
msgstr "Seriály"
|
||||
|
||||
msgctxt "#30262"
|
||||
msgid "TV Shows - Favorites"
|
||||
msgstr "Seriály - Oblíbené"
|
||||
|
||||
msgctxt "#30263"
|
||||
msgid "Episodes - Recently Added"
|
||||
msgstr "Epizody - Nedávno přidané"
|
||||
|
||||
msgctxt "#30215"
|
||||
msgid "On playback stop (100% = disabled)"
|
||||
msgstr "Při zastavení přehrávání (100% = zakázáno)"
|
||||
|
||||
msgctxt "#30217"
|
||||
msgid "Prompt to delete episode after %"
|
||||
msgstr "Výzva ke smazání epizody po %"
|
||||
|
||||
msgctxt "#30219"
|
||||
msgid " - Prompt before play"
|
||||
msgstr "- Výzva před přehráním"
|
||||
|
||||
msgctxt "#30223"
|
||||
msgid "Page Size and Filtering"
|
||||
msgstr "Velikost stránky a filtrování"
|
||||
|
||||
msgctxt "#30271"
|
||||
msgid "Mark Unwatched"
|
||||
msgstr "Označit jako nezhlédnuté"
|
||||
|
||||
msgctxt "#30258"
|
||||
msgid "Movies - In Progress"
|
||||
msgstr "Filmy - Probíhající"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30280"
|
||||
msgid "Missing Title"
|
||||
msgstr "Chybějící Nadpis"
|
||||
|
||||
msgctxt "#30292"
|
||||
msgid "Select Subtitle Stream"
|
||||
msgstr "Vyberte stopu titulků"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30291"
|
||||
msgid "Select Audio Stream"
|
||||
msgstr "Vyberte zvukovou stopu"
|
||||
|
||||
msgctxt "#30242"
|
||||
msgid "Force transcode av1"
|
||||
msgstr "Vynutit překódování av1"
|
||||
|
||||
msgctxt "#30264"
|
||||
msgid "Episodes - In Progress"
|
||||
msgstr "Epizody - Probíhající"
|
||||
|
||||
msgctxt "#30268"
|
||||
msgid " - Recently Added"
|
||||
msgstr "- Nedávno Přidané"
|
||||
|
||||
msgctxt "#30270"
|
||||
msgid "Mark Watched"
|
||||
msgstr "Označit jako zhlédnuté"
|
||||
|
||||
msgctxt "#30274"
|
||||
msgid "Delete"
|
||||
msgstr "Odstranit"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30281"
|
||||
msgid "Refresh Cached Images"
|
||||
msgstr "Obnovit přednačtené obrázky"
|
||||
|
||||
msgctxt "#30290"
|
||||
msgid "All"
|
||||
msgstr "Vše"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30293"
|
||||
msgid "Cache images"
|
||||
msgstr "Přednačíst obrázky"
|
||||
|
||||
msgctxt "#30294"
|
||||
msgid "Notice"
|
||||
msgstr "Upozornění"
|
||||
|
||||
msgctxt "#30225"
|
||||
msgid "Interface Mode"
|
||||
msgstr "Režim rozhraní"
|
||||
|
||||
msgctxt "#30236"
|
||||
msgid "Force transcode h265 (hevc)"
|
||||
msgstr "Vynutit překódování h265 (hevc)"
|
||||
|
||||
msgctxt "#30239"
|
||||
msgid "Force transcode mpeg2"
|
||||
msgstr "Vynutit překódování mpeg2"
|
||||
|
||||
msgctxt "#30240"
|
||||
msgid "Force transcode msmpeg4v3 (divx)"
|
||||
msgstr "Vynutit překódování msmpeg4v3 (divx)"
|
||||
|
||||
msgctxt "#30241"
|
||||
msgid "Force transcode mpeg4"
|
||||
msgstr "Vynutit překódování mpeg4"
|
||||
|
||||
msgctxt "#30269"
|
||||
msgid "Movies - Random"
|
||||
msgstr "Filmy - Náhodné"
|
||||
|
||||
msgctxt "#30272"
|
||||
msgid "Set Favourite"
|
||||
msgstr "Přidat mezi oblíbené"
|
||||
|
||||
msgctxt "#30273"
|
||||
msgid "Unset Favourite"
|
||||
msgstr "Odebrat z oblíbených"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30278"
|
||||
msgid " - Next Up"
|
||||
msgstr "- Další na řadě"
|
||||
|
||||
msgctxt "#30275"
|
||||
msgid "Force Transcode"
|
||||
msgstr "Vynutit překódování"
|
||||
|
||||
msgctxt "#30277"
|
||||
msgid "JellyCon needs to prompt for resume on partily played items, Kodi can also prompt, this can cause a double prompt. Do you want to remove the double prompt?"
|
||||
msgstr ""
|
||||
"JellyCon se musí zeptat zda-li se chcete vrátit na předchozí pozici u zčásti "
|
||||
"přehraných médií, Kodi se na toto může zeptat také, což může způsobit "
|
||||
"zdvojený dotaz. Chcete tento zdvojený dotaz odstranit?"
|
||||
|
||||
msgctxt "#30282"
|
||||
msgid "No Jellyfin servers detected on your local network."
|
||||
msgstr "Na vaší místní síti nebyly nalezeny žádné Jellyfin servery."
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30283"
|
||||
msgid "Play Next Episode?"
|
||||
msgstr "Přehrát další epizodu?"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30285"
|
||||
msgid " - Unwatched"
|
||||
msgstr "- Nezhlédnuté"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30286"
|
||||
msgid "Movies - Unwatched"
|
||||
msgstr "Filmy - Nezhlédnuté"
|
||||
|
||||
msgctxt "#30288"
|
||||
msgid " - Latest"
|
||||
msgstr "- Nejnovější"
|
||||
|
||||
msgctxt "#30296"
|
||||
msgid "Delete"
|
||||
msgstr "Odstranit"
|
||||
|
||||
msgctxt "#30297"
|
||||
msgid "Delete unused images?"
|
||||
msgstr "Odstranit nepoužité obrázky?"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30299"
|
||||
msgid "Cache Images"
|
||||
msgstr "Přednačíst obrázky"
|
||||
@@ -1,2 +1,418 @@
|
||||
msgid ""
|
||||
msgstr "X-Generator: Weblate\nMIME-Version: 1.0\nContent-Type: text/plain; charset=UTF-8\nContent-Transfer-Encoding: 8bit"
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2022-05-08 11:13+0000\n"
|
||||
"Last-Translator: Rhodri <rhodrilld@gmail.com>\n"
|
||||
"Language-Team: Welsh <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/cy/>\n"
|
||||
"Language: cy\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=6; plural=(n==0) ? 0 : (n==1) ? 1 : (n==2) ? 2 : "
|
||||
"(n==3) ? 3 :(n==6) ? 4 : 5;\n"
|
||||
"X-Generator: Weblate 4.10.1\n"
|
||||
|
||||
msgctxt "#30006"
|
||||
msgid "Password"
|
||||
msgstr "Cyfrinair"
|
||||
|
||||
msgctxt "#30005"
|
||||
msgid "Username"
|
||||
msgstr "Enw defnyddiwr"
|
||||
|
||||
msgctxt "#30003"
|
||||
msgid "Verify HTTPS certificate"
|
||||
msgstr "Gwiriwch dystysgrif HTTPS"
|
||||
|
||||
msgctxt "#30001"
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
msgctxt "#30000"
|
||||
msgid "Host"
|
||||
msgstr "Gwesteiwr"
|
||||
|
||||
msgctxt "#30021"
|
||||
msgid "Show all episodes item"
|
||||
msgstr "Dangos bob pennod"
|
||||
|
||||
msgctxt "#30020"
|
||||
msgid "Flatten single season"
|
||||
msgstr "Gwastadu tymor sengl"
|
||||
|
||||
msgctxt "#30019"
|
||||
msgid "Filtered episode name format"
|
||||
msgstr "Fformat enw pennod wedi'i hidlo"
|
||||
|
||||
msgctxt "#30018"
|
||||
msgid "Number of items to show in filtered lists"
|
||||
msgstr "Nifer yr eitemau i'w dangos mewn rhestrau wedi'u hidlo"
|
||||
|
||||
msgctxt "#30017"
|
||||
msgid "Show connected clients"
|
||||
msgstr "Dangos cleients cysylltiedig"
|
||||
|
||||
msgctxt "#30016"
|
||||
msgid "Device display name"
|
||||
msgstr "Enw arddangos dyfais"
|
||||
|
||||
msgctxt "#30015"
|
||||
msgid "Log timing data"
|
||||
msgstr "Logio data amseru"
|
||||
|
||||
msgctxt "#30014"
|
||||
msgid "Jellyfin"
|
||||
msgstr "Jellyfin"
|
||||
|
||||
msgctxt "#30012"
|
||||
msgid "[Change user]"
|
||||
msgstr "[Newid defnyddiwr]"
|
||||
|
||||
msgctxt "#30011"
|
||||
msgid "[Detect local server]"
|
||||
msgstr "[Canfod gweinydd lleol]"
|
||||
|
||||
msgctxt "#30010"
|
||||
msgid "Number of performance profiles to capture"
|
||||
msgstr "Nifer y proffiliau perfformiad i'w gynhyrchu"
|
||||
|
||||
msgctxt "#30008"
|
||||
msgid "Samba password"
|
||||
msgstr "Cyfrinair Samba"
|
||||
|
||||
msgctxt "#30007"
|
||||
msgid "Samba username"
|
||||
msgstr "Enw defnyddiwr Samba"
|
||||
|
||||
msgctxt "#30169"
|
||||
msgid "Address: "
|
||||
msgstr "Cyfeiriad:"
|
||||
|
||||
msgctxt "#30167"
|
||||
msgid "Selected Server Address"
|
||||
msgstr "Cyfeiriad Gweinydd a ddewiswyd"
|
||||
|
||||
msgctxt "#30166"
|
||||
msgid "Select Server"
|
||||
msgstr "Dewis Gweinydd"
|
||||
|
||||
msgctxt "#30135"
|
||||
msgid "Error"
|
||||
msgstr "Gwall"
|
||||
|
||||
msgctxt "#30126"
|
||||
msgid "Processing Item : "
|
||||
msgstr "Prosesi'r eitem:"
|
||||
|
||||
msgctxt "#30125"
|
||||
msgid "Done"
|
||||
msgstr "Wedi gorffen"
|
||||
|
||||
msgctxt "#30121"
|
||||
msgid "On resume"
|
||||
msgstr "Ar barhad"
|
||||
|
||||
msgctxt "#30113"
|
||||
msgid "Retrieving Data"
|
||||
msgstr "Adalw Data"
|
||||
|
||||
msgctxt "#30112"
|
||||
msgid "Loading Content"
|
||||
msgstr "Llwytho Cynnwys"
|
||||
|
||||
msgctxt "#30111"
|
||||
msgid "Services"
|
||||
msgstr "Gwasanaethau"
|
||||
|
||||
msgctxt "#30092"
|
||||
msgid "Warning: This action will delete the media files from the server."
|
||||
msgstr ""
|
||||
"Rhybudd: Bydd y weithred hon yn dileu'r ffeiliau cyfryngau o'r gweinydd."
|
||||
|
||||
msgctxt "#30091"
|
||||
msgid "Confirm delete?"
|
||||
msgstr "Cadarnhau dileu?"
|
||||
|
||||
msgctxt "#30063"
|
||||
msgid "N/A"
|
||||
msgstr "N/A"
|
||||
|
||||
msgctxt "#30053"
|
||||
msgid "Waiting for server to delete"
|
||||
msgstr "Aros i'r gweinydd i'w ddileu"
|
||||
|
||||
msgctxt "#30052"
|
||||
msgid "Deleting"
|
||||
msgstr "Wrthi'n dileu"
|
||||
|
||||
msgctxt "#30045"
|
||||
msgid "Username not found"
|
||||
msgstr "Enw defnyddiwr ddim yn bodoli"
|
||||
|
||||
msgctxt "#30044"
|
||||
msgid "Incorrect Username/Password"
|
||||
msgstr "Enw defnyddiwr/Cyfrinair anghywir"
|
||||
|
||||
msgctxt "#30025"
|
||||
msgid "Password:"
|
||||
msgstr "Cyfrinair:"
|
||||
|
||||
msgctxt "#30024"
|
||||
msgid "Username:"
|
||||
msgstr "Enw defnyddiwr:"
|
||||
|
||||
msgctxt "#30022"
|
||||
msgid "Advanced"
|
||||
msgstr "Uwchraddol"
|
||||
|
||||
msgctxt "#30216"
|
||||
msgid "Item Details"
|
||||
msgstr "Gwybodaeth Eitem"
|
||||
|
||||
msgctxt "#30200"
|
||||
msgid "URL error"
|
||||
msgstr "gwall URL"
|
||||
|
||||
msgctxt "#30180"
|
||||
msgid "Select User"
|
||||
msgstr "Dewis Defnyddiwr"
|
||||
|
||||
msgctxt "#30429"
|
||||
msgid "Genre"
|
||||
msgstr "Genre"
|
||||
|
||||
msgctxt "#30430"
|
||||
msgid "Label"
|
||||
msgstr "Label"
|
||||
|
||||
msgctxt "#30426"
|
||||
msgid "Title"
|
||||
msgstr "Teitl"
|
||||
|
||||
msgctxt "#30425"
|
||||
msgid "Year"
|
||||
msgstr "Blwyddyn"
|
||||
|
||||
msgctxt "#30401"
|
||||
msgid "Info"
|
||||
msgstr "Gwybodaeth"
|
||||
|
||||
msgctxt "#30399"
|
||||
msgid "Hide"
|
||||
msgstr "Cuddio"
|
||||
|
||||
msgctxt "#30392"
|
||||
msgid "HTTPS"
|
||||
msgstr "HTTPS"
|
||||
|
||||
msgctxt "#30391"
|
||||
msgid "HTTP"
|
||||
msgstr "HTTP"
|
||||
|
||||
msgctxt "#30380"
|
||||
msgid "Never"
|
||||
msgstr "Byth"
|
||||
|
||||
msgctxt "#30339"
|
||||
msgid "Person"
|
||||
msgstr "Person"
|
||||
|
||||
msgctxt "#30338"
|
||||
msgid "Album"
|
||||
msgstr "Albwm"
|
||||
|
||||
msgctxt "#30337"
|
||||
msgid "Song"
|
||||
msgstr "Cân"
|
||||
|
||||
msgctxt "#30314"
|
||||
msgid "Play"
|
||||
msgstr "Chwarae"
|
||||
|
||||
msgctxt "#30313"
|
||||
msgid "Menu"
|
||||
msgstr "Dewislen"
|
||||
|
||||
msgctxt "#30296"
|
||||
msgid "Delete"
|
||||
msgstr "Dileu"
|
||||
|
||||
msgctxt "#30274"
|
||||
msgid "Delete"
|
||||
msgstr "Dileu"
|
||||
|
||||
msgctxt "#30256"
|
||||
msgid "Movies"
|
||||
msgstr "Ffilmiau"
|
||||
|
||||
msgctxt "#30250"
|
||||
msgid "Unknown"
|
||||
msgstr "Anhysbys"
|
||||
|
||||
msgctxt "#30246"
|
||||
msgid "Search"
|
||||
msgstr "Chwilio"
|
||||
|
||||
msgctxt "#30235"
|
||||
msgid "Episodes"
|
||||
msgstr "Pennodau"
|
||||
|
||||
msgctxt "#30231"
|
||||
msgid "Movies"
|
||||
msgstr "Ffilmiau"
|
||||
|
||||
msgctxt "#30218"
|
||||
msgid "Play next episode after %"
|
||||
msgstr "Chwarae'r bennod nesaf ar ôl %"
|
||||
|
||||
msgctxt "#30214"
|
||||
msgid "Events"
|
||||
msgstr "Digwyddiadau"
|
||||
|
||||
msgctxt "#30211"
|
||||
msgid "Transcode options"
|
||||
msgstr "Opsiynau trawsgodio"
|
||||
|
||||
msgctxt "#30201"
|
||||
msgid "Unable to connect to server"
|
||||
msgstr "Methu cysylltu â'r gweinydd"
|
||||
|
||||
msgctxt "#30183"
|
||||
msgid "Include people"
|
||||
msgstr "Cynnwys pobl"
|
||||
|
||||
msgctxt "#30181"
|
||||
msgid "Include plot"
|
||||
msgstr "Cynnwys plot"
|
||||
|
||||
msgctxt "#30163"
|
||||
msgid "Add (cc) if subtitle is available"
|
||||
msgstr "Ychwanegu (cc) os oes is-deitlau ar gael"
|
||||
|
||||
msgctxt "#30114"
|
||||
msgid "Jump back seconds"
|
||||
msgstr "Neidio yn ôl eiliadau"
|
||||
|
||||
msgctxt "#30110"
|
||||
msgid "Interface"
|
||||
msgstr "Rhyngwyneb"
|
||||
|
||||
msgctxt "#30027"
|
||||
msgid "Enable debug logging"
|
||||
msgstr "Actifadu logio dadfygio"
|
||||
|
||||
msgctxt "#30023"
|
||||
msgid "Hide unwatched episode details"
|
||||
msgstr "Cuddio manylion penodau heb eu gwylio"
|
||||
|
||||
msgctxt "#30381"
|
||||
msgid "More than one"
|
||||
msgstr "Mwy na un"
|
||||
|
||||
msgctxt "#30362"
|
||||
msgid " - Recordings"
|
||||
msgstr "- Recordiadau"
|
||||
|
||||
msgctxt "#30361"
|
||||
msgid " - Programs"
|
||||
msgstr "- Rhaglenni"
|
||||
|
||||
msgctxt "#30360"
|
||||
msgid " - Channels"
|
||||
msgstr "- Sianeli"
|
||||
|
||||
msgctxt "#30325"
|
||||
msgid " - Genres"
|
||||
msgstr "- Genres"
|
||||
|
||||
msgctxt "#30316"
|
||||
msgid "Connection Error"
|
||||
msgstr "Gwall cysylltiad"
|
||||
|
||||
msgctxt "#30312"
|
||||
msgid "All - "
|
||||
msgstr "Pobeth -"
|
||||
|
||||
msgctxt "#30311"
|
||||
msgid "Library - "
|
||||
msgstr "Llyfrgell -"
|
||||
|
||||
msgctxt "#30294"
|
||||
msgid "Notice"
|
||||
msgstr "Rhybydd"
|
||||
|
||||
msgctxt "#30290"
|
||||
msgid "All"
|
||||
msgstr "Pobeth"
|
||||
|
||||
msgctxt "#30288"
|
||||
msgid " - Latest"
|
||||
msgstr "- Diweddaraf"
|
||||
|
||||
msgctxt "#30285"
|
||||
msgid " - Unwatched"
|
||||
msgstr "- Heb ei wylio"
|
||||
|
||||
msgctxt "#30283"
|
||||
msgid "Play Next Episode?"
|
||||
msgstr "Chwarae'r bennod nesaf?"
|
||||
|
||||
msgctxt "#30280"
|
||||
msgid "Missing Title"
|
||||
msgstr "Teitl ar goll"
|
||||
|
||||
msgctxt "#30278"
|
||||
msgid " - Next Up"
|
||||
msgstr "- Nesaf"
|
||||
|
||||
msgctxt "#30286"
|
||||
msgid "Movies - Unwatched"
|
||||
msgstr "Ffilmiau - Heb ei wylio"
|
||||
|
||||
msgctxt "#30252"
|
||||
msgid "Movies - A-Z"
|
||||
msgstr "Ffilmiau - A-Z"
|
||||
|
||||
msgctxt "#30251"
|
||||
msgid "Movies - Genres"
|
||||
msgstr "Ffilmiau - Genres"
|
||||
|
||||
msgctxt "#30259"
|
||||
msgid "Movies - Favorites"
|
||||
msgstr "Ffilmiau - Ffefrynnau"
|
||||
|
||||
msgctxt "#30415"
|
||||
msgid " - Favorite Collections"
|
||||
msgstr "- Hoff Gasgliadau"
|
||||
|
||||
msgctxt "#30414"
|
||||
msgid " - Favorites"
|
||||
msgstr "- Ffefrynnau"
|
||||
|
||||
msgctxt "#30289"
|
||||
msgid "TV Shows - Genres"
|
||||
msgstr "Rhaglenni teledu - Genres"
|
||||
|
||||
msgctxt "#30287"
|
||||
msgid "TV Shows - Latest"
|
||||
msgstr "Rhaglenni teledu - Diweddaraf"
|
||||
|
||||
msgctxt "#30279"
|
||||
msgid "TV Shows - Unwatched"
|
||||
msgstr "Rhaglenni teledu - Heb ei wylio"
|
||||
|
||||
msgctxt "#30262"
|
||||
msgid "TV Shows - Favorites"
|
||||
msgstr "Rhaglenni teledu - Ffefrynnau"
|
||||
|
||||
msgctxt "#30261"
|
||||
msgid "TV Shows"
|
||||
msgstr "Rhaglenni teledu"
|
||||
|
||||
msgctxt "#30255"
|
||||
msgid "TV Shows - A-Z"
|
||||
msgstr "Rhaglenni teledu - A-Z"
|
||||
|
||||
msgctxt "#30229"
|
||||
msgid "TV Shows"
|
||||
msgstr "Rhaglenni teledu"
|
||||
|
||||
1153
resources/language/resource.language.da/strings.po
Normal file
1153
resources/language/resource.language.da/strings.po
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -301,6 +301,18 @@ msgctxt "#30224"
|
||||
msgid "Interaction"
|
||||
msgstr "Interaction"
|
||||
|
||||
msgctxt "#30225"
|
||||
msgid "Interface Mode"
|
||||
msgstr "Interface Mode"
|
||||
|
||||
msgctxt "#30226"
|
||||
msgid "Default"
|
||||
msgstr "Default"
|
||||
|
||||
msgctxt "#30227"
|
||||
msgid "Simple"
|
||||
msgstr "Simple"
|
||||
|
||||
msgctxt "#30229"
|
||||
msgid "TV Shows"
|
||||
msgstr "TV Shows"
|
||||
@@ -337,6 +349,10 @@ msgctxt "#30241"
|
||||
msgid "Force transcode mpeg4"
|
||||
msgstr "Force transcode mpeg4"
|
||||
|
||||
msgctxt "#30242"
|
||||
msgid "Force transcode av1"
|
||||
msgstr "Force transcode av1"
|
||||
|
||||
msgctxt "#30246"
|
||||
msgid "Search"
|
||||
msgstr "Search"
|
||||
@@ -624,6 +640,10 @@ msgctxt "#30322"
|
||||
msgid "Auto resume"
|
||||
msgstr "Auto resume"
|
||||
|
||||
msgctxt "#30323"
|
||||
msgid "Artists"
|
||||
msgstr "Artists"
|
||||
|
||||
msgctxt "#30325"
|
||||
msgid " - Genres"
|
||||
msgstr "- Genres"
|
||||
@@ -1073,8 +1093,8 @@ msgid "Play cinema intros"
|
||||
msgstr "Play cinema intros"
|
||||
|
||||
msgctxt "#30439"
|
||||
msgid "Show play next episode at time left"
|
||||
msgstr "Show play next episode at time left"
|
||||
msgid "Show play next episode at time left in seconds"
|
||||
msgstr "Show play next episode at time left in seconds"
|
||||
|
||||
msgctxt "#30440"
|
||||
msgid "Play next"
|
||||
@@ -1087,3 +1107,52 @@ msgstr "Use cached widget data"
|
||||
msgctxt "#30442"
|
||||
msgid "Simple new content check"
|
||||
msgstr "Simple new content check"
|
||||
|
||||
msgctxt "#30443"
|
||||
msgid "Quick Connect"
|
||||
msgstr "Quick Connect"
|
||||
|
||||
msgctxt "#30444"
|
||||
msgid "Login using Quick Connect"
|
||||
msgstr "Login using Quick Connect"
|
||||
|
||||
|
||||
msgctxt "#30445"
|
||||
msgid "Continue Watching"
|
||||
msgstr "Continue Watching"
|
||||
|
||||
msgctxt "#30446"
|
||||
msgid "There was an error logging in"
|
||||
msgstr "There was an error logging in"
|
||||
|
||||
msgctxt "#30447"
|
||||
msgid "Max Play Queue Size"
|
||||
msgstr "Max Play Queue Size"
|
||||
|
||||
msgctxt "#30448"
|
||||
msgid "Shuffle"
|
||||
msgstr "Shuffle"
|
||||
|
||||
msgctxt "#30449"
|
||||
msgid "Instant Mix"
|
||||
msgstr "Instant Mix"
|
||||
|
||||
msgctxt "#30450"
|
||||
msgid "Next Up Rewatching"
|
||||
msgstr "Next Up Rewatching"
|
||||
|
||||
msgctxt "#30451"
|
||||
msgid "Rewatch Days (0 = Disabled)"
|
||||
msgstr "Rewatch Days (0 = Disabled)"
|
||||
|
||||
msgctxt "#30452"
|
||||
msgid "Combine instead of replace (might cause slow-down)"
|
||||
msgstr "Combine instead of replace (might cause slow-down)"
|
||||
|
||||
msgctxt "#30453"
|
||||
msgid "Hide number of items to show on entry title"
|
||||
msgstr "Hide number of items to show on entry title"
|
||||
|
||||
msgctxt "#30454"
|
||||
msgid " - Totally Unwatched"
|
||||
msgstr " - Totally Unwatched"
|
||||
2
resources/language/resource.language.enm/strings.po
Normal file
2
resources/language/resource.language.enm/strings.po
Normal file
@@ -0,0 +1,2 @@
|
||||
msgid ""
|
||||
msgstr "X-Generator: Weblate\nMIME-Version: 1.0\nContent-Type: text/plain; charset=UTF-8\nContent-Transfer-Encoding: 8bit"
|
||||
@@ -1,6 +1,6 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2021-11-14 13:05+0000\n"
|
||||
"PO-Revision-Date: 2022-08-10 20:22+0000\n"
|
||||
"Last-Translator: WWWesten <wwwesten@gmail.com>\n"
|
||||
"Language-Team: Esperanto <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/eo/>\n"
|
||||
@@ -9,7 +9,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 4.5.2\n"
|
||||
"X-Generator: Weblate 4.10.1\n"
|
||||
|
||||
msgctxt "#30254"
|
||||
msgid "Show add-on settings"
|
||||
@@ -1085,3 +1085,19 @@ msgstr "Montri ĉiujn epizodojn"
|
||||
msgctxt "#30019"
|
||||
msgid "Filtered episode name format"
|
||||
msgstr "Noma formato de filtrita epizodo"
|
||||
|
||||
msgctxt "#30444"
|
||||
msgid "Login using Quick Connect"
|
||||
msgstr "Ensaluti uzante Rapidan Konekton"
|
||||
|
||||
msgctxt "#30443"
|
||||
msgid "Quick Connect"
|
||||
msgstr "Rapida Konekto"
|
||||
|
||||
msgctxt "#30323"
|
||||
msgid "Artists"
|
||||
msgstr "Artistoj"
|
||||
|
||||
msgctxt "#30445"
|
||||
msgid "Continue Watching"
|
||||
msgstr "Daŭrigi Spektadon"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2021-12-07 18:05+0000\n"
|
||||
"Last-Translator: oxixes <adrianquevedobenito@gmail.com>\n"
|
||||
"PO-Revision-Date: 2024-11-11 04:00+0000\n"
|
||||
"Last-Translator: SullensCR <sullenscr@protonmail.com>\n"
|
||||
"Language-Team: Spanish <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/es/>\n"
|
||||
"Language: es\n"
|
||||
@@ -9,7 +9,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 4.5.2\n"
|
||||
"X-Generator: Weblate 5.7.2\n"
|
||||
|
||||
msgctxt "#30442"
|
||||
msgid "Simple new content check"
|
||||
@@ -23,10 +23,9 @@ msgctxt "#30439"
|
||||
msgid "Show play next episode at time left"
|
||||
msgstr "Mostrar reproducir siguiente episodio al tiempo restante"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30438"
|
||||
msgid "Play cinema intros"
|
||||
msgstr "Reproducir introducciones de cine"
|
||||
msgstr "Reproducir Introducciones de Cine"
|
||||
|
||||
msgctxt "#30437"
|
||||
msgid "Playback options"
|
||||
@@ -50,7 +49,7 @@ msgstr "Permitir reproducción directa de archivo"
|
||||
|
||||
msgctxt "#30432"
|
||||
msgid "Hide watched items in lists"
|
||||
msgstr "Esconder elementos vistos en las listas"
|
||||
msgstr "Ocultar elementos vistos en las listas"
|
||||
|
||||
msgctxt "#30431"
|
||||
msgid "Seasons"
|
||||
@@ -106,7 +105,7 @@ msgstr "No tienes permiso para borrar este elemento"
|
||||
|
||||
msgctxt "#30416"
|
||||
msgid "HTTP timeout seconds"
|
||||
msgstr "Segundos del tiempo de espera de HTTP"
|
||||
msgstr "Maximo tiempo de espera de HTTP en segundos"
|
||||
|
||||
msgctxt "#30415"
|
||||
msgid " - Favorite Collections"
|
||||
@@ -281,7 +280,6 @@ msgctxt "#30368"
|
||||
msgid "Clear Password?"
|
||||
msgstr "¿Borrar contraseña?"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30367"
|
||||
msgid "Allow fast user switching password saving"
|
||||
msgstr "Permitir guardado rápido de la contraseña de usuario cambiada"
|
||||
@@ -541,7 +539,6 @@ msgctxt "#30296"
|
||||
msgid "Delete"
|
||||
msgstr "Borrar"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30295"
|
||||
msgid "To use this feature you need HTTP control enabled"
|
||||
msgstr "Para usar esta característica necesitas activar el control HTTP"
|
||||
@@ -794,7 +791,6 @@ msgctxt "#30211"
|
||||
msgid "Transcode options"
|
||||
msgstr "Opciones de transcodificación"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30209"
|
||||
msgid "File direct path"
|
||||
msgstr "Ruta directa al archivo"
|
||||
@@ -986,3 +982,178 @@ msgstr "Verificar certificado HTTPS"
|
||||
msgctxt "#30001"
|
||||
msgid "Port"
|
||||
msgstr "Puerto"
|
||||
|
||||
msgctxt "#30441"
|
||||
msgid "Use cached widget data"
|
||||
msgstr "Usar información en cache del complemento"
|
||||
|
||||
msgctxt "#30423"
|
||||
msgid "NotSet"
|
||||
msgstr "No establecido"
|
||||
|
||||
msgctxt "#30421"
|
||||
msgid "Views"
|
||||
msgstr "Vistas"
|
||||
|
||||
msgctxt "#30408"
|
||||
msgid "Custom Widgets"
|
||||
msgstr "Controles Personalizados"
|
||||
|
||||
msgctxt "#30400"
|
||||
msgid "Cache images interval minutes (0 = disabled)"
|
||||
msgstr "Intervalo de almacenamiento de imágenes en caché (0 = deshabilitado)"
|
||||
|
||||
msgctxt "#30384"
|
||||
msgid "Random movies interval minutes (0 = disabled)"
|
||||
msgstr "Intervalo de películas aleatorias en minutos (0 = deshabilitado)"
|
||||
|
||||
msgctxt "#30379"
|
||||
msgid "External subtitle prompt"
|
||||
msgstr "Confirmación de subtítulos externos"
|
||||
|
||||
msgctxt "#30345"
|
||||
msgid "Cache Jellyfin server data requests"
|
||||
msgstr "Hacer caché de solicitudes al servidor Jellyfin"
|
||||
|
||||
msgctxt "#30333"
|
||||
msgid "Cache artwork in the background"
|
||||
msgstr "Almacenar en la memoria caché el material gráfico en segundo plano"
|
||||
|
||||
msgctxt "#30299"
|
||||
msgid "Cache Images"
|
||||
msgstr "Almacenar Imágenes en caché"
|
||||
|
||||
msgctxt "#30277"
|
||||
msgid "JellyCon needs to prompt for resume on partily played items, Kodi can also prompt, this can cause a double prompt. Do you want to remove the double prompt?"
|
||||
msgstr ""
|
||||
"JellyCon Necesita confirmar para reanudar archivos reproducidos "
|
||||
"parcialmente, Kodi también puede solicitar confirmación , esto puede causar "
|
||||
"una doble confirmación. ¿Desea eliminar la doble confirmación?"
|
||||
|
||||
msgctxt "#30247"
|
||||
msgid "Custom Widget Content"
|
||||
msgstr "Contenido del widget personalizado"
|
||||
|
||||
msgctxt "#30215"
|
||||
msgid "On playback stop (100% = disabled)"
|
||||
msgstr "Al detener la reproducción (100% = deshabilitado)"
|
||||
|
||||
msgctxt "#30210"
|
||||
msgid "HTTP direct stream"
|
||||
msgstr "Transmisión directa por HTTP"
|
||||
|
||||
msgctxt "#30182"
|
||||
msgid "Include media stream info"
|
||||
msgstr "Incluir información de la transmisión"
|
||||
|
||||
msgctxt "#30163"
|
||||
msgid "Add (cc) if subtitle is available"
|
||||
msgstr "Agregar (cc) si los subtítulos están disponibles"
|
||||
|
||||
msgctxt "#30139"
|
||||
msgid "No Media Type Set"
|
||||
msgstr "No se ha establecido el tipo de medio"
|
||||
|
||||
msgctxt "#30121"
|
||||
msgid "On resume"
|
||||
msgstr "Al reanudar"
|
||||
|
||||
msgctxt "#30116"
|
||||
msgid "Add unwatched counts to names"
|
||||
msgstr "Agregar contador de no vistos a nombres"
|
||||
|
||||
msgctxt "#30114"
|
||||
msgid "Jump back seconds"
|
||||
msgstr "Regresar en segundos"
|
||||
|
||||
msgctxt "#30026"
|
||||
msgid "Widget item select action"
|
||||
msgstr "Acción al seleccionar un ítem del widget"
|
||||
|
||||
msgctxt "#30020"
|
||||
msgid "Flatten single season"
|
||||
msgstr "Aplanar una sola temporada"
|
||||
|
||||
msgctxt "#30015"
|
||||
msgid "Log timing data"
|
||||
msgstr "Frecuencia de registro de datos"
|
||||
|
||||
msgctxt "#30000"
|
||||
msgid "Host"
|
||||
msgstr "Anfitrión"
|
||||
|
||||
msgctxt "#30276"
|
||||
msgid "Extra Resume Prompt Detected"
|
||||
msgstr "Detectada solicitud adicional a reanudar"
|
||||
|
||||
msgctxt "#30260"
|
||||
msgid "BoxSets"
|
||||
msgstr "Colecciones"
|
||||
|
||||
msgctxt "#30444"
|
||||
msgid "Login using Quick Connect"
|
||||
msgstr "Inicia sesión usando Conexión Rápida"
|
||||
|
||||
msgctxt "#30443"
|
||||
msgid "Quick Connect"
|
||||
msgstr "Conexión rápida"
|
||||
|
||||
msgctxt "#30323"
|
||||
msgid "Artists"
|
||||
msgstr "Artistas"
|
||||
|
||||
msgctxt "#30445"
|
||||
msgid "Continue Watching"
|
||||
msgstr "Continuar viendo"
|
||||
|
||||
msgctxt "#30439"
|
||||
msgid "Show play next episode at time left in seconds"
|
||||
msgstr "Mostrar reproducir el próximo episodio a los segundos restantes"
|
||||
|
||||
msgctxt "#30446"
|
||||
msgid "There was an error logging in"
|
||||
msgstr "Se ha producido un error al iniciar sesión"
|
||||
|
||||
msgctxt "#30447"
|
||||
msgid "Max Play Queue Size"
|
||||
msgstr "Tamaño máximo de la cola de reproducción"
|
||||
|
||||
msgctxt "#30449"
|
||||
msgid "Instant Mix"
|
||||
msgstr "Mezcla instantánea"
|
||||
|
||||
msgctxt "#30448"
|
||||
msgid "Shuffle"
|
||||
msgstr "Mezclar"
|
||||
|
||||
msgctxt "#30225"
|
||||
msgid "Interface Mode"
|
||||
msgstr "Modo de Interfaz"
|
||||
|
||||
msgctxt "#30226"
|
||||
msgid "Default"
|
||||
msgstr "Predeterminado"
|
||||
|
||||
msgctxt "#30227"
|
||||
msgid "Simple"
|
||||
msgstr "Simple"
|
||||
|
||||
msgctxt "#30452"
|
||||
msgid "Combine instead of replace (might cause slow-down)"
|
||||
msgstr "Combinar en vez de reemplazar (podría causar una bajada rendimiento)"
|
||||
|
||||
msgctxt "#30242"
|
||||
msgid "Force transcode av1"
|
||||
msgstr "Forzar transcodificación AV1"
|
||||
|
||||
msgctxt "#30450"
|
||||
msgid "Next Up Rewatching"
|
||||
msgstr "Volver a ver a continuación"
|
||||
|
||||
msgctxt "#30451"
|
||||
msgid "Rewatch Days (0 = Disabled)"
|
||||
msgstr "Días para volver a verlo (0 = deshabilitado)"
|
||||
|
||||
msgctxt "#30453"
|
||||
msgid "Hide number of items to show on entry title"
|
||||
msgstr "Ocultar el número de ítems que se enseñan en el título"
|
||||
|
||||
763
resources/language/resource.language.et/strings.po
Normal file
763
resources/language/resource.language.et/strings.po
Normal file
@@ -0,0 +1,763 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2022-01-03 18:05+0000\n"
|
||||
"Last-Translator: rimasx <riks_12@hot.ee>\n"
|
||||
"Language-Team: Estonian <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/et/>\n"
|
||||
"Language: et\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 4.5.2\n"
|
||||
|
||||
msgctxt "#30021"
|
||||
msgid "Show all episodes item"
|
||||
msgstr "Kuva kõik episoodid"
|
||||
|
||||
msgctxt "#30018"
|
||||
msgid "Number of items to show in filtered lists"
|
||||
msgstr "Filtreeritud loendites kuvatavate üksuste arv"
|
||||
|
||||
msgctxt "#30017"
|
||||
msgid "Show connected clients"
|
||||
msgstr "Kuva ühendatud kliendid"
|
||||
|
||||
msgctxt "#30016"
|
||||
msgid "Device display name"
|
||||
msgstr "Seadme kuvatav nimi"
|
||||
|
||||
msgctxt "#30015"
|
||||
msgid "Log timing data"
|
||||
msgstr "Logi ajakirjed"
|
||||
|
||||
msgctxt "#30014"
|
||||
msgid "Jellyfin"
|
||||
msgstr "Jellyfin"
|
||||
|
||||
msgctxt "#30012"
|
||||
msgid "[Change user]"
|
||||
msgstr "[Muuda kasutajat]"
|
||||
|
||||
msgctxt "#30011"
|
||||
msgid "[Detect local server]"
|
||||
msgstr "[Tuvasta kohalik server]"
|
||||
|
||||
msgctxt "#30010"
|
||||
msgid "Number of performance profiles to capture"
|
||||
msgstr "Jäädvustavate jõudlusprofiilide arv"
|
||||
|
||||
msgctxt "#30008"
|
||||
msgid "Samba password"
|
||||
msgstr "Samba parool"
|
||||
|
||||
msgctxt "#30007"
|
||||
msgid "Samba username"
|
||||
msgstr "Samba kasutajanimi"
|
||||
|
||||
msgctxt "#30006"
|
||||
msgid "Password"
|
||||
msgstr "Parool"
|
||||
|
||||
msgctxt "#30005"
|
||||
msgid "Username"
|
||||
msgstr "Kasutajanimi"
|
||||
|
||||
msgctxt "#30003"
|
||||
msgid "Verify HTTPS certificate"
|
||||
msgstr "Kinnita HTTPS sertifikaat"
|
||||
|
||||
msgctxt "#30001"
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
msgctxt "#30366"
|
||||
msgid "Manually enter user details"
|
||||
msgstr "Sisesta kasutaja andmed käsitsi"
|
||||
|
||||
msgctxt "#30241"
|
||||
msgid "Force transcode mpeg4"
|
||||
msgstr "Transkoodi jõuga mpeg4"
|
||||
|
||||
msgctxt "#30240"
|
||||
msgid "Force transcode msmpeg4v3 (divx)"
|
||||
msgstr "Transkoodi jõuga msmpeg4v3 (divx)"
|
||||
|
||||
msgctxt "#30365"
|
||||
msgid "Manual Login"
|
||||
msgstr "Käsitsi sisselogimine"
|
||||
|
||||
msgctxt "#30364"
|
||||
msgid "Do you want to save the password?"
|
||||
msgstr "Kas soovid parooli salvestada?"
|
||||
|
||||
msgctxt "#30363"
|
||||
msgid "Save Password?"
|
||||
msgstr "Kas salvestada parool?"
|
||||
|
||||
msgctxt "#30362"
|
||||
msgid " - Recordings"
|
||||
msgstr "- salvestised"
|
||||
|
||||
msgctxt "#30361"
|
||||
msgid " - Programs"
|
||||
msgstr "- saated"
|
||||
|
||||
msgctxt "#30360"
|
||||
msgid " - Channels"
|
||||
msgstr "- kanalid"
|
||||
|
||||
msgctxt "#30359"
|
||||
msgid "Building full image list"
|
||||
msgstr "Täieliku piltide loendi koostamine"
|
||||
|
||||
msgctxt "#30358"
|
||||
msgid "Retreiving remote image list"
|
||||
msgstr "Kaugpiltide loendi vastuvõtt"
|
||||
|
||||
msgctxt "#30357"
|
||||
msgid "Processing existing image list"
|
||||
msgstr "Olemasoleva piltide loendi töötlemine"
|
||||
|
||||
msgctxt "#30356"
|
||||
msgid "Loading existing image list"
|
||||
msgstr "Olemasoleva piltide loendi laadimine"
|
||||
|
||||
msgctxt "#30355"
|
||||
msgid "Kodi Settings->Services->Allow remote control via HTTP"
|
||||
msgstr "Kodi seaded-> Teenused-> Luba kaugjuhtimine HTTP kaudu"
|
||||
|
||||
msgctxt "#30354"
|
||||
msgid "Go To Series"
|
||||
msgstr "Ava seriaal"
|
||||
|
||||
msgctxt "#30353"
|
||||
msgid " - Frequently Played"
|
||||
msgstr "- sageli esitatud"
|
||||
|
||||
msgctxt "#30321"
|
||||
msgid " - Album Artists"
|
||||
msgstr "– albumi esitajad"
|
||||
|
||||
msgctxt "#30319"
|
||||
msgid "Music - All Album Artists"
|
||||
msgstr "Muusika – kõik albumi esitajad"
|
||||
|
||||
msgctxt "#30352"
|
||||
msgid "Music - Frequently Played"
|
||||
msgstr "Muusika – sageli esitatud"
|
||||
|
||||
msgctxt "#30327"
|
||||
msgid "Go To Season"
|
||||
msgstr "Ava hooaeg"
|
||||
|
||||
msgctxt "#30209"
|
||||
msgid "File direct path"
|
||||
msgstr "Faili otserada"
|
||||
|
||||
msgctxt "#30263"
|
||||
msgid "Episodes - Recently Added"
|
||||
msgstr "Episoodid – viimati lisatud"
|
||||
|
||||
msgctxt "#30257"
|
||||
msgid "Movies - Recently Added"
|
||||
msgstr "Filmid – viimati lisatud"
|
||||
|
||||
msgctxt "#30349"
|
||||
msgid " - Recently Played"
|
||||
msgstr "- viimati esitatud"
|
||||
|
||||
msgctxt "#30268"
|
||||
msgid " - Recently Added"
|
||||
msgstr "- viimati lisatud"
|
||||
|
||||
msgctxt "#30351"
|
||||
msgid "Music - Recently Played"
|
||||
msgstr "Muusika – viimati esitatud"
|
||||
|
||||
msgctxt "#30350"
|
||||
msgid "Music - Recently Added"
|
||||
msgstr "Muusika – viimati lisatud"
|
||||
|
||||
msgctxt "#30348"
|
||||
msgid "Add user ratings"
|
||||
msgstr "Lisa kasutajahinded"
|
||||
|
||||
msgctxt "#30347"
|
||||
msgid "Getting Existing Images"
|
||||
msgstr "Olemasolevate piltide hankimine"
|
||||
|
||||
msgctxt "#30346"
|
||||
msgid "Deleteing Cached Images"
|
||||
msgstr "Vahemällu salvestatud piltide kustutamine"
|
||||
|
||||
msgctxt "#30345"
|
||||
msgid "Cache Jellyfin server data requests"
|
||||
msgstr "Salvesta Jellyfin serveri andmepäringud vahemällu"
|
||||
|
||||
msgctxt "#30344"
|
||||
msgid "Number of images removed from cache"
|
||||
msgstr "Vahemälust eemaldatud piltide arv"
|
||||
|
||||
msgctxt "#30343"
|
||||
msgid "Changes Require Kodi Restart"
|
||||
msgstr "Muudatused nõuavad Kodi taaskäivitamist"
|
||||
|
||||
msgctxt "#30342"
|
||||
msgid "New content check interval (0 = disabled)"
|
||||
msgstr "Uus sisu kontrollimise intervall (0 = keelatud)"
|
||||
|
||||
msgctxt "#30341"
|
||||
msgid "Background image update interval (0 = disabled)"
|
||||
msgstr "Taustapildi värskendamise intervall (0 = keelatud)"
|
||||
|
||||
msgctxt "#30340"
|
||||
msgid "Group movies into collections"
|
||||
msgstr "Rühmita filmid kogumikesse"
|
||||
|
||||
msgctxt "#30339"
|
||||
msgid "Person"
|
||||
msgstr "Isik"
|
||||
|
||||
msgctxt "#30338"
|
||||
msgid "Album"
|
||||
msgstr "Album"
|
||||
|
||||
msgctxt "#30337"
|
||||
msgid "Song"
|
||||
msgstr "Lugu"
|
||||
|
||||
msgctxt "#30334"
|
||||
msgid "Use JellyCon context menu"
|
||||
msgstr "Kasuta JellyCon kontekstimenüüd"
|
||||
|
||||
msgctxt "#30333"
|
||||
msgid "Cache artwork in the background"
|
||||
msgstr "Salvesta pildid vahemällu taustal"
|
||||
|
||||
msgctxt "#30332"
|
||||
msgid "Stop media playback on screensaver activation"
|
||||
msgstr "Peata meedia taasesitus ekraanisäästja aktiveerimisel"
|
||||
|
||||
msgctxt "#30331"
|
||||
msgid "Movies per page"
|
||||
msgstr "Filme lehel"
|
||||
|
||||
msgctxt "#30330"
|
||||
msgid "Show change user dialog"
|
||||
msgstr "Kuva kasutaja muutmise dialoog"
|
||||
|
||||
msgctxt "#30329"
|
||||
msgid "Screensaver"
|
||||
msgstr "Ekraanisäästja"
|
||||
|
||||
msgctxt "#30328"
|
||||
msgid "Show empty folders (shows, seasons, collections)"
|
||||
msgstr "Kuva tühjad kaustad (saated, hooajad, kogumikud)"
|
||||
|
||||
msgctxt "#30325"
|
||||
msgid " - Genres"
|
||||
msgstr "- žanrid"
|
||||
|
||||
msgctxt "#30322"
|
||||
msgid "Auto resume"
|
||||
msgstr "Automaatne jätkamine"
|
||||
|
||||
msgctxt "#30320"
|
||||
msgid " - Albums"
|
||||
msgstr "- albumid"
|
||||
|
||||
msgctxt "#30318"
|
||||
msgid "Music - Albums"
|
||||
msgstr "Muusika – albumid"
|
||||
|
||||
msgctxt "#30317"
|
||||
msgid "Play All"
|
||||
msgstr "Esita kõik"
|
||||
|
||||
msgctxt "#30316"
|
||||
msgid "Connection Error"
|
||||
msgstr "Ühenduse viga"
|
||||
|
||||
msgctxt "#30315"
|
||||
msgid "Suppress notifications for connection errors"
|
||||
msgstr "Lülita ühenduse veateavitused välja"
|
||||
|
||||
msgctxt "#30314"
|
||||
msgid "Play"
|
||||
msgstr "Esita"
|
||||
|
||||
msgctxt "#30313"
|
||||
msgid "Menu"
|
||||
msgstr "Menüü"
|
||||
|
||||
msgctxt "#30312"
|
||||
msgid "All - "
|
||||
msgstr "Kõik -"
|
||||
|
||||
msgctxt "#30311"
|
||||
msgid "Library - "
|
||||
msgstr "Meediakogu -"
|
||||
|
||||
msgctxt "#30310"
|
||||
msgid "Enable Jellyfin remote control"
|
||||
msgstr "Luba Jellyfini kaugjuhtimine"
|
||||
|
||||
msgctxt "#30309"
|
||||
msgid "Select Media Source"
|
||||
msgstr "Vali meedia allikas"
|
||||
|
||||
msgctxt "#30308"
|
||||
msgid "Select Trailer"
|
||||
msgstr "Vali treiler"
|
||||
|
||||
msgctxt "#30307"
|
||||
msgid "Play Trailer"
|
||||
msgstr "Esita treiler"
|
||||
|
||||
msgctxt "#30306"
|
||||
msgid "Playback starting"
|
||||
msgstr "Taasesitus algab"
|
||||
|
||||
msgctxt "#30305"
|
||||
msgid "Not Found"
|
||||
msgstr "Ei leitud"
|
||||
|
||||
msgctxt "#30304"
|
||||
msgid "Cached Jellyfin images : "
|
||||
msgstr "Vahemällu salvestatud Jellyfini pildid:"
|
||||
|
||||
msgctxt "#30303"
|
||||
msgid "Missing Jellyfin images : "
|
||||
msgstr "Puuduvad Jellyfini pildid:"
|
||||
|
||||
msgctxt "#30302"
|
||||
msgid "Existing images : "
|
||||
msgstr "Olemasolevad pildid:"
|
||||
|
||||
msgctxt "#30301"
|
||||
msgid "Caching Images"
|
||||
msgstr "Piltide vahemällu salvestamine"
|
||||
|
||||
msgctxt "#30300"
|
||||
msgid "Cache all Jellyfin images as local Kodi images?"
|
||||
msgstr "Kas salvestada kõik Jellyfini pildid vahemällu kohalike Kodi piltidena?"
|
||||
|
||||
msgctxt "#30299"
|
||||
msgid "Cache Images"
|
||||
msgstr "Pildid vahemällu"
|
||||
|
||||
msgctxt "#30298"
|
||||
msgid "Deleting Kodi Images"
|
||||
msgstr "Kodi piltide kustutamine"
|
||||
|
||||
msgctxt "#30297"
|
||||
msgid "Delete unused images?"
|
||||
msgstr "Kas kustutada kasutamata pildid?"
|
||||
|
||||
msgctxt "#30296"
|
||||
msgid "Delete"
|
||||
msgstr "Kustuta"
|
||||
|
||||
msgctxt "#30295"
|
||||
msgid "To use this feature you need HTTP control enabled"
|
||||
msgstr "Selle funktsiooni kasutamiseks peab HTTP juhtimine olema lubatud"
|
||||
|
||||
msgctxt "#30294"
|
||||
msgid "Notice"
|
||||
msgstr "Märkus"
|
||||
|
||||
msgctxt "#30293"
|
||||
msgid "Cache images"
|
||||
msgstr "Pildid vahemällu"
|
||||
|
||||
msgctxt "#30292"
|
||||
msgid "Select Subtitle Stream"
|
||||
msgstr "Vali subtiitrirada"
|
||||
|
||||
msgctxt "#30291"
|
||||
msgid "Select Audio Stream"
|
||||
msgstr "Vali heliriba"
|
||||
|
||||
msgctxt "#30290"
|
||||
msgid "All"
|
||||
msgstr "Kõik"
|
||||
|
||||
msgctxt "#30289"
|
||||
msgid "TV Shows - Genres"
|
||||
msgstr "Sarjad - žanrid"
|
||||
|
||||
msgctxt "#30288"
|
||||
msgid " - Latest"
|
||||
msgstr "- uued"
|
||||
|
||||
msgctxt "#30287"
|
||||
msgid "TV Shows - Latest"
|
||||
msgstr "Sarjad - uued"
|
||||
|
||||
msgctxt "#30286"
|
||||
msgid "Movies - Unwatched"
|
||||
msgstr "Filmid - vaatamata"
|
||||
|
||||
msgctxt "#30285"
|
||||
msgid " - Unwatched"
|
||||
msgstr "- vaatamata"
|
||||
|
||||
msgctxt "#30283"
|
||||
msgid "Play Next Episode?"
|
||||
msgstr "Kas esitada järgmine episood?"
|
||||
|
||||
msgctxt "#30282"
|
||||
msgid "No Jellyfin servers detected on your local network."
|
||||
msgstr "Kohtvõrgus ei tuvastatud Jellyfini servereid."
|
||||
|
||||
msgctxt "#30281"
|
||||
msgid "Refresh Cached Images"
|
||||
msgstr "Värskenda vahemällu salvestatud pilte"
|
||||
|
||||
msgctxt "#30280"
|
||||
msgid "Missing Title"
|
||||
msgstr "Puuduv pealkiri"
|
||||
|
||||
msgctxt "#30279"
|
||||
msgid "TV Shows - Unwatched"
|
||||
msgstr "Sarjad - vaatamata"
|
||||
|
||||
msgctxt "#30278"
|
||||
msgid " - Next Up"
|
||||
msgstr "- järgmisena"
|
||||
|
||||
msgctxt "#30277"
|
||||
msgid "JellyCon needs to prompt for resume on partily played items, Kodi can also prompt, this can cause a double prompt. Do you want to remove the double prompt?"
|
||||
msgstr ""
|
||||
"JellyCon peab küsima jätkamist osaliselt esitatud üksuste puhul. Kodi võib "
|
||||
"samuti küsida ja see võib põhjustada päringu. Kas soovid topeltpäringu "
|
||||
"eemaldada?"
|
||||
|
||||
msgctxt "#30276"
|
||||
msgid "Extra Resume Prompt Detected"
|
||||
msgstr "Tuvastati täiendav jätkamise päring"
|
||||
|
||||
msgctxt "#30275"
|
||||
msgid "Force Transcode"
|
||||
msgstr "Sunnitud transkoodimine"
|
||||
|
||||
msgctxt "#30274"
|
||||
msgid "Delete"
|
||||
msgstr "Kustuta"
|
||||
|
||||
msgctxt "#30272"
|
||||
msgid "Set Favourite"
|
||||
msgstr "Määra lemmikuks"
|
||||
|
||||
msgctxt "#30271"
|
||||
msgid "Mark Unwatched"
|
||||
msgstr "Märgi mittevaadatuks"
|
||||
|
||||
msgctxt "#30270"
|
||||
msgid "Mark Watched"
|
||||
msgstr "Märgi vaadatuks"
|
||||
|
||||
msgctxt "#30269"
|
||||
msgid "Movies - Random"
|
||||
msgstr "Filmid – juhuslikud"
|
||||
|
||||
msgctxt "#30267"
|
||||
msgid " - In Progress"
|
||||
msgstr "- pooleli"
|
||||
|
||||
msgctxt "#30266"
|
||||
msgid "Movies - Pages"
|
||||
msgstr "Filmid – lehed"
|
||||
|
||||
msgctxt "#30265"
|
||||
msgid "Episodes - Next Up"
|
||||
msgstr "Episoodid – järgmine"
|
||||
|
||||
msgctxt "#30264"
|
||||
msgid "Episodes - In Progress"
|
||||
msgstr "Episoodid – pooleli"
|
||||
|
||||
msgctxt "#30262"
|
||||
msgid "TV Shows - Favorites"
|
||||
msgstr "Sarjad - lemmikud"
|
||||
|
||||
msgctxt "#30261"
|
||||
msgid "TV Shows"
|
||||
msgstr "Sarjad"
|
||||
|
||||
msgctxt "#30260"
|
||||
msgid "BoxSets"
|
||||
msgstr "Kogumikud"
|
||||
|
||||
msgctxt "#30259"
|
||||
msgid "Movies - Favorites"
|
||||
msgstr "Filmid – lemmikud"
|
||||
|
||||
msgctxt "#30258"
|
||||
msgid "Movies - In Progress"
|
||||
msgstr "Filmid – pooleli"
|
||||
|
||||
msgctxt "#30256"
|
||||
msgid "Movies"
|
||||
msgstr "Filmid"
|
||||
|
||||
msgctxt "#30255"
|
||||
msgid "TV Shows - A-Z"
|
||||
msgstr "Sarjad - A-Ü"
|
||||
|
||||
msgctxt "#30254"
|
||||
msgid "Show add-on settings"
|
||||
msgstr "Kuva lisamooduli seaded"
|
||||
|
||||
msgctxt "#30252"
|
||||
msgid "Movies - A-Z"
|
||||
msgstr "Filmid – A-Ü"
|
||||
|
||||
msgctxt "#30251"
|
||||
msgid "Movies - Genres"
|
||||
msgstr "Filmid – žanrid"
|
||||
|
||||
msgctxt "#30250"
|
||||
msgid "Unknown"
|
||||
msgstr "Teadmata"
|
||||
|
||||
msgctxt "#30246"
|
||||
msgid "Search"
|
||||
msgstr "Otsi"
|
||||
|
||||
msgctxt "#30239"
|
||||
msgid "Force transcode mpeg2"
|
||||
msgstr "Transkoodi jõuga mpeg2"
|
||||
|
||||
msgctxt "#30238"
|
||||
msgid "Playback stream options"
|
||||
msgstr "Taasesituse striimimise valikud"
|
||||
|
||||
msgctxt "#30237"
|
||||
msgid "Start from beginning"
|
||||
msgstr "Alusta algusest"
|
||||
|
||||
msgctxt "#30236"
|
||||
msgid "Force transcode h265 (hevc)"
|
||||
msgstr "Transkoodi jõuga h265 (hevc)"
|
||||
|
||||
msgctxt "#30235"
|
||||
msgid "Episodes"
|
||||
msgstr "Episoodid"
|
||||
|
||||
msgctxt "#30231"
|
||||
msgid "Movies"
|
||||
msgstr "Filmid"
|
||||
|
||||
msgctxt "#30229"
|
||||
msgid "TV Shows"
|
||||
msgstr "Sarjad"
|
||||
|
||||
msgctxt "#30223"
|
||||
msgid "Page Size and Filtering"
|
||||
msgstr "Lehekülje suurus ja filtreerimine"
|
||||
|
||||
msgctxt "#30222"
|
||||
msgid "Item Layout"
|
||||
msgstr "Üksuse paigutus"
|
||||
|
||||
msgctxt "#30220"
|
||||
msgid "Prompt to delete movie after %"
|
||||
msgstr "Paku filmi kustutamist pärast %"
|
||||
|
||||
msgctxt "#30219"
|
||||
msgid " - Prompt before play"
|
||||
msgstr "- Küsi enne esitust"
|
||||
|
||||
msgctxt "#30218"
|
||||
msgid "Play next episode after %"
|
||||
msgstr "Esita järgmine episood pärast %"
|
||||
|
||||
msgctxt "#30217"
|
||||
msgid "Prompt to delete episode after %"
|
||||
msgstr "Paku episoodi kustutamist pärast %"
|
||||
|
||||
msgctxt "#30216"
|
||||
msgid "Item Details"
|
||||
msgstr "Üksuse üksikasjad"
|
||||
|
||||
msgctxt "#30215"
|
||||
msgid "On playback stop (100% = disabled)"
|
||||
msgstr "Taasesituse peatamisel (100% = keelatud)"
|
||||
|
||||
msgctxt "#30214"
|
||||
msgid "Events"
|
||||
msgstr "Sündmused"
|
||||
|
||||
msgctxt "#30212"
|
||||
msgid "Video max width"
|
||||
msgstr "Video maksimaalne laius"
|
||||
|
||||
msgctxt "#30211"
|
||||
msgid "Transcode options"
|
||||
msgstr "Transkoodimise valikud"
|
||||
|
||||
msgctxt "#30210"
|
||||
msgid "HTTP direct stream"
|
||||
msgstr "HTTP otsevoog"
|
||||
|
||||
msgctxt "#30000"
|
||||
msgid "Host"
|
||||
msgstr "Peremeesmasin"
|
||||
|
||||
msgctxt "#30182"
|
||||
msgid "Include media stream info"
|
||||
msgstr "Kaasa meediavoo teave"
|
||||
|
||||
msgctxt "#30208"
|
||||
msgid "Max stream bitrate (Kbits)"
|
||||
msgstr "Voo maksimaalne bitikiirus (Kbps)"
|
||||
|
||||
msgctxt "#30207"
|
||||
msgid "Playback"
|
||||
msgstr "Taasesitus"
|
||||
|
||||
msgctxt "#30206"
|
||||
msgid "Playback type"
|
||||
msgstr "Taasesituse tüüp"
|
||||
|
||||
msgctxt "#30201"
|
||||
msgid "Unable to connect to server"
|
||||
msgstr "Serveriga ei saa ühendust"
|
||||
|
||||
msgctxt "#30200"
|
||||
msgid "URL error"
|
||||
msgstr "URL viga"
|
||||
|
||||
msgctxt "#30183"
|
||||
msgid "Include people"
|
||||
msgstr "Kaasa inimesed"
|
||||
|
||||
msgctxt "#30181"
|
||||
msgid "Include plot"
|
||||
msgstr "Kaasa süžee"
|
||||
|
||||
msgctxt "#30180"
|
||||
msgid "Select User"
|
||||
msgstr "Vali kasutaja"
|
||||
|
||||
msgctxt "#30169"
|
||||
msgid "Address: "
|
||||
msgstr "Aadress:"
|
||||
|
||||
msgctxt "#30167"
|
||||
msgid "Selected Server Address"
|
||||
msgstr "Valitud serveri aadress"
|
||||
|
||||
msgctxt "#30166"
|
||||
msgid "Select Server"
|
||||
msgstr "Vali server"
|
||||
|
||||
msgctxt "#30163"
|
||||
msgid "Add (cc) if subtitle is available"
|
||||
msgstr "Lisa (cc) subtiitrite olemasolul"
|
||||
|
||||
msgctxt "#30139"
|
||||
msgid "No Media Type Set"
|
||||
msgstr "Meediatüüp määramata"
|
||||
|
||||
msgctxt "#30135"
|
||||
msgid "Error"
|
||||
msgstr "Viga"
|
||||
|
||||
msgctxt "#30126"
|
||||
msgid "Processing Item : "
|
||||
msgstr "Üksuse töötlemine:"
|
||||
|
||||
msgctxt "#30125"
|
||||
msgid "Done"
|
||||
msgstr "Tehtud"
|
||||
|
||||
msgctxt "#30121"
|
||||
msgid "On resume"
|
||||
msgstr "Jätkamisel"
|
||||
|
||||
msgctxt "#30120"
|
||||
msgid "Show load progress"
|
||||
msgstr "Kuva laadimise edenemine"
|
||||
|
||||
msgctxt "#30116"
|
||||
msgid "Add unwatched counts to names"
|
||||
msgstr "Lisa nimedele vaatamata arv"
|
||||
|
||||
msgctxt "#30118"
|
||||
msgid "Add resume percent to names"
|
||||
msgstr "Lisa nimedele jätkamise protsent"
|
||||
|
||||
msgctxt "#30114"
|
||||
msgid "Jump back seconds"
|
||||
msgstr "Tagasihüpe (sek)"
|
||||
|
||||
msgctxt "#30113"
|
||||
msgid "Retrieving Data"
|
||||
msgstr "Andmete toomine"
|
||||
|
||||
msgctxt "#30112"
|
||||
msgid "Loading Content"
|
||||
msgstr "Sisu laadimine"
|
||||
|
||||
msgctxt "#30111"
|
||||
msgid "Services"
|
||||
msgstr "Teenused"
|
||||
|
||||
msgctxt "#30110"
|
||||
msgid "Interface"
|
||||
msgstr "Liides"
|
||||
|
||||
msgctxt "#30092"
|
||||
msgid "Warning: This action will delete the media files from the server."
|
||||
msgstr "Hoiatus: see toiming kustutab meediafailid serverist."
|
||||
|
||||
msgctxt "#30091"
|
||||
msgid "Confirm delete?"
|
||||
msgstr "Kas kinnitada kustutamine?"
|
||||
|
||||
msgctxt "#30063"
|
||||
msgid "N/A"
|
||||
msgstr "Pole saadaval"
|
||||
|
||||
msgctxt "#30053"
|
||||
msgid "Waiting for server to delete"
|
||||
msgstr "Serveri kustutamise ootel"
|
||||
|
||||
msgctxt "#30052"
|
||||
msgid "Deleting"
|
||||
msgstr "Kustutamine"
|
||||
|
||||
msgctxt "#30045"
|
||||
msgid "Username not found"
|
||||
msgstr "Kasutajanime ei leitud"
|
||||
|
||||
msgctxt "#30044"
|
||||
msgid "Incorrect Username/Password"
|
||||
msgstr "Vale kasutajanimi/parool"
|
||||
|
||||
msgctxt "#30027"
|
||||
msgid "Enable debug logging"
|
||||
msgstr "Luba silumislogimine"
|
||||
|
||||
msgctxt "#30026"
|
||||
msgid "Widget item select action"
|
||||
msgstr "Vidina toiming üksuse valikul"
|
||||
|
||||
msgctxt "#30025"
|
||||
msgid "Password:"
|
||||
msgstr "Parool:"
|
||||
|
||||
msgctxt "#30024"
|
||||
msgid "Username:"
|
||||
msgstr "Kasutajanimi:"
|
||||
|
||||
msgctxt "#30023"
|
||||
msgid "Hide unwatched episode details"
|
||||
msgstr "Peida vaatamata episoodi üksikasjad"
|
||||
|
||||
msgctxt "#30022"
|
||||
msgid "Advanced"
|
||||
msgstr "Täpsem"
|
||||
1155
resources/language/resource.language.fi/strings.po
Normal file
1155
resources/language/resource.language.fi/strings.po
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,2 +1,720 @@
|
||||
msgid ""
|
||||
msgstr "X-Generator: Weblate\nMIME-Version: 1.0\nContent-Type: text/plain; charset=UTF-8\nContent-Transfer-Encoding: 8bit"
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2024-07-05 15:41+0000\n"
|
||||
"Last-Translator: Viswanadha Y Manu Sharma <manu.viswanad@gmail.com>\n"
|
||||
"Language-Team: Hindi <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/hi/>\n"
|
||||
"Language: hi\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
||||
"X-Generator: Weblate 5.4.2\n"
|
||||
|
||||
msgctxt "#30407"
|
||||
msgid "Global Lists"
|
||||
msgstr "वैश्विक सूची"
|
||||
|
||||
msgctxt "#30408"
|
||||
msgid "Custom Widgets"
|
||||
msgstr "कस्टम विड्जेट"
|
||||
|
||||
msgctxt "#30409"
|
||||
msgid "Add-on Actions"
|
||||
msgstr "अतिरिक्त कार्य"
|
||||
|
||||
msgctxt "#30410"
|
||||
msgid " - Collections"
|
||||
msgstr "संग्रह"
|
||||
|
||||
msgctxt "#30417"
|
||||
msgid "You do not have permision to delete this item"
|
||||
msgstr "आपके पास इस वस्तु को मिटाने की अनुमति नहीं है"
|
||||
|
||||
msgctxt "#30416"
|
||||
msgid "HTTP timeout seconds"
|
||||
msgstr "एचटीटीपी के समय समाप्ति (सेकड़ो में)"
|
||||
|
||||
msgctxt "#30413"
|
||||
msgid " - Tags"
|
||||
msgstr "चिप्पी"
|
||||
|
||||
msgctxt "#30418"
|
||||
msgid "Audio bitrate (Kbits)"
|
||||
msgstr "ऑडियो बितरते (किलो बिट प्रति घंटा)"
|
||||
|
||||
msgctxt "#30419"
|
||||
msgid "Audio codec"
|
||||
msgstr "ऑडियो कोडेक"
|
||||
|
||||
msgctxt "#30420"
|
||||
msgid "Audio max channels"
|
||||
msgstr "अधिकतम ऑडियो चैनल"
|
||||
|
||||
msgctxt "#30421"
|
||||
msgid "Views"
|
||||
msgstr "कितनी बार देखा गया"
|
||||
|
||||
msgctxt "#30422"
|
||||
msgid "Sorting"
|
||||
msgstr "छंटाई"
|
||||
|
||||
msgctxt "#30423"
|
||||
msgid "NotSet"
|
||||
msgstr "नहीं लगाया गया"
|
||||
|
||||
msgctxt "#30424"
|
||||
msgid "Default"
|
||||
msgstr "पहले से चुना हुआ"
|
||||
|
||||
msgctxt "#30425"
|
||||
msgid "Year"
|
||||
msgstr "साल"
|
||||
|
||||
msgctxt "#30434"
|
||||
msgid "Force transcode stream bitrate (Kbits)"
|
||||
msgstr "जबरदस्ती बिट्रेट तय करे (किलो बिट प्रति सेकंड)"
|
||||
|
||||
msgctxt "#30436"
|
||||
msgid "Speed test data size (MB)"
|
||||
msgstr "इंटरनेट की रफ़्तार नापने के लिए डाटा का माप (मेगा बाईट)"
|
||||
|
||||
msgctxt "#30433"
|
||||
msgid "Allow direct file playback"
|
||||
msgstr "सीधे फाइल से प्लेबैक की अनुमति दें"
|
||||
|
||||
msgctxt "#30437"
|
||||
msgid "Playback options"
|
||||
msgstr "चलने के विकल्प दिखाएं"
|
||||
|
||||
msgctxt "#30439"
|
||||
msgid "Show play next episode at time left"
|
||||
msgstr "कितने समय पहले अगले अध्याय पर जाने का बटन दिखाएं"
|
||||
|
||||
msgctxt "#30438"
|
||||
msgid "Play cinema intros"
|
||||
msgstr "सिनेमा उपक्षेप चलायें"
|
||||
|
||||
msgctxt "#30441"
|
||||
msgid "Use cached widget data"
|
||||
msgstr "पुराणी विद्गट जानकारी इस्तेमाल करें"
|
||||
|
||||
msgctxt "#30442"
|
||||
msgid "Simple new content check"
|
||||
msgstr "नए कंटेंट के लिए चेक करें"
|
||||
|
||||
msgctxt "#30435"
|
||||
msgid "Connection speed test"
|
||||
msgstr "कनेक्शन की स्पीड नापें"
|
||||
|
||||
msgctxt "#30440"
|
||||
msgid "Play next"
|
||||
msgstr "अगला चलाएं"
|
||||
|
||||
msgctxt "#30114"
|
||||
msgid "Jump back seconds"
|
||||
msgstr "कुछ सेकंड पीछे जाएं"
|
||||
|
||||
msgctxt "#30113"
|
||||
msgid "Retrieving Data"
|
||||
msgstr "देता प्राप्त कर रहे है"
|
||||
|
||||
msgctxt "#30112"
|
||||
msgid "Loading Content"
|
||||
msgstr "कंटेंट लोड हो रहा है"
|
||||
|
||||
msgctxt "#30027"
|
||||
msgid "Enable debug logging"
|
||||
msgstr "डीबग सूचि बनाएं"
|
||||
|
||||
msgctxt "#30026"
|
||||
msgid "Widget item select action"
|
||||
msgstr "विद्गट वास्तु का कार्य चुनें"
|
||||
|
||||
msgctxt "#30020"
|
||||
msgid "Flatten single season"
|
||||
msgstr "सिर्फ एक सत्र वाले शो के लिए सत्र पेज हटाएं"
|
||||
|
||||
msgctxt "#30415"
|
||||
msgid " - Favorite Collections"
|
||||
msgstr "पसंदीदा संग्रह"
|
||||
|
||||
msgctxt "#30414"
|
||||
msgid " - Favorites"
|
||||
msgstr "पसंदीदा"
|
||||
|
||||
msgctxt "#30411"
|
||||
msgid " - Years"
|
||||
msgstr "साल"
|
||||
|
||||
msgctxt "#30399"
|
||||
msgid "Hide"
|
||||
msgstr "छुपाएँ"
|
||||
|
||||
msgctxt "#30412"
|
||||
msgid " - Decades"
|
||||
msgstr "दशक"
|
||||
|
||||
msgctxt "#30432"
|
||||
msgid "Hide watched items in lists"
|
||||
msgstr "देखि हुईं वस्तुएं हटाएं"
|
||||
|
||||
msgctxt "#30431"
|
||||
msgid "Seasons"
|
||||
msgstr "सत्र"
|
||||
|
||||
msgctxt "#30430"
|
||||
msgid "Label"
|
||||
msgstr "लेबल"
|
||||
|
||||
msgctxt "#30427"
|
||||
msgid "Added"
|
||||
msgstr "जोड़ा हुआ"
|
||||
|
||||
msgctxt "#30426"
|
||||
msgid "Title"
|
||||
msgstr "शीर्षक"
|
||||
|
||||
msgctxt "#30428"
|
||||
msgid "Rating"
|
||||
msgstr "रेटिंग"
|
||||
|
||||
msgctxt "#30429"
|
||||
msgid "Genre"
|
||||
msgstr "शैली"
|
||||
|
||||
msgctxt "#30019"
|
||||
msgid "Filtered episode name format"
|
||||
msgstr "छठें हुएं अध्यायों के नामों का प्रारूप"
|
||||
|
||||
msgctxt "#30018"
|
||||
msgid "Number of items to show in filtered lists"
|
||||
msgstr "छांटी हुई सूचि में कितने वास्तु दिखाए"
|
||||
|
||||
msgctxt "#30015"
|
||||
msgid "Log timing data"
|
||||
msgstr "समय की जानकारी लिखें"
|
||||
|
||||
msgctxt "#30016"
|
||||
msgid "Device display name"
|
||||
msgstr "उपकरण का नाम"
|
||||
|
||||
msgctxt "#30017"
|
||||
msgid "Show connected clients"
|
||||
msgstr "जुड़े हुए क्लाइंट्स दिखाएं"
|
||||
|
||||
msgctxt "#30023"
|
||||
msgid "Hide unwatched episode details"
|
||||
msgstr "अंधेके एपिसोडों का विवरण हटाएँ"
|
||||
|
||||
msgctxt "#30021"
|
||||
msgid "Show all episodes item"
|
||||
msgstr "सारे एपिसोड दिखाएं"
|
||||
|
||||
msgctxt "#30025"
|
||||
msgid "Password:"
|
||||
msgstr "पासवर्ड :"
|
||||
|
||||
msgctxt "#30246"
|
||||
msgid "Search"
|
||||
msgstr "खोज"
|
||||
|
||||
msgctxt "#30235"
|
||||
msgid "Episodes"
|
||||
msgstr "अध्याय"
|
||||
|
||||
msgctxt "#30229"
|
||||
msgid "TV Shows"
|
||||
msgstr "टीवी शो"
|
||||
|
||||
msgctxt "#30231"
|
||||
msgid "Movies"
|
||||
msgstr "फ़िल्म"
|
||||
|
||||
msgctxt "#30216"
|
||||
msgid "Item Details"
|
||||
msgstr "वास्तु का विवरण"
|
||||
|
||||
msgctxt "#30169"
|
||||
msgid "Address: "
|
||||
msgstr "पता :"
|
||||
|
||||
msgctxt "#30044"
|
||||
msgid "Incorrect Username/Password"
|
||||
msgstr "गलत उपयोगरता का नाम / पासवर्ड"
|
||||
|
||||
msgctxt "#30045"
|
||||
msgid "Username not found"
|
||||
msgstr "उपयोगकर्ता का नाम नहीं पाया गया"
|
||||
|
||||
msgctxt "#30022"
|
||||
msgid "Advanced"
|
||||
msgstr "उन्नत"
|
||||
|
||||
msgctxt "#30092"
|
||||
msgid "Warning: This action will delete the media files from the server."
|
||||
msgstr "चेतावनी : यह कार्य आपकी मिडिया मिटा देगा |"
|
||||
|
||||
msgctxt "#30135"
|
||||
msgid "Error"
|
||||
msgstr "समस्या"
|
||||
|
||||
msgctxt "#30125"
|
||||
msgid "Done"
|
||||
msgstr "खत्म"
|
||||
|
||||
msgctxt "#30181"
|
||||
msgid "Include plot"
|
||||
msgstr "कहानी जोड़ें"
|
||||
|
||||
msgctxt "#30180"
|
||||
msgid "Select User"
|
||||
msgstr "उपयोगकर्ता चुनें"
|
||||
|
||||
msgctxt "#30167"
|
||||
msgid "Selected Server Address"
|
||||
msgstr "चुनें हुए सर्वर का पता"
|
||||
|
||||
msgctxt "#30166"
|
||||
msgid "Select Server"
|
||||
msgstr "सर्वर चुनें"
|
||||
|
||||
msgctxt "#30111"
|
||||
msgid "Services"
|
||||
msgstr "सेवाएं"
|
||||
|
||||
msgctxt "#30110"
|
||||
msgid "Interface"
|
||||
msgstr "अंतराफलक"
|
||||
|
||||
msgctxt "#30091"
|
||||
msgid "Confirm delete?"
|
||||
msgstr "क्या आप पक्का मिटाना चाहतें हैं?"
|
||||
|
||||
msgctxt "#30063"
|
||||
msgid "N/A"
|
||||
msgstr "उपलब्ध नहीं है"
|
||||
|
||||
msgctxt "#30053"
|
||||
msgid "Waiting for server to delete"
|
||||
msgstr "सर्वर द्वारा हटाए जानें का इंतज़ार कर रहें हैं"
|
||||
|
||||
msgctxt "#30052"
|
||||
msgid "Deleting"
|
||||
msgstr "हटा रहें हैं"
|
||||
|
||||
msgctxt "#30024"
|
||||
msgid "Username:"
|
||||
msgstr "उपयोगकर्ता का नाम :"
|
||||
|
||||
msgctxt "#30010"
|
||||
msgid "Number of performance profiles to capture"
|
||||
msgstr "कितने कार्य प्रोफाइल रखने हैं"
|
||||
|
||||
msgctxt "#30011"
|
||||
msgid "[Detect local server]"
|
||||
msgstr "स्थानीय सर्वर का पता करें"
|
||||
|
||||
msgctxt "#30012"
|
||||
msgid "[Change user]"
|
||||
msgstr "उपयोगकर्ता बदलें"
|
||||
|
||||
msgctxt "#30014"
|
||||
msgid "Jellyfin"
|
||||
msgstr "जेलीफिन"
|
||||
|
||||
msgctxt "#30008"
|
||||
msgid "Samba password"
|
||||
msgstr "साम्बा में पासवर्ड"
|
||||
|
||||
msgctxt "#30007"
|
||||
msgid "Samba username"
|
||||
msgstr "साम्बा में उपयोगकर्ता का नाम"
|
||||
|
||||
msgctxt "#30006"
|
||||
msgid "Password"
|
||||
msgstr "पासवर्ड"
|
||||
|
||||
msgctxt "#30005"
|
||||
msgid "Username"
|
||||
msgstr "उपयोगकर्ता का नाम"
|
||||
|
||||
msgctxt "#30003"
|
||||
msgid "Verify HTTPS certificate"
|
||||
msgstr "HTTPS प्रमाणपत्र की जांच करें"
|
||||
|
||||
msgctxt "#30001"
|
||||
msgid "Port"
|
||||
msgstr "द्वार"
|
||||
|
||||
msgctxt "#30000"
|
||||
msgid "Host"
|
||||
msgstr "आतिथेय"
|
||||
|
||||
msgctxt "#30118"
|
||||
msgid "Add resume percent to names"
|
||||
msgstr "नामों में फिर शुरू करनेका प्रतिशत जोड़ें"
|
||||
|
||||
msgctxt "#30116"
|
||||
msgid "Add unwatched counts to names"
|
||||
msgstr "नामों में न देखी गई गिनती जोड़ें"
|
||||
|
||||
msgctxt "#30120"
|
||||
msgid "Show load progress"
|
||||
msgstr "लोड प्रगति दिखाएं"
|
||||
|
||||
msgctxt "#30121"
|
||||
msgid "On resume"
|
||||
msgstr "फिर से शुरू करने पर"
|
||||
|
||||
msgctxt "#30139"
|
||||
msgid "No Media Type Set"
|
||||
msgstr "कोई मीडिया प्रकार सेट नहीं"
|
||||
|
||||
msgctxt "#30183"
|
||||
msgid "Include people"
|
||||
msgstr "लोगों को शामिल करें"
|
||||
|
||||
msgctxt "#30208"
|
||||
msgid "Max stream bitrate (Kbits)"
|
||||
msgstr "अधिकतम स्ट्रीम बिटरेट (Kbps)"
|
||||
|
||||
msgctxt "#30212"
|
||||
msgid "Video max width"
|
||||
msgstr "वीडियो की अधिकतम चौड़ाई"
|
||||
|
||||
msgctxt "#30217"
|
||||
msgid "Prompt to delete episode after %"
|
||||
msgstr "% के बाद एपिसोड हटाने का संकेत"
|
||||
|
||||
msgctxt "#30219"
|
||||
msgid " - Prompt before play"
|
||||
msgstr "- खेलने से पहले संकेत दें"
|
||||
|
||||
msgctxt "#30220"
|
||||
msgid "Prompt to delete movie after %"
|
||||
msgstr "% के बाद मूवी हटाने का संकेत"
|
||||
|
||||
msgctxt "#30257"
|
||||
msgid "Movies - Recently Added"
|
||||
msgstr "फ़िल्में - हाल ही में जोड़ी गईं"
|
||||
|
||||
msgctxt "#30265"
|
||||
msgid "Episodes - Next Up"
|
||||
msgstr "एपिसोड - अगला"
|
||||
|
||||
msgctxt "#30163"
|
||||
msgid "Add (cc) if subtitle is available"
|
||||
msgstr "यदि उपशीर्षक उपलब्ध है तो (सीसी) जोड़ें"
|
||||
|
||||
msgctxt "#30182"
|
||||
msgid "Include media stream info"
|
||||
msgstr "मीडिया स्ट्रीम जानकारी शामिल करें"
|
||||
|
||||
msgctxt "#30200"
|
||||
msgid "URL error"
|
||||
msgstr "यूआरएल त्रुटि"
|
||||
|
||||
msgctxt "#30201"
|
||||
msgid "Unable to connect to server"
|
||||
msgstr "सर्वर से कनेक्ट करने में असमर्थ है"
|
||||
|
||||
msgctxt "#30206"
|
||||
msgid "Playback type"
|
||||
msgstr "प्लेबैक प्रकार"
|
||||
|
||||
msgctxt "#30207"
|
||||
msgid "Playback"
|
||||
msgstr "प्लेबैक"
|
||||
|
||||
msgctxt "#30209"
|
||||
msgid "File direct path"
|
||||
msgstr "फ़ाइल का सीधा पथ"
|
||||
|
||||
msgctxt "#30210"
|
||||
msgid "HTTP direct stream"
|
||||
msgstr "HTTP डायरेक्ट स्ट्रीम"
|
||||
|
||||
msgctxt "#30211"
|
||||
msgid "Transcode options"
|
||||
msgstr "ट्रांसकोड विकल्प"
|
||||
|
||||
msgctxt "#30213"
|
||||
msgid "Video force 8 bit"
|
||||
msgstr "वीडियो बल 8 बिट"
|
||||
|
||||
msgctxt "#30214"
|
||||
msgid "Events"
|
||||
msgstr "आयोजन"
|
||||
|
||||
msgctxt "#30215"
|
||||
msgid "On playback stop (100% = disabled)"
|
||||
msgstr "प्लेबैक स्टॉप पर (100% = अक्षम)"
|
||||
|
||||
msgctxt "#30218"
|
||||
msgid "Play next episode after %"
|
||||
msgstr "% के बाद अगला एपिसोड चलाएं"
|
||||
|
||||
msgctxt "#30222"
|
||||
msgid "Item Layout"
|
||||
msgstr "आइटम लेआउट"
|
||||
|
||||
msgctxt "#30223"
|
||||
msgid "Page Size and Filtering"
|
||||
msgstr "पृष्ठ आकार और फ़िल्टरिंग"
|
||||
|
||||
msgctxt "#30224"
|
||||
msgid "Interaction"
|
||||
msgstr "इंटरैक्शन"
|
||||
|
||||
msgctxt "#30258"
|
||||
msgid "Movies - In Progress"
|
||||
msgstr "फ़िल्में - प्रगति पर हैं"
|
||||
|
||||
msgctxt "#30126"
|
||||
msgid "Processing Item : "
|
||||
msgstr "आइटम का प्रसंस्करण:"
|
||||
|
||||
msgctxt "#30267"
|
||||
msgid " - In Progress"
|
||||
msgstr "- प्रगति पर है"
|
||||
|
||||
msgctxt "#30268"
|
||||
msgid " - Recently Added"
|
||||
msgstr "- हाल ही में जोड़ा"
|
||||
|
||||
msgctxt "#30225"
|
||||
msgid "Interface Mode"
|
||||
msgstr "इंटरफ़ेस मोड"
|
||||
|
||||
msgctxt "#30226"
|
||||
msgid "Default"
|
||||
msgstr "डिफ़ॉल्ट"
|
||||
|
||||
msgctxt "#30227"
|
||||
msgid "Simple"
|
||||
msgstr "सरल"
|
||||
|
||||
msgctxt "#30236"
|
||||
msgid "Force transcode h265 (hevc)"
|
||||
msgstr "फोर्स ट्रांसकोड h265 (hevc)"
|
||||
|
||||
msgctxt "#30237"
|
||||
msgid "Start from beginning"
|
||||
msgstr "शुरू से शुरू करो"
|
||||
|
||||
msgctxt "#30238"
|
||||
msgid "Playback stream options"
|
||||
msgstr "प्लेबैक स्ट्रीम विकल्प"
|
||||
|
||||
msgctxt "#30239"
|
||||
msgid "Force transcode mpeg2"
|
||||
msgstr "फोर्स ट्रांसकोड mpeg2"
|
||||
|
||||
msgctxt "#30240"
|
||||
msgid "Force transcode msmpeg4v3 (divx)"
|
||||
msgstr "फोर्स ट्रांसकोड msmpeg4v3 (divx)"
|
||||
|
||||
msgctxt "#30241"
|
||||
msgid "Force transcode mpeg4"
|
||||
msgstr "फोर्स ट्रांसकोड mpeg4"
|
||||
|
||||
msgctxt "#30247"
|
||||
msgid "Custom Widget Content"
|
||||
msgstr "कस्टम विजेट सामग्री"
|
||||
|
||||
msgctxt "#30250"
|
||||
msgid "Unknown"
|
||||
msgstr "अज्ञात"
|
||||
|
||||
msgctxt "#30251"
|
||||
msgid "Movies - Genres"
|
||||
msgstr "फ़िल्में - शैलियाँ"
|
||||
|
||||
msgctxt "#30252"
|
||||
msgid "Movies - A-Z"
|
||||
msgstr "फ़िल्में - ए-जेड"
|
||||
|
||||
msgctxt "#30254"
|
||||
msgid "Show add-on settings"
|
||||
msgstr "ऐड-ऑन सेटिंग दिखाएं"
|
||||
|
||||
msgctxt "#30255"
|
||||
msgid "TV Shows - A-Z"
|
||||
msgstr "टीवी शो - ए-जेड"
|
||||
|
||||
msgctxt "#30256"
|
||||
msgid "Movies"
|
||||
msgstr "फ़िल्म"
|
||||
|
||||
msgctxt "#30259"
|
||||
msgid "Movies - Favorites"
|
||||
msgstr "फ़िल्में - पसंदीदा"
|
||||
|
||||
msgctxt "#30260"
|
||||
msgid "BoxSets"
|
||||
msgstr "बॉक्ससेट"
|
||||
|
||||
msgctxt "#30261"
|
||||
msgid "TV Shows"
|
||||
msgstr "टीवी शो"
|
||||
|
||||
msgctxt "#30262"
|
||||
msgid "TV Shows - Favorites"
|
||||
msgstr "टीवी शो - पसंदीदा"
|
||||
|
||||
msgctxt "#30263"
|
||||
msgid "Episodes - Recently Added"
|
||||
msgstr "एपिसोड - हाल ही में जोड़े गए"
|
||||
|
||||
msgctxt "#30264"
|
||||
msgid "Episodes - In Progress"
|
||||
msgstr "एपिसोड - प्रगति पर है"
|
||||
|
||||
msgctxt "#30266"
|
||||
msgid "Movies - Pages"
|
||||
msgstr "फ़िल्में - पन्ने"
|
||||
|
||||
msgctxt "#30269"
|
||||
msgid "Movies - Random"
|
||||
msgstr "फ़िल्में - यादृच्छिक"
|
||||
|
||||
msgctxt "#30270"
|
||||
msgid "Mark Watched"
|
||||
msgstr "मार्क वॉचड"
|
||||
|
||||
msgctxt "#30271"
|
||||
msgid "Mark Unwatched"
|
||||
msgstr "मार्क अनवॉच्ड"
|
||||
|
||||
msgctxt "#30272"
|
||||
msgid "Set Favourite"
|
||||
msgstr "पसंदीदा सेट करें"
|
||||
|
||||
msgctxt "#30273"
|
||||
msgid "Unset Favourite"
|
||||
msgstr "पसंदीदा को अनसेट करें"
|
||||
|
||||
msgctxt "#30274"
|
||||
msgid "Delete"
|
||||
msgstr "मिटाना"
|
||||
|
||||
msgctxt "#30275"
|
||||
msgid "Force Transcode"
|
||||
msgstr "फोर्स ट्रांसकोड"
|
||||
|
||||
msgctxt "#30296"
|
||||
msgid "Delete"
|
||||
msgstr "मिटाना"
|
||||
|
||||
msgctxt "#30300"
|
||||
msgid "Cache all Jellyfin images as local Kodi images?"
|
||||
msgstr "सभी जेलीफ़िन छवियों को स्थानीय कोडी छवियों के रूप में कैश करें?"
|
||||
|
||||
msgctxt "#30301"
|
||||
msgid "Caching Images"
|
||||
msgstr "छवियाँ कैशिंग"
|
||||
|
||||
msgctxt "#30278"
|
||||
msgid " - Next Up"
|
||||
msgstr "- अगला"
|
||||
|
||||
msgctxt "#30302"
|
||||
msgid "Existing images : "
|
||||
msgstr "मौजूदा छवियाँ:"
|
||||
|
||||
msgctxt "#30242"
|
||||
msgid "Force transcode av1"
|
||||
msgstr "फोर्स ट्रांसकोड av1"
|
||||
|
||||
msgctxt "#30288"
|
||||
msgid " - Latest"
|
||||
msgstr "- नवीनतम"
|
||||
|
||||
msgctxt "#30289"
|
||||
msgid "TV Shows - Genres"
|
||||
msgstr "टीवी शो - शैलियाँ"
|
||||
|
||||
msgctxt "#30297"
|
||||
msgid "Delete unused images?"
|
||||
msgstr "अप्रयुक्त छवियाँ हटाएँ?"
|
||||
|
||||
msgctxt "#30298"
|
||||
msgid "Deleting Kodi Images"
|
||||
msgstr "कोडी छवियाँ हटाना"
|
||||
|
||||
msgctxt "#30299"
|
||||
msgid "Cache Images"
|
||||
msgstr "कैश छवियाँ"
|
||||
|
||||
msgctxt "#30303"
|
||||
msgid "Missing Jellyfin images : "
|
||||
msgstr "गुम जेलीफ़िन छवियाँ:"
|
||||
|
||||
msgctxt "#30279"
|
||||
msgid "TV Shows - Unwatched"
|
||||
msgstr "टीवी शो - नहीं देखे गए"
|
||||
|
||||
msgctxt "#30280"
|
||||
msgid "Missing Title"
|
||||
msgstr "गुम शीर्षक"
|
||||
|
||||
msgctxt "#30282"
|
||||
msgid "No Jellyfin servers detected on your local network."
|
||||
msgstr "आपके स्थानीय नेटवर्क पर कोई जेलीफ़िन सर्वर नहीं पाया गया।"
|
||||
|
||||
msgctxt "#30283"
|
||||
msgid "Play Next Episode?"
|
||||
msgstr "अगला एपिसोड खेलें?"
|
||||
|
||||
msgctxt "#30281"
|
||||
msgid "Refresh Cached Images"
|
||||
msgstr "कैश्ड छवियाँ ताज़ा करें"
|
||||
|
||||
msgctxt "#30285"
|
||||
msgid " - Unwatched"
|
||||
msgstr "- न देखा गया"
|
||||
|
||||
msgctxt "#30286"
|
||||
msgid "Movies - Unwatched"
|
||||
msgstr "फिल्में - नहीं देखी गईं"
|
||||
|
||||
msgctxt "#30287"
|
||||
msgid "TV Shows - Latest"
|
||||
msgstr "टीवी शो - नवीनतम"
|
||||
|
||||
msgctxt "#30294"
|
||||
msgid "Notice"
|
||||
msgstr "सूचना"
|
||||
|
||||
msgctxt "#30295"
|
||||
msgid "To use this feature you need HTTP control enabled"
|
||||
msgstr "इस सुविधा का उपयोग करने के लिए आपको HTTP नियंत्रण सक्षम करना होगा"
|
||||
|
||||
msgctxt "#30290"
|
||||
msgid "All"
|
||||
msgstr "सभी"
|
||||
|
||||
msgctxt "#30291"
|
||||
msgid "Select Audio Stream"
|
||||
msgstr "ऑडियो स्ट्रीम चुनें"
|
||||
|
||||
msgctxt "#30292"
|
||||
msgid "Select Subtitle Stream"
|
||||
msgstr "उपशीर्षक स्ट्रीम का चयन करें"
|
||||
|
||||
msgctxt "#30293"
|
||||
msgid "Cache images"
|
||||
msgstr "कैश छवियाँ"
|
||||
|
||||
msgctxt "#30304"
|
||||
msgid "Cached Jellyfin images : "
|
||||
msgstr "कैश्ड जेलीफ़िन छवियाँ:"
|
||||
|
||||
msgctxt "#30305"
|
||||
msgid "Not Found"
|
||||
msgstr "नहीं मिला"
|
||||
|
||||
msgctxt "#30306"
|
||||
msgid "Playback starting"
|
||||
msgstr "प्लेबैक प्रारंभ हो रहा है"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2021-11-14 13:05+0000\n"
|
||||
"Last-Translator: Csaba <csab0825@gmail.com>\n"
|
||||
"PO-Revision-Date: 2024-05-04 10:18+0000\n"
|
||||
"Last-Translator: Szilágyi Kristóf <kriny96@gmail.com>\n"
|
||||
"Language-Team: Hungarian <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/hu/>\n"
|
||||
"Language: hu\n"
|
||||
@@ -9,7 +9,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 4.5.2\n"
|
||||
"X-Generator: Weblate 5.4.2\n"
|
||||
|
||||
msgctxt "#30441"
|
||||
msgid "Use cached widget data"
|
||||
@@ -886,7 +886,7 @@ msgstr "Fájl közvetlen elérési útja"
|
||||
|
||||
msgctxt "#30208"
|
||||
msgid "Max stream bitrate (Kbits)"
|
||||
msgstr "Maximális streamelési bitsebesség (Kbit)"
|
||||
msgstr "Maximális streamelési bitsebesség (Kbit/s)"
|
||||
|
||||
msgctxt "#30207"
|
||||
msgid "Playback"
|
||||
@@ -1087,3 +1087,71 @@ msgstr "Port"
|
||||
msgctxt "#30000"
|
||||
msgid "Host"
|
||||
msgstr "Hoszt"
|
||||
|
||||
msgctxt "#30444"
|
||||
msgid "Login using Quick Connect"
|
||||
msgstr "Bejelentkezés Gyors Csatlakozással"
|
||||
|
||||
msgctxt "#30443"
|
||||
msgid "Quick Connect"
|
||||
msgstr "Gyors Csatlakozás"
|
||||
|
||||
msgctxt "#30323"
|
||||
msgid "Artists"
|
||||
msgstr "Művészek"
|
||||
|
||||
msgctxt "#30445"
|
||||
msgid "Continue Watching"
|
||||
msgstr "Megtekintés folytatása"
|
||||
|
||||
msgctxt "#30439"
|
||||
msgid "Show play next episode at time left in seconds"
|
||||
msgstr "A következő epizód lejátszása a másodpercben hátralévő időpontban"
|
||||
|
||||
msgctxt "#30446"
|
||||
msgid "There was an error logging in"
|
||||
msgstr "Hiba történt a bejelentkezéskor"
|
||||
|
||||
msgctxt "#30448"
|
||||
msgid "Shuffle"
|
||||
msgstr "Keverés"
|
||||
|
||||
msgctxt "#30447"
|
||||
msgid "Max Play Queue Size"
|
||||
msgstr "Lejátszási sor maximális mérete"
|
||||
|
||||
msgctxt "#30449"
|
||||
msgid "Instant Mix"
|
||||
msgstr "Instant keverés"
|
||||
|
||||
msgctxt "#30226"
|
||||
msgid "Default"
|
||||
msgstr "Alapértelmezett"
|
||||
|
||||
msgctxt "#30225"
|
||||
msgid "Interface Mode"
|
||||
msgstr "Interfész mód"
|
||||
|
||||
msgctxt "#30227"
|
||||
msgid "Simple"
|
||||
msgstr "Egyszerű"
|
||||
|
||||
msgctxt "#30242"
|
||||
msgid "Force transcode av1"
|
||||
msgstr "av1 transzkódolás kényszerítése"
|
||||
|
||||
msgctxt "#30450"
|
||||
msgid "Next Up Rewatching"
|
||||
msgstr "A Következő Újrajátszása"
|
||||
|
||||
msgctxt "#30451"
|
||||
msgid "Rewatch Days (0 = Disabled)"
|
||||
msgstr "Újrajátszási Napok (0=Kikapcsolva)"
|
||||
|
||||
msgctxt "#30452"
|
||||
msgid "Combine instead of replace (might cause slow-down)"
|
||||
msgstr "Egyesítés csere helyett (lassulást okozhat)"
|
||||
|
||||
msgctxt "#30453"
|
||||
msgid "Hide number of items to show on entry title"
|
||||
msgstr "Elemek számának rejtése a cím mellett"
|
||||
|
||||
1124
resources/language/resource.language.id/strings.po
Normal file
1124
resources/language/resource.language.id/strings.po
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2021-12-02 18:05+0000\n"
|
||||
"Last-Translator: Alfonso Scarpino <alfonso.scarpino@gmail.com>\n"
|
||||
"PO-Revision-Date: 2024-03-21 14:30+0000\n"
|
||||
"Last-Translator: VitoFe <vito-7@hotmail.it>\n"
|
||||
"Language-Team: Italian <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/it/>\n"
|
||||
"Language: it\n"
|
||||
@@ -9,11 +9,11 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 4.5.2\n"
|
||||
"X-Generator: Weblate 5.4.2\n"
|
||||
|
||||
msgctxt "#30120"
|
||||
msgid "Show load progress"
|
||||
msgstr "Mostra avanzamento del caricamento"
|
||||
msgstr "Mostra progressione del caricamento"
|
||||
|
||||
msgctxt "#30118"
|
||||
msgid "Add resume percent to names"
|
||||
@@ -97,7 +97,7 @@ msgstr "Avanzate"
|
||||
|
||||
msgctxt "#30021"
|
||||
msgid "Show all episodes item"
|
||||
msgstr "Mostra elemento tutti gli episodi"
|
||||
msgstr "Mostra tutti gli episodi"
|
||||
|
||||
msgctxt "#30020"
|
||||
msgid "Flatten single season"
|
||||
@@ -426,3 +426,723 @@ msgstr "Percorso diretto del file"
|
||||
msgctxt "#30208"
|
||||
msgid "Max stream bitrate (Kbits)"
|
||||
msgstr "Bitrate massimo del flusso (Kbits)"
|
||||
|
||||
msgctxt "#30277"
|
||||
msgid "JellyCon needs to prompt for resume on partily played items, Kodi can also prompt, this can cause a double prompt. Do you want to remove the double prompt?"
|
||||
msgstr ""
|
||||
"JellyCon richiede una finestra per continuare la riproduzione di elementi, "
|
||||
"anche Kodi può richiedere una finestra, causando lapertura di una doppia "
|
||||
"finestra. Vuoi rimuovere la doppia finestra?"
|
||||
|
||||
msgctxt "#30213"
|
||||
msgid "Video force 8 bit"
|
||||
msgstr "Forza video 8 bit"
|
||||
|
||||
msgctxt "#30114"
|
||||
msgid "Jump back seconds"
|
||||
msgstr "Riavvolgi secondi"
|
||||
|
||||
msgctxt "#30331"
|
||||
msgid "Movies per page"
|
||||
msgstr "Film per pagina"
|
||||
|
||||
msgctxt "#30329"
|
||||
msgid "Screensaver"
|
||||
msgstr "Salvaschermo"
|
||||
|
||||
msgctxt "#30337"
|
||||
msgid "Song"
|
||||
msgstr "Canzone"
|
||||
|
||||
msgctxt "#30327"
|
||||
msgid "Go To Season"
|
||||
msgstr "Vai Alla Stagione"
|
||||
|
||||
msgctxt "#30325"
|
||||
msgid " - Genres"
|
||||
msgstr "- Generi"
|
||||
|
||||
msgctxt "#30323"
|
||||
msgid "Artists"
|
||||
msgstr "Artisti"
|
||||
|
||||
msgctxt "#30311"
|
||||
msgid "Library - "
|
||||
msgstr "Libreria -"
|
||||
|
||||
msgctxt "#30296"
|
||||
msgid "Delete"
|
||||
msgstr "Elimina"
|
||||
|
||||
msgctxt "#30288"
|
||||
msgid " - Latest"
|
||||
msgstr "- Ultimo"
|
||||
|
||||
msgctxt "#30280"
|
||||
msgid "Missing Title"
|
||||
msgstr "Titolo Mancante"
|
||||
|
||||
msgctxt "#30278"
|
||||
msgid " - Next Up"
|
||||
msgstr "- Prossimo"
|
||||
|
||||
msgctxt "#30312"
|
||||
msgid "All - "
|
||||
msgstr "Tutto -"
|
||||
|
||||
msgctxt "#30320"
|
||||
msgid " - Albums"
|
||||
msgstr "- Album"
|
||||
|
||||
msgctxt "#30279"
|
||||
msgid "TV Shows - Unwatched"
|
||||
msgstr "Serie TV - Non guardati"
|
||||
|
||||
msgctxt "#30282"
|
||||
msgid "No Jellyfin servers detected on your local network."
|
||||
msgstr "Nessun server Jellyfin rilevato nella tua rete locale."
|
||||
|
||||
msgctxt "#30286"
|
||||
msgid "Movies - Unwatched"
|
||||
msgstr "Film - Non guardati"
|
||||
|
||||
msgctxt "#30287"
|
||||
msgid "TV Shows - Latest"
|
||||
msgstr "Serie TV - Ultimi"
|
||||
|
||||
msgctxt "#30289"
|
||||
msgid "TV Shows - Genres"
|
||||
msgstr "Serie TV - Generi"
|
||||
|
||||
msgctxt "#30290"
|
||||
msgid "All"
|
||||
msgstr "Tutti"
|
||||
|
||||
msgctxt "#30291"
|
||||
msgid "Select Audio Stream"
|
||||
msgstr "Seleziona fonte audio"
|
||||
|
||||
msgctxt "#30297"
|
||||
msgid "Delete unused images?"
|
||||
msgstr "Eliminare immagini non usati?"
|
||||
|
||||
msgctxt "#30305"
|
||||
msgid "Not Found"
|
||||
msgstr "Non trovato"
|
||||
|
||||
msgctxt "#30306"
|
||||
msgid "Playback starting"
|
||||
msgstr "Avvio riproduzione"
|
||||
|
||||
msgctxt "#30307"
|
||||
msgid "Play Trailer"
|
||||
msgstr "Riproduci Trailer"
|
||||
|
||||
msgctxt "#30308"
|
||||
msgid "Select Trailer"
|
||||
msgstr "Seleziona Trailer"
|
||||
|
||||
msgctxt "#30313"
|
||||
msgid "Menu"
|
||||
msgstr "Menù"
|
||||
|
||||
msgctxt "#30314"
|
||||
msgid "Play"
|
||||
msgstr "Riproduci"
|
||||
|
||||
msgctxt "#30316"
|
||||
msgid "Connection Error"
|
||||
msgstr "Errore di connessione"
|
||||
|
||||
msgctxt "#30318"
|
||||
msgid "Music - Albums"
|
||||
msgstr "Musica - Album"
|
||||
|
||||
msgctxt "#30322"
|
||||
msgid "Auto resume"
|
||||
msgstr "Ripresa automatica"
|
||||
|
||||
msgctxt "#30328"
|
||||
msgid "Show empty folders (shows, seasons, collections)"
|
||||
msgstr "Mostra cartelle vuote (serie, stagioni, collezioni)"
|
||||
|
||||
msgctxt "#30285"
|
||||
msgid " - Unwatched"
|
||||
msgstr "- Non visto"
|
||||
|
||||
msgctxt "#30303"
|
||||
msgid "Missing Jellyfin images : "
|
||||
msgstr "Immagini mancanti di Jellyfin:"
|
||||
|
||||
msgctxt "#30330"
|
||||
msgid "Show change user dialog"
|
||||
msgstr "Mostra la finestra di cambio utente"
|
||||
|
||||
msgctxt "#30332"
|
||||
msgid "Stop media playback on screensaver activation"
|
||||
msgstr ""
|
||||
"Interrompi la riproduzione multimediale all'attivazione dello screensaver"
|
||||
|
||||
msgctxt "#30338"
|
||||
msgid "Album"
|
||||
msgstr "Album"
|
||||
|
||||
msgctxt "#30340"
|
||||
msgid "Group movies into collections"
|
||||
msgstr "Raggruppa film in collezioni"
|
||||
|
||||
msgctxt "#30281"
|
||||
msgid "Refresh Cached Images"
|
||||
msgstr "Aggiorna immagine in cache"
|
||||
|
||||
msgctxt "#30292"
|
||||
msgid "Select Subtitle Stream"
|
||||
msgstr "Seleziona fonte sottotitoli"
|
||||
|
||||
msgctxt "#30293"
|
||||
msgid "Cache images"
|
||||
msgstr "Memorizza immagini"
|
||||
|
||||
msgctxt "#30310"
|
||||
msgid "Enable Jellyfin remote control"
|
||||
msgstr "Abilitare il controllo remoto di Jellyfin"
|
||||
|
||||
msgctxt "#30317"
|
||||
msgid "Play All"
|
||||
msgstr "Riproduci tutto"
|
||||
|
||||
msgctxt "#30283"
|
||||
msgid "Play Next Episode?"
|
||||
msgstr "Riprodurre episodio successivo?"
|
||||
|
||||
msgctxt "#30295"
|
||||
msgid "To use this feature you need HTTP control enabled"
|
||||
msgstr "Per poter utilizzare questa funzione devi abilitare il controllo HTTP"
|
||||
|
||||
msgctxt "#30298"
|
||||
msgid "Deleting Kodi Images"
|
||||
msgstr "Eliminazione immagini di Kodi"
|
||||
|
||||
msgctxt "#30302"
|
||||
msgid "Existing images : "
|
||||
msgstr "Immagini presenti:"
|
||||
|
||||
msgctxt "#30309"
|
||||
msgid "Select Media Source"
|
||||
msgstr "Seleziona sorgente multimediale"
|
||||
|
||||
msgctxt "#30315"
|
||||
msgid "Suppress notifications for connection errors"
|
||||
msgstr "Elimina le notifiche per gli errori di connessione"
|
||||
|
||||
msgctxt "#30344"
|
||||
msgid "Number of images removed from cache"
|
||||
msgstr "Numero di immagini rimosse dalla cache"
|
||||
|
||||
msgctxt "#30304"
|
||||
msgid "Cached Jellyfin images : "
|
||||
msgstr "Immagini Jellyfin salvate nella cache:"
|
||||
|
||||
msgctxt "#30334"
|
||||
msgid "Use JellyCon context menu"
|
||||
msgstr "Usa menu contestuale di JellyCon"
|
||||
|
||||
msgctxt "#30346"
|
||||
msgid "Deleteing Cached Images"
|
||||
msgstr "Eliminazione immagini salvate nella cache"
|
||||
|
||||
msgctxt "#30347"
|
||||
msgid "Getting Existing Images"
|
||||
msgstr "Recupero immagini esistenti"
|
||||
|
||||
msgctxt "#30343"
|
||||
msgid "Changes Require Kodi Restart"
|
||||
msgstr "Le modifiche richiedono il riavvio di Kodi"
|
||||
|
||||
msgctxt "#30339"
|
||||
msgid "Person"
|
||||
msgstr "Persona"
|
||||
|
||||
msgctxt "#30294"
|
||||
msgid "Notice"
|
||||
msgstr "Avviso"
|
||||
|
||||
msgctxt "#30299"
|
||||
msgid "Cache Images"
|
||||
msgstr "Memorizza immagini"
|
||||
|
||||
msgctxt "#30300"
|
||||
msgid "Cache all Jellyfin images as local Kodi images?"
|
||||
msgstr "Memorizzare tutte le immagini Jellyfin come immagini locali Kodi?"
|
||||
|
||||
msgctxt "#30414"
|
||||
msgid " - Favorites"
|
||||
msgstr "- Preferiti"
|
||||
|
||||
msgctxt "#30333"
|
||||
msgid "Cache artwork in the background"
|
||||
msgstr "Memorizza artwork in background"
|
||||
|
||||
msgctxt "#30349"
|
||||
msgid " - Recently Played"
|
||||
msgstr "- Riprodotti di recente"
|
||||
|
||||
msgctxt "#30350"
|
||||
msgid "Music - Recently Added"
|
||||
msgstr "Musica - Aggiunta di recente"
|
||||
|
||||
msgctxt "#30352"
|
||||
msgid "Music - Frequently Played"
|
||||
msgstr "Musica - Ascoltata frequentemente"
|
||||
|
||||
msgctxt "#30319"
|
||||
msgid "Music - All Album Artists"
|
||||
msgstr "Musica - Artisti dell'album"
|
||||
|
||||
msgctxt "#30354"
|
||||
msgid "Go To Series"
|
||||
msgstr "Vai alle Serie"
|
||||
|
||||
msgctxt "#30355"
|
||||
msgid "Kodi Settings->Services->Allow remote control via HTTP"
|
||||
msgstr "Impostazioni di Kodi -> Servizi -> Consenti controllo remoto via HTTP"
|
||||
|
||||
msgctxt "#30360"
|
||||
msgid " - Channels"
|
||||
msgstr "- Canali"
|
||||
|
||||
msgctxt "#30361"
|
||||
msgid " - Programs"
|
||||
msgstr "- Programmi"
|
||||
|
||||
msgctxt "#30362"
|
||||
msgid " - Recordings"
|
||||
msgstr "- Registrazioni"
|
||||
|
||||
msgctxt "#30366"
|
||||
msgid "Manually enter user details"
|
||||
msgstr "Inserisci manualmente i dettagli dell'utente"
|
||||
|
||||
msgctxt "#30375"
|
||||
msgid "Receiving data packet"
|
||||
msgstr "Ottengo i pacchetti"
|
||||
|
||||
msgctxt "#30377"
|
||||
msgid "Sending request"
|
||||
msgstr "Invio la richiesta"
|
||||
|
||||
msgctxt "#30380"
|
||||
msgid "Never"
|
||||
msgstr "Mai"
|
||||
|
||||
msgctxt "#30381"
|
||||
msgid "More than one"
|
||||
msgstr "Più di uno"
|
||||
|
||||
msgctxt "#30382"
|
||||
msgid "Always"
|
||||
msgstr "Sempre"
|
||||
|
||||
msgctxt "#30383"
|
||||
msgid "System - "
|
||||
msgstr "Sistema -"
|
||||
|
||||
msgctxt "#30390"
|
||||
msgid "Protocol"
|
||||
msgstr "Protocollo"
|
||||
|
||||
msgctxt "#30391"
|
||||
msgid "HTTP"
|
||||
msgstr "HTTP"
|
||||
|
||||
msgctxt "#30392"
|
||||
msgid "HTTPS"
|
||||
msgstr "HTTPS"
|
||||
|
||||
msgctxt "#30397"
|
||||
msgid " - Pages"
|
||||
msgstr "- Pagine"
|
||||
|
||||
msgctxt "#30402"
|
||||
msgid "Add to Kodi Playlist"
|
||||
msgstr "Aggiungi alla playlist di Kodi"
|
||||
|
||||
msgctxt "#30405"
|
||||
msgid " - Show All"
|
||||
msgstr "- Mostra tutto"
|
||||
|
||||
msgctxt "#30408"
|
||||
msgid "Custom Widgets"
|
||||
msgstr "Widget Personalizzati"
|
||||
|
||||
msgctxt "#30409"
|
||||
msgid "Add-on Actions"
|
||||
msgstr "Azioni Add-on"
|
||||
|
||||
msgctxt "#30410"
|
||||
msgid " - Collections"
|
||||
msgstr "- Collezioni"
|
||||
|
||||
msgctxt "#30411"
|
||||
msgid " - Years"
|
||||
msgstr "- Anni"
|
||||
|
||||
msgctxt "#30413"
|
||||
msgid " - Tags"
|
||||
msgstr "- Tags"
|
||||
|
||||
msgctxt "#30415"
|
||||
msgid " - Favorite Collections"
|
||||
msgstr "- Collezioni Preferite"
|
||||
|
||||
msgctxt "#30418"
|
||||
msgid "Audio bitrate (Kbits)"
|
||||
msgstr "Bitrate dell'Audio (Kbps)"
|
||||
|
||||
msgctxt "#30419"
|
||||
msgid "Audio codec"
|
||||
msgstr "Codifica dell'Audio"
|
||||
|
||||
msgctxt "#30420"
|
||||
msgid "Audio max channels"
|
||||
msgstr "Canali massimi dell'audio"
|
||||
|
||||
msgctxt "#30421"
|
||||
msgid "Views"
|
||||
msgstr "Visualizzazioni"
|
||||
|
||||
msgctxt "#30422"
|
||||
msgid "Sorting"
|
||||
msgstr "Ordina"
|
||||
|
||||
msgctxt "#30424"
|
||||
msgid "Default"
|
||||
msgstr "Predefinito"
|
||||
|
||||
msgctxt "#30425"
|
||||
msgid "Year"
|
||||
msgstr "Anno"
|
||||
|
||||
msgctxt "#30301"
|
||||
msgid "Caching Images"
|
||||
msgstr "Memorizzando le immagini"
|
||||
|
||||
msgctxt "#30359"
|
||||
msgid "Building full image list"
|
||||
msgstr "Compongo la lista completa delle immagini"
|
||||
|
||||
msgctxt "#30363"
|
||||
msgid "Save Password?"
|
||||
msgstr "Salvare la Password?"
|
||||
|
||||
msgctxt "#30364"
|
||||
msgid "Do you want to save the password?"
|
||||
msgstr "Vuoi salvare la Password?"
|
||||
|
||||
msgctxt "#30368"
|
||||
msgid "Clear Password?"
|
||||
msgstr "Cancellare la Password?"
|
||||
|
||||
msgctxt "#30371"
|
||||
msgid "Could not connect to the URL you entered, do you want to try again?"
|
||||
msgstr "Non è stato possibile connettersi con l'URL fornito, vuoi riprovare?"
|
||||
|
||||
msgctxt "#30372"
|
||||
msgid "Server URL"
|
||||
msgstr "URL del Server"
|
||||
|
||||
msgctxt "#30373"
|
||||
msgid "Scanning for local servers"
|
||||
msgstr "Scansione di server locali"
|
||||
|
||||
msgctxt "#30388"
|
||||
msgid "Server details"
|
||||
msgstr "Dettagli del server"
|
||||
|
||||
msgctxt "#30394"
|
||||
msgid "Cache files deleted"
|
||||
msgstr "File di cache eliminati"
|
||||
|
||||
msgctxt "#30395"
|
||||
msgid "Clear cached server data"
|
||||
msgstr "Elimina la cache del server"
|
||||
|
||||
msgctxt "#30398"
|
||||
msgid "Refresh Jellyfin Metadata"
|
||||
msgstr "Aggiorna i metadati di Jellyfin"
|
||||
|
||||
msgctxt "#30399"
|
||||
msgid "Hide"
|
||||
msgstr "Nascondi"
|
||||
|
||||
msgctxt "#30401"
|
||||
msgid "Info"
|
||||
msgstr "Informazioni"
|
||||
|
||||
msgctxt "#30406"
|
||||
msgid "Jellyfin Libraries"
|
||||
msgstr "Librerie Jellyfin"
|
||||
|
||||
msgctxt "#30407"
|
||||
msgid "Global Lists"
|
||||
msgstr "Lista Globale"
|
||||
|
||||
msgctxt "#30416"
|
||||
msgid "HTTP timeout seconds"
|
||||
msgstr "HTTP timeout secondi"
|
||||
|
||||
msgctxt "#30417"
|
||||
msgid "You do not have permision to delete this item"
|
||||
msgstr "Non hai il permetto di eliminare questo elemento"
|
||||
|
||||
msgctxt "#30426"
|
||||
msgid "Title"
|
||||
msgstr "Titolo"
|
||||
|
||||
msgctxt "#30427"
|
||||
msgid "Added"
|
||||
msgstr "Aggiunto"
|
||||
|
||||
msgctxt "#30428"
|
||||
msgid "Rating"
|
||||
msgstr "Valutazione"
|
||||
|
||||
msgctxt "#30429"
|
||||
msgid "Genre"
|
||||
msgstr "Genere"
|
||||
|
||||
msgctxt "#30430"
|
||||
msgid "Label"
|
||||
msgstr "Etichetta"
|
||||
|
||||
msgctxt "#30431"
|
||||
msgid "Seasons"
|
||||
msgstr "Stagioni"
|
||||
|
||||
msgctxt "#30432"
|
||||
msgid "Hide watched items in lists"
|
||||
msgstr "Nascondi gli elementi già visti dalla lista"
|
||||
|
||||
msgctxt "#30433"
|
||||
msgid "Allow direct file playback"
|
||||
msgstr "Consenti la riproduzione diretta del file"
|
||||
|
||||
msgctxt "#30341"
|
||||
msgid "Background image update interval (0 = disabled)"
|
||||
msgstr "Intervallo di aggiornamento dell'immagine di sfondo (0 = disabilitato)"
|
||||
|
||||
msgctxt "#30348"
|
||||
msgid "Add user ratings"
|
||||
msgstr "Aggiungi valutazioni dell'utente"
|
||||
|
||||
msgctxt "#30351"
|
||||
msgid "Music - Recently Played"
|
||||
msgstr "Musica - Ascoltata di recente"
|
||||
|
||||
msgctxt "#30321"
|
||||
msgid " - Album Artists"
|
||||
msgstr "- Artisti dell'album"
|
||||
|
||||
msgctxt "#30353"
|
||||
msgid " - Frequently Played"
|
||||
msgstr "- Riprodotto frequentemente"
|
||||
|
||||
msgctxt "#30358"
|
||||
msgid "Retreiving remote image list"
|
||||
msgstr "Ottengo lista immagini remota"
|
||||
|
||||
msgctxt "#30365"
|
||||
msgid "Manual Login"
|
||||
msgstr "Accesso Manuale"
|
||||
|
||||
msgctxt "#30369"
|
||||
msgid "Do you want to clear your saved password?"
|
||||
msgstr "Vuoi eliminare le tue password salvate?"
|
||||
|
||||
msgctxt "#30370"
|
||||
msgid "Do you want to manually enter a server url?"
|
||||
msgstr "Vuoi inserire manualmente l'URL del server?"
|
||||
|
||||
msgctxt "#30374"
|
||||
msgid "Sending request"
|
||||
msgstr "Invio la richiesta"
|
||||
|
||||
msgctxt "#30376"
|
||||
msgid "Checking server url"
|
||||
msgstr "Controllo l'URL del server"
|
||||
|
||||
msgctxt "#30378"
|
||||
msgid "Persist user details"
|
||||
msgstr "Conserva i dettagli dell'utente"
|
||||
|
||||
msgctxt "#30389"
|
||||
msgid "User details"
|
||||
msgstr "Dettagli dell'utente"
|
||||
|
||||
msgctxt "#30403"
|
||||
msgid "Movies - Recommendations"
|
||||
msgstr "Film - Consigliati"
|
||||
|
||||
msgctxt "#30404"
|
||||
msgid " - A-Z"
|
||||
msgstr "- A-Z"
|
||||
|
||||
msgctxt "#30412"
|
||||
msgid " - Decades"
|
||||
msgstr "- Decenni"
|
||||
|
||||
msgctxt "#30423"
|
||||
msgid "NotSet"
|
||||
msgstr "Non impostato"
|
||||
|
||||
msgctxt "#30446"
|
||||
msgid "There was an error logging in"
|
||||
msgstr "Si è verificato un errore al login"
|
||||
|
||||
msgctxt "#30443"
|
||||
msgid "Quick Connect"
|
||||
msgstr "Connessione rapida"
|
||||
|
||||
msgctxt "#30445"
|
||||
msgid "Continue Watching"
|
||||
msgstr "Continua a guardare"
|
||||
|
||||
msgctxt "#30448"
|
||||
msgid "Shuffle"
|
||||
msgstr "Casuale"
|
||||
|
||||
msgctxt "#30447"
|
||||
msgid "Max Play Queue Size"
|
||||
msgstr "Dimensione massima della coda di riproduzione"
|
||||
|
||||
msgctxt "#30242"
|
||||
msgid "Force transcode av1"
|
||||
msgstr "Forza transcodifica AV1"
|
||||
|
||||
msgctxt "#30356"
|
||||
msgid "Loading existing image list"
|
||||
msgstr "Caricamento lista di immagini esistenti"
|
||||
|
||||
msgctxt "#30384"
|
||||
msgid "Random movies interval minutes (0 = disabled)"
|
||||
msgstr "Intervallo, in minuti, di film casuali (0 = disabilitato)"
|
||||
|
||||
msgctxt "#30385"
|
||||
msgid "Existing images before delete : "
|
||||
msgstr "Immagini esistenti prima della cancellazione:"
|
||||
|
||||
msgctxt "#30386"
|
||||
msgid "Unused Jellyfin images : "
|
||||
msgstr "Immagini Jellyfin inutilizzate:"
|
||||
|
||||
msgctxt "#30387"
|
||||
msgid "Unused images removed : "
|
||||
msgstr "Immagini inutilizzate rimosse:"
|
||||
|
||||
msgctxt "#30393"
|
||||
msgid "Clear Cache Result"
|
||||
msgstr "Cancella la cache dei risultati"
|
||||
|
||||
msgctxt "#30440"
|
||||
msgid "Play next"
|
||||
msgstr "Riproduci prossimo"
|
||||
|
||||
msgctxt "#30441"
|
||||
msgid "Use cached widget data"
|
||||
msgstr "Utilizza dati widget in cache"
|
||||
|
||||
msgctxt "#30444"
|
||||
msgid "Login using Quick Connect"
|
||||
msgstr "Loggati con la Connessione Rapida"
|
||||
|
||||
msgctxt "#30452"
|
||||
msgid "Combine instead of replace (might cause slow-down)"
|
||||
msgstr "Combina invece di sostituire (può causare rallentamenti)"
|
||||
|
||||
msgctxt "#30342"
|
||||
msgid "New content check interval (0 = disabled)"
|
||||
msgstr "Intervallo di verifica di nuovi contenuti (0 = disabilitato)"
|
||||
|
||||
msgctxt "#30357"
|
||||
msgid "Processing existing image list"
|
||||
msgstr "Analizzando la lista di immagini esistenti"
|
||||
|
||||
msgctxt "#30400"
|
||||
msgid "Cache images interval minutes (0 = disabled)"
|
||||
msgstr "Intervallo, in minuti, della cache delle immagini (0 = disabilitato)"
|
||||
|
||||
msgctxt "#30435"
|
||||
msgid "Connection speed test"
|
||||
msgstr "Test di velocità della connessione"
|
||||
|
||||
msgctxt "#30436"
|
||||
msgid "Speed test data size (MB)"
|
||||
msgstr "Dimensioni dati per il test di velocità (MB)"
|
||||
|
||||
msgctxt "#30437"
|
||||
msgid "Playback options"
|
||||
msgstr "Opzioni di riproduzione"
|
||||
|
||||
msgctxt "#30225"
|
||||
msgid "Interface Mode"
|
||||
msgstr "Modalità interfaccia"
|
||||
|
||||
msgctxt "#30226"
|
||||
msgid "Default"
|
||||
msgstr "Predefinito"
|
||||
|
||||
msgctxt "#30227"
|
||||
msgid "Simple"
|
||||
msgstr "Semplice"
|
||||
|
||||
msgctxt "#30121"
|
||||
msgid "On resume"
|
||||
msgstr "Riprendi"
|
||||
|
||||
msgctxt "#30442"
|
||||
msgid "Simple new content check"
|
||||
msgstr "Ricerca dei contenuti nuovi semplice"
|
||||
|
||||
msgctxt "#30215"
|
||||
msgid "On playback stop (100% = disabled)"
|
||||
msgstr "A riproduzione ferma (100% = disabilitato)"
|
||||
|
||||
msgctxt "#30379"
|
||||
msgid "External subtitle prompt"
|
||||
msgstr "Prompt sottotitolo esterno"
|
||||
|
||||
msgctxt "#30434"
|
||||
msgid "Force transcode stream bitrate (Kbits)"
|
||||
msgstr "Forza transcodifica del bitrate dello stream (Kbps)"
|
||||
|
||||
msgctxt "#30345"
|
||||
msgid "Cache Jellyfin server data requests"
|
||||
msgstr "Stiva dati richieste del server Jellyfin"
|
||||
|
||||
msgctxt "#30439"
|
||||
msgid "Show play next episode at time left in seconds"
|
||||
msgstr "Mostra riproduci il prossimo episodio a tempo rimasto in secondi"
|
||||
|
||||
msgctxt "#30367"
|
||||
msgid "Allow fast user switching password saving"
|
||||
msgstr "Consenti salvataggio veloce della password utente cambiata"
|
||||
|
||||
msgctxt "#30438"
|
||||
msgid "Play cinema intros"
|
||||
msgstr "Riproduci introduzioni cinema"
|
||||
|
||||
msgctxt "#30449"
|
||||
msgid "Instant Mix"
|
||||
msgstr "Mix Istantaneo"
|
||||
|
||||
msgctxt "#30451"
|
||||
msgid "Rewatch Days (0 = Disabled)"
|
||||
msgstr "Giorni da Riguardare (0 = Disabilitato)"
|
||||
|
||||
msgctxt "#30276"
|
||||
msgid "Extra Resume Prompt Detected"
|
||||
msgstr "Finestra di Ripresa Duplicata Rilevata"
|
||||
|
||||
msgctxt "#30450"
|
||||
msgid "Next Up Rewatching"
|
||||
msgstr "Prossimo da Riguardare"
|
||||
|
||||
702
resources/language/resource.language.ja/strings.po
Normal file
702
resources/language/resource.language.ja/strings.po
Normal file
@@ -0,0 +1,702 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2024-11-11 04:00+0000\n"
|
||||
"Last-Translator: okaits#7534 <okaits@okaits7534.net>\n"
|
||||
"Language-Team: Japanese <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/ja/>\n"
|
||||
"Language: ja\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"X-Generator: Weblate 5.7.2\n"
|
||||
|
||||
msgctxt "#30112"
|
||||
msgid "Loading Content"
|
||||
msgstr "コンテンツをロード中"
|
||||
|
||||
msgctxt "#30008"
|
||||
msgid "Samba password"
|
||||
msgstr "Samba パスワード"
|
||||
|
||||
msgctxt "#30016"
|
||||
msgid "Device display name"
|
||||
msgstr "デバイスディスプレイ名"
|
||||
|
||||
msgctxt "#30021"
|
||||
msgid "Show all episodes item"
|
||||
msgstr "全てのエピソードを見る"
|
||||
|
||||
msgctxt "#30044"
|
||||
msgid "Incorrect Username/Password"
|
||||
msgstr "誤ったユーザー名もしくはパスワード"
|
||||
|
||||
msgctxt "#30000"
|
||||
msgid "Host"
|
||||
msgstr "ホスト"
|
||||
|
||||
msgctxt "#30001"
|
||||
msgid "Port"
|
||||
msgstr "ポート"
|
||||
|
||||
msgctxt "#30003"
|
||||
msgid "Verify HTTPS certificate"
|
||||
msgstr "HTTPS証明書を検証"
|
||||
|
||||
msgctxt "#30005"
|
||||
msgid "Username"
|
||||
msgstr "ユーザー名"
|
||||
|
||||
msgctxt "#30006"
|
||||
msgid "Password"
|
||||
msgstr "パスワード"
|
||||
|
||||
msgctxt "#30007"
|
||||
msgid "Samba username"
|
||||
msgstr "Samba ユーザー名"
|
||||
|
||||
msgctxt "#30010"
|
||||
msgid "Number of performance profiles to capture"
|
||||
msgstr "キャプチャするパフォーマンスプロファイルの数"
|
||||
|
||||
msgctxt "#30011"
|
||||
msgid "[Detect local server]"
|
||||
msgstr "[ローカルサーバーを検出]"
|
||||
|
||||
msgctxt "#30012"
|
||||
msgid "[Change user]"
|
||||
msgstr "[ユーザーを変更]"
|
||||
|
||||
msgctxt "#30014"
|
||||
msgid "Jellyfin"
|
||||
msgstr "Jellyfin"
|
||||
|
||||
msgctxt "#30015"
|
||||
msgid "Log timing data"
|
||||
msgstr "ログタイミングデータ"
|
||||
|
||||
msgctxt "#30017"
|
||||
msgid "Show connected clients"
|
||||
msgstr "接続されたクライアントを表示"
|
||||
|
||||
msgctxt "#30018"
|
||||
msgid "Number of items to show in filtered lists"
|
||||
msgstr "フィルターされたリストに表示するアイテムの数"
|
||||
|
||||
msgctxt "#30019"
|
||||
msgid "Filtered episode name format"
|
||||
msgstr "フィルターされたエピソードの名前フォーマット"
|
||||
|
||||
msgctxt "#30022"
|
||||
msgid "Advanced"
|
||||
msgstr "高度"
|
||||
|
||||
msgctxt "#30023"
|
||||
msgid "Hide unwatched episode details"
|
||||
msgstr "観ていないエピソードの詳細を隠す"
|
||||
|
||||
msgctxt "#30024"
|
||||
msgid "Username:"
|
||||
msgstr "ユーザー名:"
|
||||
|
||||
msgctxt "#30025"
|
||||
msgid "Password:"
|
||||
msgstr "パスワード:"
|
||||
|
||||
msgctxt "#30027"
|
||||
msgid "Enable debug logging"
|
||||
msgstr "デバッグロギングを有効化"
|
||||
|
||||
msgctxt "#30045"
|
||||
msgid "Username not found"
|
||||
msgstr "ユーザー名が見つからない"
|
||||
|
||||
msgctxt "#30052"
|
||||
msgid "Deleting"
|
||||
msgstr "削除中"
|
||||
|
||||
msgctxt "#30053"
|
||||
msgid "Waiting for server to delete"
|
||||
msgstr "サーバーが削除するのを待機中"
|
||||
|
||||
msgctxt "#30091"
|
||||
msgid "Confirm delete?"
|
||||
msgstr "削除しますか?"
|
||||
|
||||
msgctxt "#30092"
|
||||
msgid "Warning: This action will delete the media files from the server."
|
||||
msgstr "警告: この操作はサーバーからメディアファイルを削除します。"
|
||||
|
||||
msgctxt "#30110"
|
||||
msgid "Interface"
|
||||
msgstr "インターフェース"
|
||||
|
||||
msgctxt "#30111"
|
||||
msgid "Services"
|
||||
msgstr "サービス"
|
||||
|
||||
msgctxt "#30113"
|
||||
msgid "Retrieving Data"
|
||||
msgstr "データを取得中"
|
||||
|
||||
msgctxt "#30222"
|
||||
msgid "Item Layout"
|
||||
msgstr "アイテムレイアウト"
|
||||
|
||||
msgctxt "#30224"
|
||||
msgid "Interaction"
|
||||
msgstr "インタラクション"
|
||||
|
||||
msgctxt "#30225"
|
||||
msgid "Interface Mode"
|
||||
msgstr "インターフェースモード"
|
||||
|
||||
msgctxt "#30226"
|
||||
msgid "Default"
|
||||
msgstr "既定"
|
||||
|
||||
msgctxt "#30227"
|
||||
msgid "Simple"
|
||||
msgstr "シンプル"
|
||||
|
||||
msgctxt "#30229"
|
||||
msgid "TV Shows"
|
||||
msgstr "TV番組"
|
||||
|
||||
msgctxt "#30231"
|
||||
msgid "Movies"
|
||||
msgstr "映画"
|
||||
|
||||
msgctxt "#30235"
|
||||
msgid "Episodes"
|
||||
msgstr "エピソード"
|
||||
|
||||
msgctxt "#30237"
|
||||
msgid "Start from beginning"
|
||||
msgstr "最初から始める"
|
||||
|
||||
msgctxt "#30239"
|
||||
msgid "Force transcode mpeg2"
|
||||
msgstr "mpeg2でのトランスコードを強制する"
|
||||
|
||||
msgctxt "#30241"
|
||||
msgid "Force transcode mpeg4"
|
||||
msgstr "mpeg4でのトランスコードを強制する"
|
||||
|
||||
msgctxt "#30246"
|
||||
msgid "Search"
|
||||
msgstr "検索"
|
||||
|
||||
msgctxt "#30250"
|
||||
msgid "Unknown"
|
||||
msgstr "不明"
|
||||
|
||||
msgctxt "#30252"
|
||||
msgid "Movies - A-Z"
|
||||
msgstr "映画 - A-Z"
|
||||
|
||||
msgctxt "#30254"
|
||||
msgid "Show add-on settings"
|
||||
msgstr "アドオン設定を見る"
|
||||
|
||||
msgctxt "#30255"
|
||||
msgid "TV Shows - A-Z"
|
||||
msgstr "TV番組 - A-Z"
|
||||
|
||||
msgctxt "#30256"
|
||||
msgid "Movies"
|
||||
msgstr "映画"
|
||||
|
||||
msgctxt "#30257"
|
||||
msgid "Movies - Recently Added"
|
||||
msgstr "映画 - 最近追加された"
|
||||
|
||||
msgctxt "#30258"
|
||||
msgid "Movies - In Progress"
|
||||
msgstr "映画 - 途中"
|
||||
|
||||
msgctxt "#30259"
|
||||
msgid "Movies - Favorites"
|
||||
msgstr "映画 - お気に入り"
|
||||
|
||||
msgctxt "#30260"
|
||||
msgid "BoxSets"
|
||||
msgstr "ボックス・セット"
|
||||
|
||||
msgctxt "#30261"
|
||||
msgid "TV Shows"
|
||||
msgstr "TV番組"
|
||||
|
||||
msgctxt "#30262"
|
||||
msgid "TV Shows - Favorites"
|
||||
msgstr "TV番組 - お気に入り"
|
||||
|
||||
msgctxt "#30264"
|
||||
msgid "Episodes - In Progress"
|
||||
msgstr "エピソード - 途中"
|
||||
|
||||
msgctxt "#30265"
|
||||
msgid "Episodes - Next Up"
|
||||
msgstr "エピソード - 次"
|
||||
|
||||
msgctxt "#30266"
|
||||
msgid "Movies - Pages"
|
||||
msgstr "映画 - ページ"
|
||||
|
||||
msgctxt "#30267"
|
||||
msgid " - In Progress"
|
||||
msgstr "- 途中"
|
||||
|
||||
msgctxt "#30268"
|
||||
msgid " - Recently Added"
|
||||
msgstr "- 最近追加された"
|
||||
|
||||
msgctxt "#30269"
|
||||
msgid "Movies - Random"
|
||||
msgstr "映画 - ランダム"
|
||||
|
||||
msgctxt "#30270"
|
||||
msgid "Mark Watched"
|
||||
msgstr "視聴済みにする"
|
||||
|
||||
msgctxt "#30271"
|
||||
msgid "Mark Unwatched"
|
||||
msgstr "未視聴にする"
|
||||
|
||||
msgctxt "#30272"
|
||||
msgid "Set Favourite"
|
||||
msgstr "お気に入りにする"
|
||||
|
||||
msgctxt "#30273"
|
||||
msgid "Unset Favourite"
|
||||
msgstr "お気に入りから外す"
|
||||
|
||||
msgctxt "#30274"
|
||||
msgid "Delete"
|
||||
msgstr "削除"
|
||||
|
||||
msgctxt "#30275"
|
||||
msgid "Force Transcode"
|
||||
msgstr "トランスコードを強制する"
|
||||
|
||||
msgctxt "#30276"
|
||||
msgid "Extra Resume Prompt Detected"
|
||||
msgstr "追加の再開プロンプトが検出された"
|
||||
|
||||
msgctxt "#30278"
|
||||
msgid " - Next Up"
|
||||
msgstr "- 次"
|
||||
|
||||
msgctxt "#30279"
|
||||
msgid "TV Shows - Unwatched"
|
||||
msgstr "TV番組 - 未視聴"
|
||||
|
||||
msgctxt "#30280"
|
||||
msgid "Missing Title"
|
||||
msgstr "タイトル欠落"
|
||||
|
||||
msgctxt "#30281"
|
||||
msgid "Refresh Cached Images"
|
||||
msgstr "キャッシュしたイメージをリフレッシュする"
|
||||
|
||||
msgctxt "#30282"
|
||||
msgid "No Jellyfin servers detected on your local network."
|
||||
msgstr "ローカルネットワークにJellyfinサーバーは検出されませんでした。"
|
||||
|
||||
msgctxt "#30283"
|
||||
msgid "Play Next Episode?"
|
||||
msgstr "次のエピソードを再生しますか?"
|
||||
|
||||
msgctxt "#30285"
|
||||
msgid " - Unwatched"
|
||||
msgstr "- 未視聴"
|
||||
|
||||
msgctxt "#30286"
|
||||
msgid "Movies - Unwatched"
|
||||
msgstr "映画 - 未視聴"
|
||||
|
||||
msgctxt "#30287"
|
||||
msgid "TV Shows - Latest"
|
||||
msgstr "TV番組 - 最新"
|
||||
|
||||
msgctxt "#30288"
|
||||
msgid " - Latest"
|
||||
msgstr "- 最新"
|
||||
|
||||
msgctxt "#30290"
|
||||
msgid "All"
|
||||
msgstr "全て"
|
||||
|
||||
msgctxt "#30291"
|
||||
msgid "Select Audio Stream"
|
||||
msgstr "音声ストリームを選択"
|
||||
|
||||
msgctxt "#30292"
|
||||
msgid "Select Subtitle Stream"
|
||||
msgstr "サブタイトルストリームを選択"
|
||||
|
||||
msgctxt "#30293"
|
||||
msgid "Cache images"
|
||||
msgstr "イメージをキャッシュする"
|
||||
|
||||
msgctxt "#30294"
|
||||
msgid "Notice"
|
||||
msgstr "通知"
|
||||
|
||||
msgctxt "#30295"
|
||||
msgid "To use this feature you need HTTP control enabled"
|
||||
msgstr "この機能を使うにはHTTPコントロールが有効化されている必要があります"
|
||||
|
||||
msgctxt "#30296"
|
||||
msgid "Delete"
|
||||
msgstr "削除"
|
||||
|
||||
msgctxt "#30297"
|
||||
msgid "Delete unused images?"
|
||||
msgstr "使用されていないイメージを削除しますか?"
|
||||
|
||||
msgctxt "#30299"
|
||||
msgid "Cache Images"
|
||||
msgstr "イメージをキャッシュする"
|
||||
|
||||
msgctxt "#30301"
|
||||
msgid "Caching Images"
|
||||
msgstr "イメージをキャッシュ中"
|
||||
|
||||
msgctxt "#30302"
|
||||
msgid "Existing images : "
|
||||
msgstr "既存のイメージ:"
|
||||
|
||||
msgctxt "#30303"
|
||||
msgid "Missing Jellyfin images : "
|
||||
msgstr "欠落したJellyfinイメージ:"
|
||||
|
||||
msgctxt "#30304"
|
||||
msgid "Cached Jellyfin images : "
|
||||
msgstr "キャッシュされたJellyfinイメージ:"
|
||||
|
||||
msgctxt "#30305"
|
||||
msgid "Not Found"
|
||||
msgstr "見つかりませんでした"
|
||||
|
||||
msgctxt "#30306"
|
||||
msgid "Playback starting"
|
||||
msgstr "再生を開始中"
|
||||
|
||||
msgctxt "#30307"
|
||||
msgid "Play Trailer"
|
||||
msgstr "トレーラーを再生"
|
||||
|
||||
msgctxt "#30308"
|
||||
msgid "Select Trailer"
|
||||
msgstr "トレーラーを選択"
|
||||
|
||||
msgctxt "#30309"
|
||||
msgid "Select Media Source"
|
||||
msgstr "メディアソースを選択"
|
||||
|
||||
msgctxt "#30311"
|
||||
msgid "Library - "
|
||||
msgstr "ライブラリー -"
|
||||
|
||||
msgctxt "#30312"
|
||||
msgid "All - "
|
||||
msgstr "全て -"
|
||||
|
||||
msgctxt "#30313"
|
||||
msgid "Menu"
|
||||
msgstr "メニュー"
|
||||
|
||||
msgctxt "#30314"
|
||||
msgid "Play"
|
||||
msgstr "再生"
|
||||
|
||||
msgctxt "#30315"
|
||||
msgid "Suppress notifications for connection errors"
|
||||
msgstr "接続エラーについての通知を抑制"
|
||||
|
||||
msgctxt "#30316"
|
||||
msgid "Connection Error"
|
||||
msgstr "接続エラー"
|
||||
|
||||
msgctxt "#30317"
|
||||
msgid "Play All"
|
||||
msgstr "全て再生"
|
||||
|
||||
msgctxt "#30318"
|
||||
msgid "Music - Albums"
|
||||
msgstr "音楽 - アルバム"
|
||||
|
||||
msgctxt "#30320"
|
||||
msgid " - Albums"
|
||||
msgstr "- アルバム"
|
||||
|
||||
msgctxt "#30322"
|
||||
msgid "Auto resume"
|
||||
msgstr "自動再開"
|
||||
|
||||
msgctxt "#30323"
|
||||
msgid "Artists"
|
||||
msgstr "アーティスト"
|
||||
|
||||
msgctxt "#30325"
|
||||
msgid " - Genres"
|
||||
msgstr "- ジャンル"
|
||||
|
||||
msgctxt "#30327"
|
||||
msgid "Go To Season"
|
||||
msgstr "シーズンに行く"
|
||||
|
||||
msgctxt "#30328"
|
||||
msgid "Show empty folders (shows, seasons, collections)"
|
||||
msgstr "空のフォルダー(番組, シーズン, コレクション)を見る"
|
||||
|
||||
msgctxt "#30329"
|
||||
msgid "Screensaver"
|
||||
msgstr "スクリーンセーバー"
|
||||
|
||||
msgctxt "#30330"
|
||||
msgid "Show change user dialog"
|
||||
msgstr "ユーザー変更ダイアログを見る"
|
||||
|
||||
msgctxt "#30331"
|
||||
msgid "Movies per page"
|
||||
msgstr "ページごとの映画"
|
||||
|
||||
msgctxt "#30332"
|
||||
msgid "Stop media playback on screensaver activation"
|
||||
msgstr "スクリーンセーバーが始まったらメディア再生をやめる"
|
||||
|
||||
msgctxt "#30334"
|
||||
msgid "Use JellyCon context menu"
|
||||
msgstr "JellyConコンテキストメニューを使う"
|
||||
|
||||
msgctxt "#30337"
|
||||
msgid "Song"
|
||||
msgstr "曲"
|
||||
|
||||
msgctxt "#30338"
|
||||
msgid "Album"
|
||||
msgstr "アルバム"
|
||||
|
||||
msgctxt "#30339"
|
||||
msgid "Person"
|
||||
msgstr "人物"
|
||||
|
||||
msgctxt "#30340"
|
||||
msgid "Group movies into collections"
|
||||
msgstr "映画のグループをコレクションに追加"
|
||||
|
||||
msgctxt "#30341"
|
||||
msgid "Background image update interval (0 = disabled)"
|
||||
msgstr "バックグラウンドのイメージ更新間隔 (0 = 無効)"
|
||||
|
||||
msgctxt "#30342"
|
||||
msgid "New content check interval (0 = disabled)"
|
||||
msgstr "新しいコンテンツの確認間隔 (0 = 無効)"
|
||||
|
||||
msgctxt "#30343"
|
||||
msgid "Changes Require Kodi Restart"
|
||||
msgstr "変更はKodiの再起動を必要とします"
|
||||
|
||||
msgctxt "#30344"
|
||||
msgid "Number of images removed from cache"
|
||||
msgstr "キャッシュから削除されたイメージの数"
|
||||
|
||||
msgctxt "#30345"
|
||||
msgid "Cache Jellyfin server data requests"
|
||||
msgstr "Jellyfinサーバーデータリクエストをキャッシュする"
|
||||
|
||||
msgctxt "#30346"
|
||||
msgid "Deleteing Cached Images"
|
||||
msgstr "キャッシュされたイメージを削除中"
|
||||
|
||||
msgctxt "#30347"
|
||||
msgid "Getting Existing Images"
|
||||
msgstr "既存のイメージを取得中"
|
||||
|
||||
msgctxt "#30348"
|
||||
msgid "Add user ratings"
|
||||
msgstr "ユーザーレーティングを追加"
|
||||
|
||||
msgctxt "#30350"
|
||||
msgid "Music - Recently Added"
|
||||
msgstr "音楽 - 最近追加された"
|
||||
|
||||
msgctxt "#30349"
|
||||
msgid " - Recently Played"
|
||||
msgstr "- 最近再生された"
|
||||
|
||||
msgctxt "#30351"
|
||||
msgid "Music - Recently Played"
|
||||
msgstr "音楽 - 最近再生された"
|
||||
|
||||
msgctxt "#30352"
|
||||
msgid "Music - Frequently Played"
|
||||
msgstr "音楽 - よく再生される"
|
||||
|
||||
msgctxt "#30319"
|
||||
msgid "Music - All Album Artists"
|
||||
msgstr "音楽 - 全てのアルバムアーティスト"
|
||||
|
||||
msgctxt "#30321"
|
||||
msgid " - Album Artists"
|
||||
msgstr "- アルバムアーティスト"
|
||||
|
||||
msgctxt "#30353"
|
||||
msgid " - Frequently Played"
|
||||
msgstr "- よく再生される"
|
||||
|
||||
msgctxt "#30354"
|
||||
msgid "Go To Series"
|
||||
msgstr "シリーズに行く"
|
||||
|
||||
msgctxt "#30356"
|
||||
msgid "Loading existing image list"
|
||||
msgstr "既存のイメージリストを読み込み中"
|
||||
|
||||
msgctxt "#30357"
|
||||
msgid "Processing existing image list"
|
||||
msgstr "既存のイメージリストを処理中"
|
||||
|
||||
msgctxt "#30358"
|
||||
msgid "Retreiving remote image list"
|
||||
msgstr "リモートイメージリストを取得中"
|
||||
|
||||
msgctxt "#30359"
|
||||
msgid "Building full image list"
|
||||
msgstr "フルイメージリストを構築中"
|
||||
|
||||
msgctxt "#30360"
|
||||
msgid " - Channels"
|
||||
msgstr "- チャンネル"
|
||||
|
||||
msgctxt "#30361"
|
||||
msgid " - Programs"
|
||||
msgstr "- 番組"
|
||||
|
||||
msgctxt "#30362"
|
||||
msgid " - Recordings"
|
||||
msgstr "- 録音"
|
||||
|
||||
msgctxt "#30363"
|
||||
msgid "Save Password?"
|
||||
msgstr "パスワードを保存しますか?"
|
||||
|
||||
msgctxt "#30364"
|
||||
msgid "Do you want to save the password?"
|
||||
msgstr "パスワードを保存しますか?"
|
||||
|
||||
msgctxt "#30365"
|
||||
msgid "Manual Login"
|
||||
msgstr "手動ログイン"
|
||||
|
||||
msgctxt "#30366"
|
||||
msgid "Manually enter user details"
|
||||
msgstr "ユーザー詳細を手動で入力"
|
||||
|
||||
msgctxt "#30367"
|
||||
msgid "Allow fast user switching password saving"
|
||||
msgstr "切り替えたユーザーのパスワードの保存を許可"
|
||||
|
||||
msgctxt "#30368"
|
||||
msgid "Clear Password?"
|
||||
msgstr "パスワードを消去しますか?"
|
||||
|
||||
msgctxt "#30369"
|
||||
msgid "Do you want to clear your saved password?"
|
||||
msgstr "保存されたパスワードを消去しますか?"
|
||||
|
||||
msgctxt "#30370"
|
||||
msgid "Do you want to manually enter a server url?"
|
||||
msgstr "サーバーURLを手動で入力しますか?"
|
||||
|
||||
msgctxt "#30371"
|
||||
msgid "Could not connect to the URL you entered, do you want to try again?"
|
||||
msgstr "入力されたURLに接続できませんでした。再試行しますか?"
|
||||
|
||||
msgctxt "#30372"
|
||||
msgid "Server URL"
|
||||
msgstr "サーバーURL"
|
||||
|
||||
msgctxt "#30373"
|
||||
msgid "Scanning for local servers"
|
||||
msgstr "ローカルサーバーを検索中"
|
||||
|
||||
msgctxt "#30374"
|
||||
msgid "Sending request"
|
||||
msgstr "リクエストを送信中"
|
||||
|
||||
msgctxt "#30377"
|
||||
msgid "Sending request"
|
||||
msgstr "リクエストを送信中"
|
||||
|
||||
msgctxt "#30378"
|
||||
msgid "Persist user details"
|
||||
msgstr "ユーザー詳細を保持する"
|
||||
|
||||
msgctxt "#30376"
|
||||
msgid "Checking server url"
|
||||
msgstr "サーバーURLを検証中"
|
||||
|
||||
msgctxt "#30236"
|
||||
msgid "Force transcode h265 (hevc)"
|
||||
msgstr "h265 (hevc)でのトランスコードを強制する"
|
||||
|
||||
msgctxt "#30240"
|
||||
msgid "Force transcode msmpeg4v3 (divx)"
|
||||
msgstr "msmpeg4v3 (divx)でのトランスコードを強制する"
|
||||
|
||||
msgctxt "#30251"
|
||||
msgid "Movies - Genres"
|
||||
msgstr "映画 - ジャンル"
|
||||
|
||||
msgctxt "#30289"
|
||||
msgid "TV Shows - Genres"
|
||||
msgstr "TV番組 - ジャンル"
|
||||
|
||||
msgctxt "#30310"
|
||||
msgid "Enable Jellyfin remote control"
|
||||
msgstr "Jellyfinリモートコントロールを有効化"
|
||||
|
||||
msgctxt "#30333"
|
||||
msgid "Cache artwork in the background"
|
||||
msgstr "アートワークをバックグラウンドでキャッシュ"
|
||||
|
||||
msgctxt "#30223"
|
||||
msgid "Page Size and Filtering"
|
||||
msgstr "ページサイズとフィルタリング"
|
||||
|
||||
msgctxt "#30247"
|
||||
msgid "Custom Widget Content"
|
||||
msgstr "カスタムウィジェットコンテンツ"
|
||||
|
||||
msgctxt "#30263"
|
||||
msgid "Episodes - Recently Added"
|
||||
msgstr "エピソード - 最近追加された"
|
||||
|
||||
msgctxt "#30298"
|
||||
msgid "Deleting Kodi Images"
|
||||
msgstr "Kodiイメージを削除中"
|
||||
|
||||
msgctxt "#30375"
|
||||
msgid "Receiving data packet"
|
||||
msgstr "データパケットを受信中"
|
||||
|
||||
msgctxt "#30238"
|
||||
msgid "Playback stream options"
|
||||
msgstr "再生ストリームオプション"
|
||||
|
||||
msgctxt "#30242"
|
||||
msgid "Force transcode av1"
|
||||
msgstr "av1でのトランスコードを強制する"
|
||||
|
||||
msgctxt "#30300"
|
||||
msgid "Cache all Jellyfin images as local Kodi images?"
|
||||
msgstr "全てのJellyfinイメージをローカルなKodiイメージとしてキャッシュしますか?"
|
||||
|
||||
msgctxt "#30277"
|
||||
msgid "JellyCon needs to prompt for resume on partily played items, Kodi can also prompt, this can cause a double prompt. Do you want to remove the double prompt?"
|
||||
msgstr ""
|
||||
"JellyConは途中まで再生したアイテムを途中から再生するか質問しますが、Kodiも同"
|
||||
"じ質問をすることがあります。重複した質問を取り除きますか?"
|
||||
@@ -1,6 +1,6 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2021-11-14 13:05+0000\n"
|
||||
"PO-Revision-Date: 2022-08-10 20:22+0000\n"
|
||||
"Last-Translator: WWWesten <wwwesten@gmail.com>\n"
|
||||
"Language-Team: Kazakh <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/kk/>\n"
|
||||
@@ -9,7 +9,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 4.5.2\n"
|
||||
"X-Generator: Weblate 4.10.1\n"
|
||||
|
||||
msgctxt "#30371"
|
||||
msgid "Could not connect to the URL you entered, do you want to try again?"
|
||||
@@ -1008,7 +1008,7 @@ msgstr "Belgısız"
|
||||
|
||||
msgctxt "#30246"
|
||||
msgid "Search"
|
||||
msgstr "İzdeu"
|
||||
msgstr "Izdeu"
|
||||
|
||||
msgctxt "#30235"
|
||||
msgid "Episodes"
|
||||
@@ -1089,3 +1089,19 @@ msgstr "Порт"
|
||||
msgctxt "#30000"
|
||||
msgid "Host"
|
||||
msgstr "Tüiın"
|
||||
|
||||
msgctxt "#30444"
|
||||
msgid "Login using Quick Connect"
|
||||
msgstr "Jyldam qosyludy paidalanyp kıru"
|
||||
|
||||
msgctxt "#30443"
|
||||
msgid "Quick Connect"
|
||||
msgstr "Jyldam qosylu"
|
||||
|
||||
msgctxt "#30323"
|
||||
msgid "Artists"
|
||||
msgstr "Oryndauşylar"
|
||||
|
||||
msgctxt "#30445"
|
||||
msgid "Continue Watching"
|
||||
msgstr "Qaraudy jalğastyru"
|
||||
|
||||
396
resources/language/resource.language.ko/strings.po
Normal file
396
resources/language/resource.language.ko/strings.po
Normal file
@@ -0,0 +1,396 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2022-11-23 06:51+0000\n"
|
||||
"Last-Translator: wolfwork <wolfdate25@naver.com>\n"
|
||||
"Language-Team: Korean <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/ko/>\n"
|
||||
"Language: ko\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"X-Generator: Weblate 4.14.1\n"
|
||||
|
||||
msgctxt "#30006"
|
||||
msgid "Password"
|
||||
msgstr "비밀번호"
|
||||
|
||||
msgctxt "#30025"
|
||||
msgid "Password:"
|
||||
msgstr "비밀번호:"
|
||||
|
||||
msgctxt "#30026"
|
||||
msgid "Widget item select action"
|
||||
msgstr "위젯 항목 선택 작업"
|
||||
|
||||
msgctxt "#30045"
|
||||
msgid "Username not found"
|
||||
msgstr "사용자 이름을 찾을 수 없습니다"
|
||||
|
||||
msgctxt "#30112"
|
||||
msgid "Loading Content"
|
||||
msgstr "콘텐츠 로드 중"
|
||||
|
||||
msgctxt "#30120"
|
||||
msgid "Show load progress"
|
||||
msgstr "로드 진행률 표시"
|
||||
|
||||
msgctxt "#30121"
|
||||
msgid "On resume"
|
||||
msgstr "재개 시"
|
||||
|
||||
msgctxt "#30166"
|
||||
msgid "Select Server"
|
||||
msgstr "서버 선택"
|
||||
|
||||
msgctxt "#30212"
|
||||
msgid "Video max width"
|
||||
msgstr "비디오 최대 길이"
|
||||
|
||||
msgctxt "#30251"
|
||||
msgid "Movies - Genres"
|
||||
msgstr "영화 - 장르"
|
||||
|
||||
msgctxt "#30264"
|
||||
msgid "Episodes - In Progress"
|
||||
msgstr "에피소드 - 진행 중"
|
||||
|
||||
msgctxt "#30269"
|
||||
msgid "Movies - Random"
|
||||
msgstr "영화 - 랜덤"
|
||||
|
||||
msgctxt "#30000"
|
||||
msgid "Host"
|
||||
msgstr "호스트"
|
||||
|
||||
msgctxt "#30001"
|
||||
msgid "Port"
|
||||
msgstr "포트"
|
||||
|
||||
msgctxt "#30003"
|
||||
msgid "Verify HTTPS certificate"
|
||||
msgstr "HTTPS 인증서 확인"
|
||||
|
||||
msgctxt "#30005"
|
||||
msgid "Username"
|
||||
msgstr "사용자 이름"
|
||||
|
||||
msgctxt "#30007"
|
||||
msgid "Samba username"
|
||||
msgstr "Samba 사용자이름"
|
||||
|
||||
msgctxt "#30008"
|
||||
msgid "Samba password"
|
||||
msgstr "Samba 비밀번호"
|
||||
|
||||
msgctxt "#30011"
|
||||
msgid "[Detect local server]"
|
||||
msgstr "[로컬 서버 찾기]"
|
||||
|
||||
msgctxt "#30012"
|
||||
msgid "[Change user]"
|
||||
msgstr "[사용자 변경]"
|
||||
|
||||
msgctxt "#30015"
|
||||
msgid "Log timing data"
|
||||
msgstr "로그 타이밍 데이터"
|
||||
|
||||
msgctxt "#30016"
|
||||
msgid "Device display name"
|
||||
msgstr "장치 표시 이름"
|
||||
|
||||
msgctxt "#30017"
|
||||
msgid "Show connected clients"
|
||||
msgstr "연결된 클라이언트 표시"
|
||||
|
||||
msgctxt "#30018"
|
||||
msgid "Number of items to show in filtered lists"
|
||||
msgstr "필터링된 목록에 표시할 항목 수"
|
||||
|
||||
msgctxt "#30019"
|
||||
msgid "Filtered episode name format"
|
||||
msgstr "필터링된 에피소드 이름 형식"
|
||||
|
||||
msgctxt "#30021"
|
||||
msgid "Show all episodes item"
|
||||
msgstr "모든 에피소드 보기"
|
||||
|
||||
msgctxt "#30022"
|
||||
msgid "Advanced"
|
||||
msgstr "고급"
|
||||
|
||||
msgctxt "#30023"
|
||||
msgid "Hide unwatched episode details"
|
||||
msgstr "시청하지 않은 에피소드 세부정보 숨기기"
|
||||
|
||||
msgctxt "#30024"
|
||||
msgid "Username:"
|
||||
msgstr "사용자이름:"
|
||||
|
||||
msgctxt "#30027"
|
||||
msgid "Enable debug logging"
|
||||
msgstr "디버그 로깅 활성화"
|
||||
|
||||
msgctxt "#30044"
|
||||
msgid "Incorrect Username/Password"
|
||||
msgstr "잘못된 사용자이름/비밀번호"
|
||||
|
||||
msgctxt "#30052"
|
||||
msgid "Deleting"
|
||||
msgstr "삭제 중"
|
||||
|
||||
msgctxt "#30053"
|
||||
msgid "Waiting for server to delete"
|
||||
msgstr "서버에서 삭제 대기 중"
|
||||
|
||||
msgctxt "#30091"
|
||||
msgid "Confirm delete?"
|
||||
msgstr "삭제하시겠습니까?"
|
||||
|
||||
msgctxt "#30092"
|
||||
msgid "Warning: This action will delete the media files from the server."
|
||||
msgstr "경고: 이 작업은 서버에서 미디어 파일을 삭제합니다."
|
||||
|
||||
msgctxt "#30110"
|
||||
msgid "Interface"
|
||||
msgstr "인터페이스"
|
||||
|
||||
msgctxt "#30111"
|
||||
msgid "Services"
|
||||
msgstr "서비스"
|
||||
|
||||
msgctxt "#30113"
|
||||
msgid "Retrieving Data"
|
||||
msgstr "데이터 수신 중"
|
||||
|
||||
msgctxt "#30114"
|
||||
msgid "Jump back seconds"
|
||||
msgstr "초 뒤로 이동"
|
||||
|
||||
msgctxt "#30116"
|
||||
msgid "Add unwatched counts to names"
|
||||
msgstr "이름에 시청하지 않은 카운트 수 추가"
|
||||
|
||||
msgctxt "#30118"
|
||||
msgid "Add resume percent to names"
|
||||
msgstr "이름에 재개율 추가"
|
||||
|
||||
msgctxt "#30125"
|
||||
msgid "Done"
|
||||
msgstr "완료"
|
||||
|
||||
msgctxt "#30126"
|
||||
msgid "Processing Item : "
|
||||
msgstr "진행중인 항목:"
|
||||
|
||||
msgctxt "#30135"
|
||||
msgid "Error"
|
||||
msgstr "오류"
|
||||
|
||||
msgctxt "#30139"
|
||||
msgid "No Media Type Set"
|
||||
msgstr "미디어 타입 설정 안됨"
|
||||
|
||||
msgctxt "#30163"
|
||||
msgid "Add (cc) if subtitle is available"
|
||||
msgstr "자막이 존재할 경우 (cc) 추가"
|
||||
|
||||
msgctxt "#30167"
|
||||
msgid "Selected Server Address"
|
||||
msgstr "선택된 서버 주소"
|
||||
|
||||
msgctxt "#30169"
|
||||
msgid "Address: "
|
||||
msgstr "주소:"
|
||||
|
||||
msgctxt "#30180"
|
||||
msgid "Select User"
|
||||
msgstr "사용자 선택"
|
||||
|
||||
msgctxt "#30181"
|
||||
msgid "Include plot"
|
||||
msgstr "플롯 포함"
|
||||
|
||||
msgctxt "#30182"
|
||||
msgid "Include media stream info"
|
||||
msgstr "미디어 스트림 정보 포함"
|
||||
|
||||
msgctxt "#30183"
|
||||
msgid "Include people"
|
||||
msgstr "사람 포함"
|
||||
|
||||
msgctxt "#30200"
|
||||
msgid "URL error"
|
||||
msgstr "URL 오류"
|
||||
|
||||
msgctxt "#30201"
|
||||
msgid "Unable to connect to server"
|
||||
msgstr "서버에 연결할 수 없습니다"
|
||||
|
||||
msgctxt "#30206"
|
||||
msgid "Playback type"
|
||||
msgstr "재생 유형"
|
||||
|
||||
msgctxt "#30207"
|
||||
msgid "Playback"
|
||||
msgstr "재생"
|
||||
|
||||
msgctxt "#30208"
|
||||
msgid "Max stream bitrate (Kbits)"
|
||||
msgstr "최대 스트림 비트레이트 (Kbps)"
|
||||
|
||||
msgctxt "#30209"
|
||||
msgid "File direct path"
|
||||
msgstr "파일 직접 경로"
|
||||
|
||||
msgctxt "#30210"
|
||||
msgid "HTTP direct stream"
|
||||
msgstr "HTTP 직접 스트림"
|
||||
|
||||
msgctxt "#30211"
|
||||
msgid "Transcode options"
|
||||
msgstr "트랜스코드 옵션"
|
||||
|
||||
msgctxt "#30213"
|
||||
msgid "Video force 8 bit"
|
||||
msgstr "비디오 강제 8 bit"
|
||||
|
||||
msgctxt "#30214"
|
||||
msgid "Events"
|
||||
msgstr "이벤트"
|
||||
|
||||
msgctxt "#30215"
|
||||
msgid "On playback stop (100% = disabled)"
|
||||
msgstr "재생 중지 시(100% = 비활성화됨)"
|
||||
|
||||
msgctxt "#30216"
|
||||
msgid "Item Details"
|
||||
msgstr "항목 세부정보"
|
||||
|
||||
msgctxt "#30218"
|
||||
msgid "Play next episode after %"
|
||||
msgstr "% 후 다음 에피소드 재생"
|
||||
|
||||
msgctxt "#30222"
|
||||
msgid "Item Layout"
|
||||
msgstr "항목 레이아웃"
|
||||
|
||||
msgctxt "#30223"
|
||||
msgid "Page Size and Filtering"
|
||||
msgstr "페이지 크기와 필터링"
|
||||
|
||||
msgctxt "#30224"
|
||||
msgid "Interaction"
|
||||
msgstr "상호작용"
|
||||
|
||||
msgctxt "#30229"
|
||||
msgid "TV Shows"
|
||||
msgstr "TV 쇼"
|
||||
|
||||
msgctxt "#30231"
|
||||
msgid "Movies"
|
||||
msgstr "영화"
|
||||
|
||||
msgctxt "#30235"
|
||||
msgid "Episodes"
|
||||
msgstr "에피소드"
|
||||
|
||||
msgctxt "#30236"
|
||||
msgid "Force transcode h265 (hevc)"
|
||||
msgstr "강제 트랜스코드 h265 (hevc)"
|
||||
|
||||
msgctxt "#30237"
|
||||
msgid "Start from beginning"
|
||||
msgstr "처음부터 시작"
|
||||
|
||||
msgctxt "#30238"
|
||||
msgid "Playback stream options"
|
||||
msgstr "재생 스트림 옵션"
|
||||
|
||||
msgctxt "#30239"
|
||||
msgid "Force transcode mpeg2"
|
||||
msgstr "강제 트랜스코드 mpeg2"
|
||||
|
||||
msgctxt "#30240"
|
||||
msgid "Force transcode msmpeg4v3 (divx)"
|
||||
msgstr "강제 트랜스코드 msmpeg4v3 (divx)"
|
||||
|
||||
msgctxt "#30241"
|
||||
msgid "Force transcode mpeg4"
|
||||
msgstr "강제 트랜스코드 mpeg4"
|
||||
|
||||
msgctxt "#30246"
|
||||
msgid "Search"
|
||||
msgstr "검색"
|
||||
|
||||
msgctxt "#30247"
|
||||
msgid "Custom Widget Content"
|
||||
msgstr "사용자 지정 위젯 콘텐츠"
|
||||
|
||||
msgctxt "#30250"
|
||||
msgid "Unknown"
|
||||
msgstr "알수없음"
|
||||
|
||||
msgctxt "#30252"
|
||||
msgid "Movies - A-Z"
|
||||
msgstr "영화 - A-Z"
|
||||
|
||||
msgctxt "#30254"
|
||||
msgid "Show add-on settings"
|
||||
msgstr "에드온 설정 보기"
|
||||
|
||||
msgctxt "#30255"
|
||||
msgid "TV Shows - A-Z"
|
||||
msgstr "TV 쇼 - A-Z"
|
||||
|
||||
msgctxt "#30256"
|
||||
msgid "Movies"
|
||||
msgstr "영화"
|
||||
|
||||
msgctxt "#30257"
|
||||
msgid "Movies - Recently Added"
|
||||
msgstr "영화 - 최근에 추가됨"
|
||||
|
||||
msgctxt "#30258"
|
||||
msgid "Movies - In Progress"
|
||||
msgstr "영화 - 진행 중"
|
||||
|
||||
msgctxt "#30259"
|
||||
msgid "Movies - Favorites"
|
||||
msgstr "영화 - 즐겨찾기"
|
||||
|
||||
msgctxt "#30261"
|
||||
msgid "TV Shows"
|
||||
msgstr "TV 쇼"
|
||||
|
||||
msgctxt "#30262"
|
||||
msgid "TV Shows - Favorites"
|
||||
msgstr "TV 쇼 - 즐겨찾기"
|
||||
|
||||
msgctxt "#30263"
|
||||
msgid "Episodes - Recently Added"
|
||||
msgstr "에피소드 - 최근에 추가됨"
|
||||
|
||||
msgctxt "#30266"
|
||||
msgid "Movies - Pages"
|
||||
msgstr "영화 - 페이지"
|
||||
|
||||
msgctxt "#30267"
|
||||
msgid " - In Progress"
|
||||
msgstr "- 진행 중"
|
||||
|
||||
msgctxt "#30268"
|
||||
msgid " - Recently Added"
|
||||
msgstr "- 최근에 추가됨"
|
||||
|
||||
msgctxt "#30270"
|
||||
msgid "Mark Watched"
|
||||
msgstr "본 것으로 표시"
|
||||
|
||||
msgctxt "#30271"
|
||||
msgid "Mark Unwatched"
|
||||
msgstr "본 것으로 표시해제"
|
||||
|
||||
msgctxt "#30272"
|
||||
msgid "Set Favourite"
|
||||
msgstr "즐겨찾기 설정"
|
||||
2
resources/language/resource.language.mk/strings.po
Normal file
2
resources/language/resource.language.mk/strings.po
Normal file
@@ -0,0 +1,2 @@
|
||||
msgid ""
|
||||
msgstr "X-Generator: Weblate\nMIME-Version: 1.0\nContent-Type: text/plain; charset=UTF-8\nContent-Transfer-Encoding: 8bit"
|
||||
1151
resources/language/resource.language.nb_NO/strings.po
Normal file
1151
resources/language/resource.language.nb_NO/strings.po
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2021-11-23 03:05+0000\n"
|
||||
"Last-Translator: Marcin Woliński <cierdek@gmail.com>\n"
|
||||
"PO-Revision-Date: 2024-10-30 10:10+0000\n"
|
||||
"Last-Translator: Kityn <kitynska@gmail.com>\n"
|
||||
"Language-Team: Polish <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/pl/>\n"
|
||||
"Language: pl\n"
|
||||
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
|
||||
"|| n%100>=20) ? 1 : 2;\n"
|
||||
"X-Generator: Weblate 4.5.2\n"
|
||||
"X-Generator: Weblate 5.7.2\n"
|
||||
|
||||
msgctxt "#30313"
|
||||
msgid "Menu"
|
||||
@@ -118,11 +118,11 @@ msgstr "- Ostatnie"
|
||||
|
||||
msgctxt "#30287"
|
||||
msgid "TV Shows - Latest"
|
||||
msgstr "Seriale — ostatnie"
|
||||
msgstr "Seriale - Ostatnie"
|
||||
|
||||
msgctxt "#30286"
|
||||
msgid "Movies - Unwatched"
|
||||
msgstr "Filmy – nieobejrzane"
|
||||
msgstr "Filmy - Nieobejrzane"
|
||||
|
||||
msgctxt "#30285"
|
||||
msgid " - Unwatched"
|
||||
@@ -146,7 +146,7 @@ msgstr "Brak tytułu"
|
||||
|
||||
msgctxt "#30279"
|
||||
msgid "TV Shows - Unwatched"
|
||||
msgstr "Seriale - Nieoglądane"
|
||||
msgstr "Seriale - Nieobejrzane"
|
||||
|
||||
msgctxt "#30278"
|
||||
msgid " - Next Up"
|
||||
@@ -181,7 +181,7 @@ msgstr "Ustaw ulubione"
|
||||
|
||||
msgctxt "#30271"
|
||||
msgid "Mark Unwatched"
|
||||
msgstr "Oznacz nieoglądane"
|
||||
msgstr "Oznacz nieobejrzane"
|
||||
|
||||
msgctxt "#30270"
|
||||
msgid "Mark Watched"
|
||||
@@ -189,7 +189,7 @@ msgstr "Zaznacz obserwowane"
|
||||
|
||||
msgctxt "#30269"
|
||||
msgid "Movies - Random"
|
||||
msgstr "Filmy — losowe"
|
||||
msgstr "Filmy - Losowe"
|
||||
|
||||
msgctxt "#30268"
|
||||
msgid " - Recently Added"
|
||||
@@ -201,23 +201,23 @@ msgstr "- W trakcie"
|
||||
|
||||
msgctxt "#30266"
|
||||
msgid "Movies - Pages"
|
||||
msgstr "Filmy – Strony"
|
||||
msgstr "Filmy - Strony"
|
||||
|
||||
msgctxt "#30265"
|
||||
msgid "Episodes - Next Up"
|
||||
msgstr "Odcinki — Następny"
|
||||
msgstr "Odcinki - Następny"
|
||||
|
||||
msgctxt "#30264"
|
||||
msgid "Episodes - In Progress"
|
||||
msgstr "Odcinki — w toku"
|
||||
msgstr "Odcinki - W trakcie"
|
||||
|
||||
msgctxt "#30263"
|
||||
msgid "Episodes - Recently Added"
|
||||
msgstr "Odcinki — ostatnio dodane"
|
||||
msgstr "Odcinki - Ostatnio dodane"
|
||||
|
||||
msgctxt "#30262"
|
||||
msgid "TV Shows - Favorites"
|
||||
msgstr "Seriale – Ulubione"
|
||||
msgstr "Seriale - Ulubione"
|
||||
|
||||
msgctxt "#30261"
|
||||
msgid "TV Shows"
|
||||
@@ -233,11 +233,11 @@ msgstr "Filmy - Ulubione"
|
||||
|
||||
msgctxt "#30258"
|
||||
msgid "Movies - In Progress"
|
||||
msgstr "Filmy – w toku"
|
||||
msgstr "Filmy - W trakcie"
|
||||
|
||||
msgctxt "#30257"
|
||||
msgid "Movies - Recently Added"
|
||||
msgstr "Filmy — ostatnio dodane"
|
||||
msgstr "Filmy - Ostatnio dodane"
|
||||
|
||||
msgctxt "#30256"
|
||||
msgid "Movies"
|
||||
@@ -257,7 +257,7 @@ msgstr "Filmy - A-Z"
|
||||
|
||||
msgctxt "#30251"
|
||||
msgid "Movies - Genres"
|
||||
msgstr "Filmy – Gatunki"
|
||||
msgstr "Filmy - Gatunki"
|
||||
|
||||
msgctxt "#30250"
|
||||
msgid "Unknown"
|
||||
@@ -309,7 +309,7 @@ msgstr "Seriale"
|
||||
|
||||
msgctxt "#30213"
|
||||
msgid "Video force 8 bit"
|
||||
msgstr "Wymuś video 8 bit"
|
||||
msgstr "Wymuś wideo 8-bitowe"
|
||||
|
||||
msgctxt "#30224"
|
||||
msgid "Interaction"
|
||||
@@ -429,11 +429,11 @@ msgstr "Brak zestawu typu nośnika"
|
||||
|
||||
msgctxt "#30321"
|
||||
msgid " - Album Artists"
|
||||
msgstr "- Artyści albumów"
|
||||
msgstr "- Wykonawcy albumów"
|
||||
|
||||
msgctxt "#30319"
|
||||
msgid "Music - All Album Artists"
|
||||
msgstr "Muzyka — wszyscy wykonawcy albumów"
|
||||
msgstr "Muzyka - Wszyscy wykonawcy albumów"
|
||||
|
||||
msgctxt "#30332"
|
||||
msgid "Stop media playback on screensaver activation"
|
||||
@@ -659,3 +659,505 @@ msgstr "Zweryfikuj certyfikat HTTPS"
|
||||
msgctxt "#30001"
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
msgctxt "#30436"
|
||||
msgid "Speed test data size (MB)"
|
||||
msgstr "Rozmiar danych testu prędkości (MB)"
|
||||
|
||||
msgctxt "#30435"
|
||||
msgid "Connection speed test"
|
||||
msgstr "Test prędkości połączenia"
|
||||
|
||||
msgctxt "#30434"
|
||||
msgid "Force transcode stream bitrate (Kbits)"
|
||||
msgstr "Wymuś szybkość transmisji strumienia transkodowania (Kb/s)"
|
||||
|
||||
msgctxt "#30433"
|
||||
msgid "Allow direct file playback"
|
||||
msgstr "Zezwalaj na bezpośrednie odtwarzanie plików"
|
||||
|
||||
msgctxt "#30432"
|
||||
msgid "Hide watched items in lists"
|
||||
msgstr "Ukryj obejrzane rzeczy na listach"
|
||||
|
||||
msgctxt "#30431"
|
||||
msgid "Seasons"
|
||||
msgstr "Sezony"
|
||||
|
||||
msgctxt "#30430"
|
||||
msgid "Label"
|
||||
msgstr "Etykieta"
|
||||
|
||||
msgctxt "#30429"
|
||||
msgid "Genre"
|
||||
msgstr "Gatunek"
|
||||
|
||||
msgctxt "#30428"
|
||||
msgid "Rating"
|
||||
msgstr "Ocena"
|
||||
|
||||
msgctxt "#30427"
|
||||
msgid "Added"
|
||||
msgstr "Dodane"
|
||||
|
||||
msgctxt "#30426"
|
||||
msgid "Title"
|
||||
msgstr "Tytuł"
|
||||
|
||||
msgctxt "#30425"
|
||||
msgid "Year"
|
||||
msgstr "Rok"
|
||||
|
||||
msgctxt "#30424"
|
||||
msgid "Default"
|
||||
msgstr "Domyślne"
|
||||
|
||||
msgctxt "#30423"
|
||||
msgid "NotSet"
|
||||
msgstr "Nie ustawione"
|
||||
|
||||
msgctxt "#30422"
|
||||
msgid "Sorting"
|
||||
msgstr "Sortowanie"
|
||||
|
||||
msgctxt "#30421"
|
||||
msgid "Views"
|
||||
msgstr "Wyświetlenia"
|
||||
|
||||
msgctxt "#30420"
|
||||
msgid "Audio max channels"
|
||||
msgstr "Maksymalna liczba kanałów audio"
|
||||
|
||||
msgctxt "#30419"
|
||||
msgid "Audio codec"
|
||||
msgstr "Kodek audio"
|
||||
|
||||
msgctxt "#30418"
|
||||
msgid "Audio bitrate (Kbits)"
|
||||
msgstr "Szybkość transmisji dźwięku (Kb/s)"
|
||||
|
||||
msgctxt "#30417"
|
||||
msgid "You do not have permision to delete this item"
|
||||
msgstr "Nie masz uprawnień do usunięcia tego elementu"
|
||||
|
||||
msgctxt "#30416"
|
||||
msgid "HTTP timeout seconds"
|
||||
msgstr "Sekundy limitu czasu HTTP"
|
||||
|
||||
msgctxt "#30415"
|
||||
msgid " - Favorite Collections"
|
||||
msgstr "- Ulubione kolekcje"
|
||||
|
||||
msgctxt "#30414"
|
||||
msgid " - Favorites"
|
||||
msgstr "- Ulubione"
|
||||
|
||||
msgctxt "#30413"
|
||||
msgid " - Tags"
|
||||
msgstr "- Tagi"
|
||||
|
||||
msgctxt "#30412"
|
||||
msgid " - Decades"
|
||||
msgstr "- Dekady"
|
||||
|
||||
msgctxt "#30411"
|
||||
msgid " - Years"
|
||||
msgstr "- Lata"
|
||||
|
||||
msgctxt "#30410"
|
||||
msgid " - Collections"
|
||||
msgstr "- Kolekcje"
|
||||
|
||||
msgctxt "#30409"
|
||||
msgid "Add-on Actions"
|
||||
msgstr "Akcje dodatkowe"
|
||||
|
||||
msgctxt "#30408"
|
||||
msgid "Custom Widgets"
|
||||
msgstr "Niestandardowe widżety"
|
||||
|
||||
msgctxt "#30407"
|
||||
msgid "Global Lists"
|
||||
msgstr "Listy globalne"
|
||||
|
||||
msgctxt "#30406"
|
||||
msgid "Jellyfin Libraries"
|
||||
msgstr "Biblioteki Jellyfin"
|
||||
|
||||
msgctxt "#30405"
|
||||
msgid " - Show All"
|
||||
msgstr "- Pokaż wszystko"
|
||||
|
||||
msgctxt "#30404"
|
||||
msgid " - A-Z"
|
||||
msgstr "- A-Z"
|
||||
|
||||
msgctxt "#30403"
|
||||
msgid "Movies - Recommendations"
|
||||
msgstr "Filmy - Rekomendacje"
|
||||
|
||||
msgctxt "#30402"
|
||||
msgid "Add to Kodi Playlist"
|
||||
msgstr "Dodaj do listy odtwarzania Kodi"
|
||||
|
||||
msgctxt "#30401"
|
||||
msgid "Info"
|
||||
msgstr "Informacja"
|
||||
|
||||
msgctxt "#30400"
|
||||
msgid "Cache images interval minutes (0 = disabled)"
|
||||
msgstr "Interwał obrazów w pamięci podręcznej w minutach (0 = wyłączone)"
|
||||
|
||||
msgctxt "#30399"
|
||||
msgid "Hide"
|
||||
msgstr "Ukryj"
|
||||
|
||||
msgctxt "#30398"
|
||||
msgid "Refresh Jellyfin Metadata"
|
||||
msgstr "Odśwież metadane Jellyfin"
|
||||
|
||||
msgctxt "#30397"
|
||||
msgid " - Pages"
|
||||
msgstr "- Strony"
|
||||
|
||||
msgctxt "#30395"
|
||||
msgid "Clear cached server data"
|
||||
msgstr "Wyczyść dane serwera z pamięci podręcznej"
|
||||
|
||||
msgctxt "#30394"
|
||||
msgid "Cache files deleted"
|
||||
msgstr "Usunięto pliki pamięci podręcznej"
|
||||
|
||||
msgctxt "#30393"
|
||||
msgid "Clear Cache Result"
|
||||
msgstr "Wyczyść wynik pamięci podręcznej"
|
||||
|
||||
msgctxt "#30392"
|
||||
msgid "HTTPS"
|
||||
msgstr "HTTPS"
|
||||
|
||||
msgctxt "#30391"
|
||||
msgid "HTTP"
|
||||
msgstr "HTTP"
|
||||
|
||||
msgctxt "#30390"
|
||||
msgid "Protocol"
|
||||
msgstr "Protokół"
|
||||
|
||||
msgctxt "#30389"
|
||||
msgid "User details"
|
||||
msgstr "Dane użytkownika"
|
||||
|
||||
msgctxt "#30388"
|
||||
msgid "Server details"
|
||||
msgstr "Szczegóły serwera"
|
||||
|
||||
msgctxt "#30387"
|
||||
msgid "Unused images removed : "
|
||||
msgstr "Usunięto nieużywane obrazy:"
|
||||
|
||||
msgctxt "#30386"
|
||||
msgid "Unused Jellyfin images : "
|
||||
msgstr "Nieużywane obrazy Jellyfin:"
|
||||
|
||||
msgctxt "#30385"
|
||||
msgid "Existing images before delete : "
|
||||
msgstr "Istniejące obrazy przed usunięciem:"
|
||||
|
||||
msgctxt "#30384"
|
||||
msgid "Random movies interval minutes (0 = disabled)"
|
||||
msgstr "Interwał losowania filmów w minutach (0 = wyłączone)"
|
||||
|
||||
msgctxt "#30383"
|
||||
msgid "System - "
|
||||
msgstr "System -"
|
||||
|
||||
msgctxt "#30382"
|
||||
msgid "Always"
|
||||
msgstr "Zawsze"
|
||||
|
||||
msgctxt "#30381"
|
||||
msgid "More than one"
|
||||
msgstr "Więcej niż jeden"
|
||||
|
||||
msgctxt "#30380"
|
||||
msgid "Never"
|
||||
msgstr "Nigdy"
|
||||
|
||||
msgctxt "#30379"
|
||||
msgid "External subtitle prompt"
|
||||
msgstr "Monit o napisy zewnętrzne"
|
||||
|
||||
msgctxt "#30378"
|
||||
msgid "Persist user details"
|
||||
msgstr "Utrwal dane użytkownika"
|
||||
|
||||
msgctxt "#30377"
|
||||
msgid "Sending request"
|
||||
msgstr "Wysyłanie prośby"
|
||||
|
||||
msgctxt "#30376"
|
||||
msgid "Checking server url"
|
||||
msgstr "Sprawdzam adres URL serwera"
|
||||
|
||||
msgctxt "#30375"
|
||||
msgid "Receiving data packet"
|
||||
msgstr "Odbieranie pakietu danych"
|
||||
|
||||
msgctxt "#30374"
|
||||
msgid "Sending request"
|
||||
msgstr "Wyślij prośbę"
|
||||
|
||||
msgctxt "#30373"
|
||||
msgid "Scanning for local servers"
|
||||
msgstr "Skanowanie w poszukiwaniu serwerów lokalnych"
|
||||
|
||||
msgctxt "#30372"
|
||||
msgid "Server URL"
|
||||
msgstr "Adres URL serwera"
|
||||
|
||||
msgctxt "#30371"
|
||||
msgid "Could not connect to the URL you entered, do you want to try again?"
|
||||
msgstr ""
|
||||
"Nie można połączyć się z wprowadzonym adresem URL, czy chcesz spróbować "
|
||||
"ponownie?"
|
||||
|
||||
msgctxt "#30370"
|
||||
msgid "Do you want to manually enter a server url?"
|
||||
msgstr "Czy chcesz ręcznie wprowadzić adres URL serwera?"
|
||||
|
||||
msgctxt "#30369"
|
||||
msgid "Do you want to clear your saved password?"
|
||||
msgstr "Czy chcesz wyczyścić zapisane hasło?"
|
||||
|
||||
msgctxt "#30368"
|
||||
msgid "Clear Password?"
|
||||
msgstr "Wyczyścić hasło?"
|
||||
|
||||
msgctxt "#30367"
|
||||
msgid "Allow fast user switching password saving"
|
||||
msgstr "Zezwalaj na szybkie zapisywanie hasła przełączanego użytkownika"
|
||||
|
||||
msgctxt "#30366"
|
||||
msgid "Manually enter user details"
|
||||
msgstr "Wprowadź ręcznie dane użytkownika"
|
||||
|
||||
msgctxt "#30365"
|
||||
msgid "Manual Login"
|
||||
msgstr "Logowanie ręczne"
|
||||
|
||||
msgctxt "#30364"
|
||||
msgid "Do you want to save the password?"
|
||||
msgstr "Czy chcesz zapisać hasło?"
|
||||
|
||||
msgctxt "#30363"
|
||||
msgid "Save Password?"
|
||||
msgstr "Zapisać hasło?"
|
||||
|
||||
msgctxt "#30362"
|
||||
msgid " - Recordings"
|
||||
msgstr "- Nagrania"
|
||||
|
||||
msgctxt "#30361"
|
||||
msgid " - Programs"
|
||||
msgstr "- Programy"
|
||||
|
||||
msgctxt "#30360"
|
||||
msgid " - Channels"
|
||||
msgstr "- Kanały"
|
||||
|
||||
msgctxt "#30359"
|
||||
msgid "Building full image list"
|
||||
msgstr "Budowanie pełnej listy obrazów"
|
||||
|
||||
msgctxt "#30358"
|
||||
msgid "Retreiving remote image list"
|
||||
msgstr "Pobieranie zdalnej listy obrazów"
|
||||
|
||||
msgctxt "#30357"
|
||||
msgid "Processing existing image list"
|
||||
msgstr "Przetwarzanie istniejącej listy obrazów"
|
||||
|
||||
msgctxt "#30356"
|
||||
msgid "Loading existing image list"
|
||||
msgstr "Ładowanie istniejącej listy obrazów"
|
||||
|
||||
msgctxt "#30355"
|
||||
msgid "Kodi Settings->Services->Allow remote control via HTTP"
|
||||
msgstr "Ustawienia Kodi->Usługi->Zezwalaj na zdalne sterowanie przez HTTP"
|
||||
|
||||
msgctxt "#30354"
|
||||
msgid "Go To Series"
|
||||
msgstr "Przejdź do serii"
|
||||
|
||||
msgctxt "#30353"
|
||||
msgid " - Frequently Played"
|
||||
msgstr "- Często odtwarzane"
|
||||
|
||||
msgctxt "#30352"
|
||||
msgid "Music - Frequently Played"
|
||||
msgstr "Muzyka - Często odtwarzana"
|
||||
|
||||
msgctxt "#30351"
|
||||
msgid "Music - Recently Played"
|
||||
msgstr "Muzyka - Ostatnio odtwarzane"
|
||||
|
||||
msgctxt "#30350"
|
||||
msgid "Music - Recently Added"
|
||||
msgstr "Muzyka - Ostatnio dodane"
|
||||
|
||||
msgctxt "#30349"
|
||||
msgid " - Recently Played"
|
||||
msgstr "- Ostatnio odtwarzane"
|
||||
|
||||
msgctxt "#30348"
|
||||
msgid "Add user ratings"
|
||||
msgstr "Dodaj oceny użytkowników"
|
||||
|
||||
msgctxt "#30347"
|
||||
msgid "Getting Existing Images"
|
||||
msgstr "Pobieranie istniejących obrazów"
|
||||
|
||||
msgctxt "#30346"
|
||||
msgid "Deleteing Cached Images"
|
||||
msgstr "Usuwanie obrazów z pamięci podręcznej"
|
||||
|
||||
msgctxt "#30345"
|
||||
msgid "Cache Jellyfin server data requests"
|
||||
msgstr "Pamięć podręczna żądań danych serwera Jellyfin"
|
||||
|
||||
msgctxt "#30344"
|
||||
msgid "Number of images removed from cache"
|
||||
msgstr "Liczba obrazów usuniętych z pamięci podręcznej"
|
||||
|
||||
msgctxt "#30343"
|
||||
msgid "Changes Require Kodi Restart"
|
||||
msgstr "Zmiany wymagają restartu Kodi"
|
||||
|
||||
msgctxt "#30342"
|
||||
msgid "New content check interval (0 = disabled)"
|
||||
msgstr "Interwał sprawdzania nowej zawartości (0 = wyłączone)"
|
||||
|
||||
msgctxt "#30341"
|
||||
msgid "Background image update interval (0 = disabled)"
|
||||
msgstr "Interwał aktualizacji obrazu tła (0 = wyłączone)"
|
||||
|
||||
msgctxt "#30340"
|
||||
msgid "Group movies into collections"
|
||||
msgstr "Grupuj filmy w kolekcje"
|
||||
|
||||
msgctxt "#30339"
|
||||
msgid "Person"
|
||||
msgstr "Osoba"
|
||||
|
||||
msgctxt "#30338"
|
||||
msgid "Album"
|
||||
msgstr "Album"
|
||||
|
||||
msgctxt "#30337"
|
||||
msgid "Song"
|
||||
msgstr "Piosenka"
|
||||
|
||||
msgctxt "#30334"
|
||||
msgid "Use JellyCon context menu"
|
||||
msgstr "Użyj menu kontekstowego JellyCon"
|
||||
|
||||
msgctxt "#30333"
|
||||
msgid "Cache artwork in the background"
|
||||
msgstr "Zbieraj grafikę w tle"
|
||||
|
||||
msgctxt "#30442"
|
||||
msgid "Simple new content check"
|
||||
msgstr "Proste sprawdzanie nowej zawartości"
|
||||
|
||||
msgctxt "#30441"
|
||||
msgid "Use cached widget data"
|
||||
msgstr "Użyj buforowanych danych widżetów"
|
||||
|
||||
msgctxt "#30440"
|
||||
msgid "Play next"
|
||||
msgstr "Odtwórz następny"
|
||||
|
||||
msgctxt "#30439"
|
||||
msgid "Show play next episode at time left"
|
||||
msgstr "Pokaż odtwórz następny odcinek w pozostałym czasie"
|
||||
|
||||
msgctxt "#30438"
|
||||
msgid "Play cinema intros"
|
||||
msgstr "Odtwórz kinowe intro"
|
||||
|
||||
msgctxt "#30437"
|
||||
msgid "Playback options"
|
||||
msgstr "Opcje odtwarzania"
|
||||
|
||||
msgctxt "#30444"
|
||||
msgid "Login using Quick Connect"
|
||||
msgstr "Zaloguj przy użyciu szybkiego łączenia"
|
||||
|
||||
msgctxt "#30443"
|
||||
msgid "Quick Connect"
|
||||
msgstr "Szybkie łączenie"
|
||||
|
||||
msgctxt "#30323"
|
||||
msgid "Artists"
|
||||
msgstr "Wykonawcy"
|
||||
|
||||
msgctxt "#30439"
|
||||
msgid "Show play next episode at time left in seconds"
|
||||
msgstr "Pokaż odtworzenie następnego odcinka o czasie pozostałym w sekundach"
|
||||
|
||||
msgctxt "#30446"
|
||||
msgid "There was an error logging in"
|
||||
msgstr "Wystąpił błąd podczas logowania"
|
||||
|
||||
msgctxt "#30445"
|
||||
msgid "Continue Watching"
|
||||
msgstr "Kontynuuj oglądanie"
|
||||
|
||||
msgctxt "#30447"
|
||||
msgid "Max Play Queue Size"
|
||||
msgstr "Maksymalny rozmiar kolejki odtwarzania"
|
||||
|
||||
msgctxt "#30448"
|
||||
msgid "Shuffle"
|
||||
msgstr "Tasuj"
|
||||
|
||||
msgctxt "#30449"
|
||||
msgid "Instant Mix"
|
||||
msgstr "Natychmiastowe mieszanie"
|
||||
|
||||
msgctxt "#30225"
|
||||
msgid "Interface Mode"
|
||||
msgstr "Tryb interfejsu"
|
||||
|
||||
msgctxt "#30226"
|
||||
msgid "Default"
|
||||
msgstr "Domyślny"
|
||||
|
||||
msgctxt "#30227"
|
||||
msgid "Simple"
|
||||
msgstr "Prosty"
|
||||
|
||||
msgctxt "#30242"
|
||||
msgid "Force transcode av1"
|
||||
msgstr "Wymuś transkodowanie av1"
|
||||
|
||||
msgctxt "#30450"
|
||||
msgid "Next Up Rewatching"
|
||||
msgstr "Następne ponowne oglądanie"
|
||||
|
||||
msgctxt "#30451"
|
||||
msgid "Rewatch Days (0 = Disabled)"
|
||||
msgstr "Dni ponownego oglądania (0 = wyłączone)"
|
||||
|
||||
msgctxt "#30452"
|
||||
msgid "Combine instead of replace (might cause slow-down)"
|
||||
msgstr "Łącz zamiast zastępować (może powodować spowolnienie)"
|
||||
|
||||
msgctxt "#30453"
|
||||
msgid "Hide number of items to show on entry title"
|
||||
msgstr "Ukryj liczbę pozycji wyświetlanych w tytule wpisu"
|
||||
|
||||
msgctxt "#30454"
|
||||
msgid " - Totally Unwatched"
|
||||
msgstr " – Zupełnie nieobejrzane"
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2021-11-14 13:05+0000\n"
|
||||
"Last-Translator: WWWesten <wwwesten@gmail.com>\n"
|
||||
"PO-Revision-Date: 2024-05-03 23:28+0000\n"
|
||||
"Last-Translator: Mikhail Arkhipov <arkhipov.ms@gmail.com>\n"
|
||||
"Language-Team: Russian <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/ru/>\n"
|
||||
"Language: ru\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
|
||||
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||
"X-Generator: Weblate 4.5.2\n"
|
||||
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
||||
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||
"X-Generator: Weblate 5.4.2\n"
|
||||
|
||||
msgctxt "#30332"
|
||||
msgid "Stop media playback on screensaver activation"
|
||||
@@ -46,7 +46,7 @@ msgstr "Обработка элемента:"
|
||||
|
||||
msgctxt "#30017"
|
||||
msgid "Show connected clients"
|
||||
msgstr "Показывать подсоединённых клиентов"
|
||||
msgstr "Показывать подсоединённые устройства"
|
||||
|
||||
msgctxt "#30275"
|
||||
msgid "Force Transcode"
|
||||
@@ -309,7 +309,7 @@ msgstr "ТВ-передачи - Жанры"
|
||||
|
||||
msgctxt "#30287"
|
||||
msgid "TV Shows - Latest"
|
||||
msgstr "ТВ-передачи - Крайние"
|
||||
msgstr "ТВ-передачи - Последние"
|
||||
|
||||
msgctxt "#30279"
|
||||
msgid "TV Shows - Unwatched"
|
||||
@@ -353,7 +353,7 @@ msgstr "Кэшировать рисунки"
|
||||
|
||||
msgctxt "#30288"
|
||||
msgid " - Latest"
|
||||
msgstr "- Крайние"
|
||||
msgstr "- Последние"
|
||||
|
||||
msgctxt "#30285"
|
||||
msgid " - Unwatched"
|
||||
@@ -389,7 +389,7 @@ msgstr "Ошибка URL"
|
||||
|
||||
msgctxt "#30183"
|
||||
msgid "Include people"
|
||||
msgstr "Включить людей"
|
||||
msgstr "Включить пользователей"
|
||||
|
||||
msgctxt "#30181"
|
||||
msgid "Include plot"
|
||||
@@ -621,7 +621,7 @@ msgstr "Подновить кэшированные рисунки"
|
||||
|
||||
msgctxt "#30278"
|
||||
msgid " - Next Up"
|
||||
msgstr "- Очередное"
|
||||
msgstr "- Последнее"
|
||||
|
||||
msgctxt "#30269"
|
||||
msgid "Movies - Random"
|
||||
@@ -681,7 +681,7 @@ msgstr "Прямой путь к файлу"
|
||||
|
||||
msgctxt "#30114"
|
||||
msgid "Jump back seconds"
|
||||
msgstr "Откат на секунды"
|
||||
msgstr "Перескок назад, секунды"
|
||||
|
||||
msgctxt "#30045"
|
||||
msgid "Username not found"
|
||||
@@ -1085,4 +1085,73 @@ msgstr "Порт"
|
||||
|
||||
msgctxt "#30000"
|
||||
msgid "Host"
|
||||
msgstr "Узел"
|
||||
msgstr "Адрес сервера"
|
||||
|
||||
msgctxt "#30444"
|
||||
msgid "Login using Quick Connect"
|
||||
msgstr "Войти используя Быстрое подключение"
|
||||
|
||||
msgctxt "#30443"
|
||||
msgid "Quick Connect"
|
||||
msgstr "Быстрое подключение"
|
||||
|
||||
msgctxt "#30323"
|
||||
msgid "Artists"
|
||||
msgstr "Исполнители"
|
||||
|
||||
msgctxt "#30445"
|
||||
msgid "Continue Watching"
|
||||
msgstr "Продолжение просмотра"
|
||||
|
||||
msgctxt "#30439"
|
||||
msgid "Show play next episode at time left in seconds"
|
||||
msgstr ""
|
||||
"За сколько секунд до окончания показывать \"Воспроизвести следующий эпизод\""
|
||||
|
||||
msgctxt "#30446"
|
||||
msgid "There was an error logging in"
|
||||
msgstr "Произошла ошибка при входе"
|
||||
|
||||
msgctxt "#30448"
|
||||
msgid "Shuffle"
|
||||
msgstr "Перемешать"
|
||||
|
||||
msgctxt "#30447"
|
||||
msgid "Max Play Queue Size"
|
||||
msgstr "Максимальный размер очереди"
|
||||
|
||||
msgctxt "#30449"
|
||||
msgid "Instant Mix"
|
||||
msgstr "Мгновенное перемешивание"
|
||||
|
||||
msgctxt "#30225"
|
||||
msgid "Interface Mode"
|
||||
msgstr "Режим интерфейса"
|
||||
|
||||
msgctxt "#30226"
|
||||
msgid "Default"
|
||||
msgstr "По умолчанию"
|
||||
|
||||
msgctxt "#30227"
|
||||
msgid "Simple"
|
||||
msgstr "Простой"
|
||||
|
||||
msgctxt "#30242"
|
||||
msgid "Force transcode av1"
|
||||
msgstr "Принудительное перекодирование av1"
|
||||
|
||||
msgctxt "#30452"
|
||||
msgid "Combine instead of replace (might cause slow-down)"
|
||||
msgstr "Объединение вместо замены (может привести к замедлению работы)"
|
||||
|
||||
msgctxt "#30453"
|
||||
msgid "Hide number of items to show on entry title"
|
||||
msgstr "Скрыть количество элементов в заголовке"
|
||||
|
||||
msgctxt "#30450"
|
||||
msgid "Next Up Rewatching"
|
||||
msgstr "Далее Повторный просмотр"
|
||||
|
||||
msgctxt "#30451"
|
||||
msgid "Rewatch Days (0 = Disabled)"
|
||||
msgstr "Дни повторного просмотра (0 = отключено)"
|
||||
|
||||
1157
resources/language/resource.language.sk/strings.po
Normal file
1157
resources/language/resource.language.sk/strings.po
Normal file
File diff suppressed because it is too large
Load Diff
56
resources/language/resource.language.sq/strings.po
Normal file
56
resources/language/resource.language.sq/strings.po
Normal file
@@ -0,0 +1,56 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2024-07-14 10:41+0000\n"
|
||||
"Last-Translator: Filan Fisteku <motto_schillernd_01@icloud.com>\n"
|
||||
"Language-Team: Albanian <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/sq/>\n"
|
||||
"Language: sq\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.4.2\n"
|
||||
|
||||
msgctxt "#30001"
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
msgctxt "#30003"
|
||||
msgid "Verify HTTPS certificate"
|
||||
msgstr "Verifiko çertifikatën HTTPS"
|
||||
|
||||
msgctxt "#30006"
|
||||
msgid "Password"
|
||||
msgstr "Fjalkalimi"
|
||||
|
||||
msgctxt "#30007"
|
||||
msgid "Samba username"
|
||||
msgstr "Përdoruesi Samba"
|
||||
|
||||
msgctxt "#30008"
|
||||
msgid "Samba password"
|
||||
msgstr "Fjalkalimi Samba"
|
||||
|
||||
msgctxt "#30012"
|
||||
msgid "[Change user]"
|
||||
msgstr "[Ndrysho përdoruesin]"
|
||||
|
||||
msgctxt "#30014"
|
||||
msgid "Jellyfin"
|
||||
msgstr "Jellyfin"
|
||||
|
||||
msgctxt "#30016"
|
||||
msgid "Device display name"
|
||||
msgstr "Emri që shfaqet"
|
||||
|
||||
msgctxt "#30000"
|
||||
msgid "Host"
|
||||
msgstr "Host"
|
||||
|
||||
msgctxt "#30005"
|
||||
msgid "Username"
|
||||
msgstr "Përdoruesi"
|
||||
|
||||
msgctxt "#30011"
|
||||
msgid "[Detect local server]"
|
||||
msgstr "[Detect local server]"
|
||||
1151
resources/language/resource.language.sv/strings.po
Normal file
1151
resources/language/resource.language.sv/strings.po
Normal file
File diff suppressed because it is too large
Load Diff
16
resources/language/resource.language.ta/strings.po
Normal file
16
resources/language/resource.language.ta/strings.po
Normal file
@@ -0,0 +1,16 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2024-04-01 19:38+0000\n"
|
||||
"Last-Translator: Oatavandi <oatavandi@gmail.com>\n"
|
||||
"Language-Team: Tamil <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/ta/>\n"
|
||||
"Language: ta\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.4.2\n"
|
||||
|
||||
msgctxt "#30000"
|
||||
msgid "Host"
|
||||
msgstr "புரவலன்"
|
||||
@@ -1,2 +1,752 @@
|
||||
msgid ""
|
||||
msgstr "X-Generator: Weblate\nMIME-Version: 1.0\nContent-Type: text/plain; charset=UTF-8\nContent-Transfer-Encoding: 8bit"
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2024-08-19 23:41+0000\n"
|
||||
"Last-Translator: queeup <queeup@zoho.com>\n"
|
||||
"Language-Team: Turkish <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/tr/>\n"
|
||||
"Language: tr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.4.2\n"
|
||||
|
||||
msgctxt "#30237"
|
||||
msgid "Start from beginning"
|
||||
msgstr "Baştan başla"
|
||||
|
||||
msgctxt "#30236"
|
||||
msgid "Force transcode h265 (hevc)"
|
||||
msgstr "H265 (hevc) kod dönüştürmeyi zorla"
|
||||
|
||||
msgctxt "#30235"
|
||||
msgid "Episodes"
|
||||
msgstr "Bölümler"
|
||||
|
||||
msgctxt "#30231"
|
||||
msgid "Movies"
|
||||
msgstr "Filmler"
|
||||
|
||||
msgctxt "#30229"
|
||||
msgid "TV Shows"
|
||||
msgstr "Diziler"
|
||||
|
||||
msgctxt "#30224"
|
||||
msgid "Interaction"
|
||||
msgstr "Etkileşim"
|
||||
|
||||
msgctxt "#30223"
|
||||
msgid "Page Size and Filtering"
|
||||
msgstr "Sayfa Boyutu ve Filtreleme"
|
||||
|
||||
msgctxt "#30222"
|
||||
msgid "Item Layout"
|
||||
msgstr "Öğe Düzeni"
|
||||
|
||||
msgctxt "#30220"
|
||||
msgid "Prompt to delete movie after %"
|
||||
msgstr "%'den sonra filmi silme istemi"
|
||||
|
||||
msgctxt "#30219"
|
||||
msgid " - Prompt before play"
|
||||
msgstr "- Oynamadan önce sor"
|
||||
|
||||
msgctxt "#30218"
|
||||
msgid "Play next episode after %"
|
||||
msgstr "% sonra sonraki bölümü oynat"
|
||||
|
||||
msgctxt "#30217"
|
||||
msgid "Prompt to delete episode after %"
|
||||
msgstr "%'den sonra bölümü silme istemi"
|
||||
|
||||
msgctxt "#30216"
|
||||
msgid "Item Details"
|
||||
msgstr "Ürün Detayları"
|
||||
|
||||
msgctxt "#30215"
|
||||
msgid "On playback stop (100% = disabled)"
|
||||
msgstr "Oynatma durduğunda (%100 = devre dışı)"
|
||||
|
||||
msgctxt "#30214"
|
||||
msgid "Events"
|
||||
msgstr "Olaylar"
|
||||
|
||||
msgctxt "#30213"
|
||||
msgid "Video force 8 bit"
|
||||
msgstr "Video 8 bit kullanimini zorla"
|
||||
|
||||
msgctxt "#30212"
|
||||
msgid "Video max width"
|
||||
msgstr "Video maksimum genişliği"
|
||||
|
||||
msgctxt "#30211"
|
||||
msgid "Transcode options"
|
||||
msgstr "Kod dönüştürme seçenekleri"
|
||||
|
||||
msgctxt "#30210"
|
||||
msgid "HTTP direct stream"
|
||||
msgstr "HTTP doğrudan akış"
|
||||
|
||||
msgctxt "#30209"
|
||||
msgid "File direct path"
|
||||
msgstr "Dosyanın doğrudan yolu"
|
||||
|
||||
msgctxt "#30208"
|
||||
msgid "Max stream bitrate (Kbits)"
|
||||
msgstr "Maksimum akış bit hızı (Kbps)"
|
||||
|
||||
msgctxt "#30207"
|
||||
msgid "Playback"
|
||||
msgstr "Oynatma"
|
||||
|
||||
msgctxt "#30206"
|
||||
msgid "Playback type"
|
||||
msgstr "Oynatma türü"
|
||||
|
||||
msgctxt "#30201"
|
||||
msgid "Unable to connect to server"
|
||||
msgstr "Sunucuya bağlanılamıyor"
|
||||
|
||||
msgctxt "#30200"
|
||||
msgid "URL error"
|
||||
msgstr "URL hatası"
|
||||
|
||||
msgctxt "#30183"
|
||||
msgid "Include people"
|
||||
msgstr "Kişileri dahil et"
|
||||
|
||||
msgctxt "#30182"
|
||||
msgid "Include media stream info"
|
||||
msgstr "Medya akışı bilgilerini dahil et"
|
||||
|
||||
msgctxt "#30181"
|
||||
msgid "Include plot"
|
||||
msgstr "Konuyu dahil et"
|
||||
|
||||
msgctxt "#30180"
|
||||
msgid "Select User"
|
||||
msgstr "Kullanıcı seç"
|
||||
|
||||
msgctxt "#30169"
|
||||
msgid "Address: "
|
||||
msgstr "Adres:"
|
||||
|
||||
msgctxt "#30167"
|
||||
msgid "Selected Server Address"
|
||||
msgstr "Seçilen Sunucunun Adresi"
|
||||
|
||||
msgctxt "#30166"
|
||||
msgid "Select Server"
|
||||
msgstr "Sunucu seç"
|
||||
|
||||
msgctxt "#30163"
|
||||
msgid "Add (cc) if subtitle is available"
|
||||
msgstr "Altyazı varsa (cc) ekleyin"
|
||||
|
||||
msgctxt "#30139"
|
||||
msgid "No Media Type Set"
|
||||
msgstr "Medya Türü Ayarı Yok"
|
||||
|
||||
msgctxt "#30135"
|
||||
msgid "Error"
|
||||
msgstr "Hata"
|
||||
|
||||
msgctxt "#30126"
|
||||
msgid "Processing Item : "
|
||||
msgstr "Öğenin İşlenmesi:"
|
||||
|
||||
msgctxt "#30125"
|
||||
msgid "Done"
|
||||
msgstr "Tamamlandı"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30121"
|
||||
msgid "On resume"
|
||||
msgstr "Sürdürünce"
|
||||
|
||||
msgctxt "#30120"
|
||||
msgid "Show load progress"
|
||||
msgstr "Yükleme ilerlemesini göster"
|
||||
|
||||
msgctxt "#30118"
|
||||
msgid "Add resume percent to names"
|
||||
msgstr "İsimlere sürdürme yüzdesi ekle"
|
||||
|
||||
msgctxt "#30116"
|
||||
msgid "Add unwatched counts to names"
|
||||
msgstr "İsimlere izlenmeyen sayılarını ekleyin"
|
||||
|
||||
msgctxt "#30114"
|
||||
msgid "Jump back seconds"
|
||||
msgstr "Geri atlama saniyesi"
|
||||
|
||||
msgctxt "#30113"
|
||||
msgid "Retrieving Data"
|
||||
msgstr "Veri Aliniyor"
|
||||
|
||||
msgctxt "#30112"
|
||||
msgid "Loading Content"
|
||||
msgstr "İçerik Yükleniyor"
|
||||
|
||||
msgctxt "#30111"
|
||||
msgid "Services"
|
||||
msgstr "Hizmetler"
|
||||
|
||||
msgctxt "#30110"
|
||||
msgid "Interface"
|
||||
msgstr "Arayüz"
|
||||
|
||||
msgctxt "#30092"
|
||||
msgid "Warning: This action will delete the media files from the server."
|
||||
msgstr "Uyarı: Bu eylem, medya dosyalarını sunucudan siler."
|
||||
|
||||
msgctxt "#30091"
|
||||
msgid "Confirm delete?"
|
||||
msgstr "Silmeyi onayla?"
|
||||
|
||||
msgctxt "#30063"
|
||||
msgid "N/A"
|
||||
msgstr "Yok"
|
||||
|
||||
msgctxt "#30053"
|
||||
msgid "Waiting for server to delete"
|
||||
msgstr "Sunucunun silmesi bekleniyor"
|
||||
|
||||
msgctxt "#30052"
|
||||
msgid "Deleting"
|
||||
msgstr "Siliniyor"
|
||||
|
||||
msgctxt "#30045"
|
||||
msgid "Username not found"
|
||||
msgstr "Kullanıcı adı bulunamadı"
|
||||
|
||||
msgctxt "#30044"
|
||||
msgid "Incorrect Username/Password"
|
||||
msgstr "Yanlış Kullanıcı Adı veya Parola"
|
||||
|
||||
msgctxt "#30027"
|
||||
msgid "Enable debug logging"
|
||||
msgstr "Hata ayıklama günlüğünü etkinleştir"
|
||||
|
||||
msgctxt "#30026"
|
||||
msgid "Widget item select action"
|
||||
msgstr "Pencere ögesi seçme eylemi"
|
||||
|
||||
msgctxt "#30025"
|
||||
msgid "Password:"
|
||||
msgstr "Parola:"
|
||||
|
||||
msgctxt "#30024"
|
||||
msgid "Username:"
|
||||
msgstr "Kullanıcı adı:"
|
||||
|
||||
msgctxt "#30023"
|
||||
msgid "Hide unwatched episode details"
|
||||
msgstr "İzlenmemiş bölümlerin ayrıntılarını gizle"
|
||||
|
||||
msgctxt "#30022"
|
||||
msgid "Advanced"
|
||||
msgstr "Gelişmiş"
|
||||
|
||||
msgctxt "#30021"
|
||||
msgid "Show all episodes item"
|
||||
msgstr "Tüm bölümleri göster"
|
||||
|
||||
msgctxt "#30020"
|
||||
msgid "Flatten single season"
|
||||
msgstr "Tek sezonu düzleştir"
|
||||
|
||||
msgctxt "#30019"
|
||||
msgid "Filtered episode name format"
|
||||
msgstr "Filtrelenmiş bölüm adı biçimi"
|
||||
|
||||
msgctxt "#30018"
|
||||
msgid "Number of items to show in filtered lists"
|
||||
msgstr "Filtrelenmiş listelerde gösterilecek öğe sayısı"
|
||||
|
||||
msgctxt "#30017"
|
||||
msgid "Show connected clients"
|
||||
msgstr "Bağlı istemcileri göster"
|
||||
|
||||
msgctxt "#30016"
|
||||
msgid "Device display name"
|
||||
msgstr "Cihazın görünen adı"
|
||||
|
||||
msgctxt "#30015"
|
||||
msgid "Log timing data"
|
||||
msgstr "Zamanlama verilerini günlüğe kaydet"
|
||||
|
||||
msgctxt "#30014"
|
||||
msgid "Jellyfin"
|
||||
msgstr "Jellyfin"
|
||||
|
||||
msgctxt "#30012"
|
||||
msgid "[Change user]"
|
||||
msgstr "[Kullanıcıyı değiştir]"
|
||||
|
||||
msgctxt "#30011"
|
||||
msgid "[Detect local server]"
|
||||
msgstr "[Yerel sunucuyu algıla]"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30010"
|
||||
msgid "Number of performance profiles to capture"
|
||||
msgstr "Yakalanacak performans profili sayısı"
|
||||
|
||||
msgctxt "#30008"
|
||||
msgid "Samba password"
|
||||
msgstr "Samba parolası"
|
||||
|
||||
msgctxt "#30007"
|
||||
msgid "Samba username"
|
||||
msgstr "Samba kullanıcı adı"
|
||||
|
||||
msgctxt "#30006"
|
||||
msgid "Password"
|
||||
msgstr "Şifre"
|
||||
|
||||
msgctxt "#30005"
|
||||
msgid "Username"
|
||||
msgstr "Kullanıcı adı"
|
||||
|
||||
msgctxt "#30003"
|
||||
msgid "Verify HTTPS certificate"
|
||||
msgstr "HTTPS sertifikasını doğrulayın"
|
||||
|
||||
msgctxt "#30000"
|
||||
msgid "Host"
|
||||
msgstr "Sunucu"
|
||||
|
||||
msgctxt "#30254"
|
||||
msgid "Show add-on settings"
|
||||
msgstr "Eklenti ayarlarını göster"
|
||||
|
||||
msgctxt "#30271"
|
||||
msgid "Mark Unwatched"
|
||||
msgstr "İzlenmedi olarak işaretle"
|
||||
|
||||
msgctxt "#30267"
|
||||
msgid " - In Progress"
|
||||
msgstr "- Devam Eden"
|
||||
|
||||
msgctxt "#30268"
|
||||
msgid " - Recently Added"
|
||||
msgstr "- Son Eklenen"
|
||||
|
||||
msgctxt "#30001"
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
msgctxt "#30239"
|
||||
msgid "Force transcode mpeg2"
|
||||
msgstr "mpeg2 kod dönüştürmeyi zorla"
|
||||
|
||||
msgctxt "#30241"
|
||||
msgid "Force transcode mpeg4"
|
||||
msgstr "mpeg4 kod dönüştürmeyi zorla"
|
||||
|
||||
msgctxt "#30240"
|
||||
msgid "Force transcode msmpeg4v3 (divx)"
|
||||
msgstr "msmpeg4v3 (divx) kod dönüştürmeyi zorla"
|
||||
|
||||
msgctxt "#30246"
|
||||
msgid "Search"
|
||||
msgstr "Ara"
|
||||
|
||||
msgctxt "#30247"
|
||||
msgid "Custom Widget Content"
|
||||
msgstr "Özel Pencere Ögesi İçeriği"
|
||||
|
||||
msgctxt "#30252"
|
||||
msgid "Movies - A-Z"
|
||||
msgstr "Filmler - A-Z"
|
||||
|
||||
msgctxt "#30255"
|
||||
msgid "TV Shows - A-Z"
|
||||
msgstr "Diziler - A-Z"
|
||||
|
||||
msgctxt "#30256"
|
||||
msgid "Movies"
|
||||
msgstr "Filmler"
|
||||
|
||||
msgctxt "#30261"
|
||||
msgid "TV Shows"
|
||||
msgstr "Diziler"
|
||||
|
||||
msgctxt "#30262"
|
||||
msgid "TV Shows - Favorites"
|
||||
msgstr "Diziler - Favoriler"
|
||||
|
||||
msgctxt "#30264"
|
||||
msgid "Episodes - In Progress"
|
||||
msgstr "Bölümler - Devam eden"
|
||||
|
||||
msgctxt "#30265"
|
||||
msgid "Episodes - Next Up"
|
||||
msgstr "Bölümler - Sıradaki"
|
||||
|
||||
msgctxt "#30266"
|
||||
msgid "Movies - Pages"
|
||||
msgstr "Filmler - Sayfalar"
|
||||
|
||||
msgctxt "#30270"
|
||||
msgid "Mark Watched"
|
||||
msgstr "İzlendi olarak işaretle"
|
||||
|
||||
msgctxt "#30269"
|
||||
msgid "Movies - Random"
|
||||
msgstr "Filmler - Rastgele"
|
||||
|
||||
msgctxt "#30272"
|
||||
msgid "Set Favourite"
|
||||
msgstr "Favoriye ekle"
|
||||
|
||||
msgctxt "#30273"
|
||||
msgid "Unset Favourite"
|
||||
msgstr "Favoriden çıkar"
|
||||
|
||||
msgctxt "#30274"
|
||||
msgid "Delete"
|
||||
msgstr "Sil"
|
||||
|
||||
msgctxt "#30276"
|
||||
msgid "Extra Resume Prompt Detected"
|
||||
msgstr "Çift Sürdürme İstemi Algılandı"
|
||||
|
||||
msgctxt "#30225"
|
||||
msgid "Interface Mode"
|
||||
msgstr "Arayüz Modu"
|
||||
|
||||
msgctxt "#30226"
|
||||
msgid "Default"
|
||||
msgstr "Varsayılan"
|
||||
|
||||
msgctxt "#30227"
|
||||
msgid "Simple"
|
||||
msgstr "Basit"
|
||||
|
||||
msgctxt "#30238"
|
||||
msgid "Playback stream options"
|
||||
msgstr "Oynatma akış seçenekleri"
|
||||
|
||||
msgctxt "#30250"
|
||||
msgid "Unknown"
|
||||
msgstr "Bilinmeyen"
|
||||
|
||||
msgctxt "#30251"
|
||||
msgid "Movies - Genres"
|
||||
msgstr "Filmler - Türler"
|
||||
|
||||
msgctxt "#30257"
|
||||
msgid "Movies - Recently Added"
|
||||
msgstr "Filmler - Son Eklenen"
|
||||
|
||||
msgctxt "#30258"
|
||||
msgid "Movies - In Progress"
|
||||
msgstr "Filmler - Devam eden"
|
||||
|
||||
msgctxt "#30259"
|
||||
msgid "Movies - Favorites"
|
||||
msgstr "Filmler - Favoriler"
|
||||
|
||||
msgctxt "#30263"
|
||||
msgid "Episodes - Recently Added"
|
||||
msgstr "Bölümler - Son Eklenen"
|
||||
|
||||
msgctxt "#30275"
|
||||
msgid "Force Transcode"
|
||||
msgstr "Kod Dönüştürmeye Zorla"
|
||||
|
||||
msgctxt "#30354"
|
||||
msgid "Go To Series"
|
||||
msgstr "Dizilere Git"
|
||||
|
||||
msgctxt "#30443"
|
||||
msgid "Quick Connect"
|
||||
msgstr "Hızlı Bağlan"
|
||||
|
||||
msgctxt "#30398"
|
||||
msgid "Refresh Jellyfin Metadata"
|
||||
msgstr "Jellyfin Meta Verisini Yenile"
|
||||
|
||||
msgctxt "#30444"
|
||||
msgid "Login using Quick Connect"
|
||||
msgstr "Hızlı Bağlan'ı kullanarak oturum aç"
|
||||
|
||||
msgctxt "#30365"
|
||||
msgid "Manual Login"
|
||||
msgstr "El İle Oturum Aç"
|
||||
|
||||
msgctxt "#30419"
|
||||
msgid "Audio codec"
|
||||
msgstr "Ses codec bileşeni"
|
||||
|
||||
msgctxt "#30291"
|
||||
msgid "Select Audio Stream"
|
||||
msgstr "Ses Akışını Seçin"
|
||||
|
||||
msgctxt "#30292"
|
||||
msgid "Select Subtitle Stream"
|
||||
msgstr "Altyazı Akışını Seçin"
|
||||
|
||||
msgctxt "#30348"
|
||||
msgid "Add user ratings"
|
||||
msgstr "Kullanıcı puanı ekleyin"
|
||||
|
||||
msgctxt "#30311"
|
||||
msgid "Library - "
|
||||
msgstr "Kütüphane -"
|
||||
|
||||
msgctxt "#30418"
|
||||
msgid "Audio bitrate (Kbits)"
|
||||
msgstr "Ses bit hızı (Kbps)"
|
||||
|
||||
msgctxt "#30289"
|
||||
msgid "TV Shows - Genres"
|
||||
msgstr "Diziler - Türler"
|
||||
|
||||
msgctxt "#30325"
|
||||
msgid " - Genres"
|
||||
msgstr "- Türler"
|
||||
|
||||
msgctxt "#30279"
|
||||
msgid "TV Shows - Unwatched"
|
||||
msgstr "Diziler - İzlenmemiş"
|
||||
|
||||
msgctxt "#30350"
|
||||
msgid "Music - Recently Added"
|
||||
msgstr "Müzik - Son Eklenen"
|
||||
|
||||
msgctxt "#30445"
|
||||
msgid "Continue Watching"
|
||||
msgstr "İzlemeye Devam Et"
|
||||
|
||||
msgctxt "#30450"
|
||||
msgid "Next Up Rewatching"
|
||||
msgstr "Sıradaki Bölümü Tekrar İzle"
|
||||
|
||||
msgctxt "#30447"
|
||||
msgid "Max Play Queue Size"
|
||||
msgstr "Maksimum Oynatma Kuyruğu Boyutu"
|
||||
|
||||
msgctxt "#30449"
|
||||
msgid "Instant Mix"
|
||||
msgstr "Anlık Mix"
|
||||
|
||||
msgctxt "#30277"
|
||||
msgid "JellyCon needs to prompt for resume on partily played items, Kodi can also prompt, this can cause a double prompt. Do you want to remove the double prompt?"
|
||||
msgstr ""
|
||||
"JellyCon'un kısmen oynatılan ögelerde sürdürmeyi istemesi gerekir. Bunu Kodi "
|
||||
"de isteyebilir ve bu çift isteme neden olabilir. Çift istemi kaldırmak "
|
||||
"istiyor musunuz?"
|
||||
|
||||
msgctxt "#30286"
|
||||
msgid "Movies - Unwatched"
|
||||
msgstr "Filmler - İzlenmemiş"
|
||||
|
||||
msgctxt "#30287"
|
||||
msgid "TV Shows - Latest"
|
||||
msgstr "Diziler - En Son"
|
||||
|
||||
msgctxt "#30322"
|
||||
msgid "Auto resume"
|
||||
msgstr "Otomatik sürdür"
|
||||
|
||||
msgctxt "#30351"
|
||||
msgid "Music - Recently Played"
|
||||
msgstr "Müzik - Son Çalınan"
|
||||
|
||||
msgctxt "#30432"
|
||||
msgid "Hide watched items in lists"
|
||||
msgstr "Listelerdeki izlenmiş içerikleri gizle"
|
||||
|
||||
msgctxt "#30242"
|
||||
msgid "Force transcode av1"
|
||||
msgstr "av1 kod dönüştürmeyi zorla"
|
||||
|
||||
msgctxt "#30428"
|
||||
msgid "Rating"
|
||||
msgstr "Puan"
|
||||
|
||||
msgctxt "#30309"
|
||||
msgid "Select Media Source"
|
||||
msgstr "Medya Kaynağını Seçin"
|
||||
|
||||
msgctxt "#30278"
|
||||
msgid " - Next Up"
|
||||
msgstr "- Sıradaki Bölümler"
|
||||
|
||||
msgctxt "#30285"
|
||||
msgid " - Unwatched"
|
||||
msgstr "- İzlenmemiş"
|
||||
|
||||
msgctxt "#30349"
|
||||
msgid " - Recently Played"
|
||||
msgstr "- Son Oynatılan"
|
||||
|
||||
msgctxt "#30288"
|
||||
msgid " - Latest"
|
||||
msgstr "- Sonuncu"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30260"
|
||||
msgid "BoxSets"
|
||||
msgstr "Kutu Setleri"
|
||||
|
||||
msgctxt "#30283"
|
||||
msgid "Play Next Episode?"
|
||||
msgstr "Sonraki Bölüm Oynatılsın mı?"
|
||||
|
||||
msgctxt "#30305"
|
||||
msgid "Not Found"
|
||||
msgstr "Bulunamadı"
|
||||
|
||||
msgctxt "#30315"
|
||||
msgid "Suppress notifications for connection errors"
|
||||
msgstr "Bağlantı hatalarına ilişkin bildirimleri bastır"
|
||||
|
||||
msgctxt "#30317"
|
||||
msgid "Play All"
|
||||
msgstr "Hepsini Oynat"
|
||||
|
||||
msgctxt "#30280"
|
||||
msgid "Missing Title"
|
||||
msgstr "Eksik Başlık"
|
||||
|
||||
msgctxt "#30294"
|
||||
msgid "Notice"
|
||||
msgstr "Uyarı"
|
||||
|
||||
msgctxt "#30295"
|
||||
msgid "To use this feature you need HTTP control enabled"
|
||||
msgstr ""
|
||||
"Bu özelliği kullanmak için HTTP kontrolünün etkinleştirilmiş olması gerekir"
|
||||
|
||||
msgctxt "#30296"
|
||||
msgid "Delete"
|
||||
msgstr "Sil"
|
||||
|
||||
msgctxt "#30302"
|
||||
msgid "Existing images : "
|
||||
msgstr "Mevcut resimler:"
|
||||
|
||||
msgctxt "#30303"
|
||||
msgid "Missing Jellyfin images : "
|
||||
msgstr "Eksik Jellyfin görselleri:"
|
||||
|
||||
msgctxt "#30306"
|
||||
msgid "Playback starting"
|
||||
msgstr "Oynatma başlatılıyor"
|
||||
|
||||
msgctxt "#30307"
|
||||
msgid "Play Trailer"
|
||||
msgstr "Fragmanı Oynat"
|
||||
|
||||
msgctxt "#30308"
|
||||
msgid "Select Trailer"
|
||||
msgstr "Fragman Seç"
|
||||
|
||||
msgctxt "#30310"
|
||||
msgid "Enable Jellyfin remote control"
|
||||
msgstr "Jellyfin uzaktan kumandasını etkinleştir"
|
||||
|
||||
msgctxt "#30312"
|
||||
msgid "All - "
|
||||
msgstr "Hepsi -"
|
||||
|
||||
msgctxt "#30313"
|
||||
msgid "Menu"
|
||||
msgstr "Menü"
|
||||
|
||||
msgctxt "#30314"
|
||||
msgid "Play"
|
||||
msgstr "Oynat"
|
||||
|
||||
msgctxt "#30316"
|
||||
msgid "Connection Error"
|
||||
msgstr "Bağlantı Hatası"
|
||||
|
||||
msgctxt "#30318"
|
||||
msgid "Music - Albums"
|
||||
msgstr "Müzik - Albümler"
|
||||
|
||||
msgctxt "#30282"
|
||||
msgid "No Jellyfin servers detected on your local network."
|
||||
msgstr "Yerel ağınızda Jellyfin sunucusu algılanmadı."
|
||||
|
||||
msgctxt "#30290"
|
||||
msgid "All"
|
||||
msgstr "Hepsi"
|
||||
|
||||
msgctxt "#30281"
|
||||
msgid "Refresh Cached Images"
|
||||
msgstr "Önbelleğe Alınmış Görüntüleri Yenile"
|
||||
|
||||
msgctxt "#30293"
|
||||
msgid "Cache images"
|
||||
msgstr "Resimleri önbelleğe al"
|
||||
|
||||
msgctxt "#30297"
|
||||
msgid "Delete unused images?"
|
||||
msgstr "Kullanılmayan görseller silinsin mi?"
|
||||
|
||||
msgctxt "#30298"
|
||||
msgid "Deleting Kodi Images"
|
||||
msgstr "Kodi Görüntülerini Silme"
|
||||
|
||||
msgctxt "#30299"
|
||||
msgid "Cache Images"
|
||||
msgstr "Görüntüleri Önbelleğe Al"
|
||||
|
||||
msgctxt "#30300"
|
||||
msgid "Cache all Jellyfin images as local Kodi images?"
|
||||
msgstr ""
|
||||
"Tüm Jellyfin görselleri yerel Kodi görselleri olarak önbelleğe alınsın mı?"
|
||||
|
||||
msgctxt "#30301"
|
||||
msgid "Caching Images"
|
||||
msgstr "Görüntüleri Önbelleğe Alma"
|
||||
|
||||
msgctxt "#30304"
|
||||
msgid "Cached Jellyfin images : "
|
||||
msgstr "Önbelleğe alınmış Jellyfin görüntüleri:"
|
||||
|
||||
msgctxt "#30406"
|
||||
msgid "Jellyfin Libraries"
|
||||
msgstr "Jellyfin Kütüphaneleri"
|
||||
|
||||
msgctxt "#30410"
|
||||
msgid " - Collections"
|
||||
msgstr "- Koleksiyonlar"
|
||||
|
||||
msgctxt "#30414"
|
||||
msgid " - Favorites"
|
||||
msgstr "- Favoriler"
|
||||
|
||||
msgctxt "#30415"
|
||||
msgid " - Favorite Collections"
|
||||
msgstr "- Favori Koleksiyonlar"
|
||||
|
||||
msgctxt "#30328"
|
||||
msgid "Show empty folders (shows, seasons, collections)"
|
||||
msgstr "Boş klasörleri göster (diziler, sezonlar, koleksiyonlar)"
|
||||
|
||||
msgctxt "#30340"
|
||||
msgid "Group movies into collections"
|
||||
msgstr "Filmleri koleksiyonlar halinde grupla"
|
||||
|
||||
msgctxt "#30437"
|
||||
msgid "Playback options"
|
||||
msgstr "Oynatma seçenekleri"
|
||||
|
||||
msgctxt "#30453"
|
||||
msgid "Hide number of items to show on entry title"
|
||||
msgstr "Giriş başlığında gösterilecek öge sayısını gizle"
|
||||
|
||||
msgctxt "#30441"
|
||||
msgid "Use cached widget data"
|
||||
msgstr "Önbelleğe alınmış pencere ögesi verilerini kullan"
|
||||
|
||||
msgctxt "#30408"
|
||||
msgid "Custom Widgets"
|
||||
msgstr "Özel Pencere Ögesi"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,15 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2021-11-17 02:05+0000\n"
|
||||
"Last-Translator: wolong gl <wolong98@gmail.com>\n"
|
||||
"Language-Team: Chinese (Simplified) <https://translate.jellyfin.org/projects/"
|
||||
"jellycon/jellycon/zh_Hans/>\n"
|
||||
"PO-Revision-Date: 2024-11-01 16:41+0000\n"
|
||||
"Last-Translator: 無情天 <kofzhanganguo@126.com>\n"
|
||||
"Language-Team: Chinese (Simplified Han script) <https://translate.jellyfin."
|
||||
"org/projects/jellycon/jellycon/zh_Hans/>\n"
|
||||
"Language: zh_Hans\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"X-Generator: Weblate 4.5.2\n"
|
||||
"X-Generator: Weblate 5.7.2\n"
|
||||
|
||||
msgctxt "#30442"
|
||||
msgid "Simple new content check"
|
||||
@@ -45,7 +45,7 @@ msgstr "连接速度测试"
|
||||
|
||||
msgctxt "#30434"
|
||||
msgid "Force transcode stream bitrate (Kbits)"
|
||||
msgstr "强制转码流比特率 (Kbits)"
|
||||
msgstr "强制转码流比特率 (Kbps)"
|
||||
|
||||
msgctxt "#30433"
|
||||
msgid "Allow direct file playback"
|
||||
@@ -109,7 +109,7 @@ msgstr "音频编码"
|
||||
|
||||
msgctxt "#30418"
|
||||
msgid "Audio bitrate (Kbits)"
|
||||
msgstr "音频比特率 (Kbits)"
|
||||
msgstr "音频比特率 (Kbps)"
|
||||
|
||||
msgctxt "#30417"
|
||||
msgid "You do not have permision to delete this item"
|
||||
@@ -857,7 +857,7 @@ msgstr "文件直接路径"
|
||||
|
||||
msgctxt "#30208"
|
||||
msgid "Max stream bitrate (Kbits)"
|
||||
msgstr "最大流比特率 (Kbits)"
|
||||
msgstr "最大流比特率 (Kbps)"
|
||||
|
||||
msgctxt "#30207"
|
||||
msgid "Playback"
|
||||
@@ -1013,7 +1013,7 @@ msgstr "高级"
|
||||
|
||||
msgctxt "#30021"
|
||||
msgid "Show all episodes item"
|
||||
msgstr "显示所有剧集项目"
|
||||
msgstr "显示所有剧集"
|
||||
|
||||
msgctxt "#30020"
|
||||
msgid "Flatten single season"
|
||||
@@ -1082,3 +1082,75 @@ msgstr "端口"
|
||||
msgctxt "#30000"
|
||||
msgid "Host"
|
||||
msgstr "主机"
|
||||
|
||||
msgctxt "#30444"
|
||||
msgid "Login using Quick Connect"
|
||||
msgstr "使用 Quick Connect 登录"
|
||||
|
||||
msgctxt "#30443"
|
||||
msgid "Quick Connect"
|
||||
msgstr "Quick Connect"
|
||||
|
||||
msgctxt "#30323"
|
||||
msgid "Artists"
|
||||
msgstr "艺术家"
|
||||
|
||||
msgctxt "#30445"
|
||||
msgid "Continue Watching"
|
||||
msgstr "继续观看"
|
||||
|
||||
msgctxt "#30439"
|
||||
msgid "Show play next episode at time left in seconds"
|
||||
msgstr "显示播放下一集的剩余时间(s)"
|
||||
|
||||
msgctxt "#30446"
|
||||
msgid "There was an error logging in"
|
||||
msgstr "登录时出错"
|
||||
|
||||
msgctxt "#30448"
|
||||
msgid "Shuffle"
|
||||
msgstr "随机"
|
||||
|
||||
msgctxt "#30449"
|
||||
msgid "Instant Mix"
|
||||
msgstr "速成合辑"
|
||||
|
||||
msgctxt "#30447"
|
||||
msgid "Max Play Queue Size"
|
||||
msgstr "最大播放队列数"
|
||||
|
||||
msgctxt "#30225"
|
||||
msgid "Interface Mode"
|
||||
msgstr "接口模式"
|
||||
|
||||
msgctxt "#30226"
|
||||
msgid "Default"
|
||||
msgstr "默认值"
|
||||
|
||||
msgctxt "#30227"
|
||||
msgid "Simple"
|
||||
msgstr "简单"
|
||||
|
||||
msgctxt "#30242"
|
||||
msgid "Force transcode av1"
|
||||
msgstr "强制转码为 AV1 格式"
|
||||
|
||||
msgctxt "#30452"
|
||||
msgid "Combine instead of replace (might cause slow-down)"
|
||||
msgstr "合并而非替换(可能会导致速度减慢)"
|
||||
|
||||
msgctxt "#30451"
|
||||
msgid "Rewatch Days (0 = Disabled)"
|
||||
msgstr "重看天数(0=已禁用)"
|
||||
|
||||
msgctxt "#30450"
|
||||
msgid "Next Up Rewatching"
|
||||
msgstr "下一个重看"
|
||||
|
||||
msgctxt "#30453"
|
||||
msgid "Hide number of items to show on entry title"
|
||||
msgstr "隐藏条目标题上显示的项目数"
|
||||
|
||||
msgctxt "#30454"
|
||||
msgid " - Totally Unwatched"
|
||||
msgstr " - 完全未观看"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import time
|
||||
import threading
|
||||
@@ -7,7 +8,7 @@ import threading
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
|
||||
from .loghandler import LazyLogger
|
||||
from .lazylogger import LazyLogger
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
|
||||
from .loghandler import LazyLogger
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
|
||||
class BitrateDialog(xbmcgui.WindowXMLDialog):
|
||||
|
||||
slider_control = None
|
||||
bitrate_label = None
|
||||
initial_bitrate_value = 0
|
||||
selected_transcode_value = 0
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
log.debug("BitrateDialog: __init__")
|
||||
xbmcgui.WindowXML.__init__(self, *args, **kwargs)
|
||||
|
||||
def onInit(self):
|
||||
log.debug("ActionMenu: onInit")
|
||||
self.action_exitkeys_id = [10, 13]
|
||||
|
||||
self.slider_control = self.getControl(3000)
|
||||
self.slider_control.setInt(self.initial_bitrate_value, 400, 100, 15000)
|
||||
|
||||
self.bitrate_label = self.getControl(3030)
|
||||
bitrate_label_string = str(self.slider_control.getInt()) + " Kbs"
|
||||
self.bitrate_label.setLabel(bitrate_label_string)
|
||||
|
||||
def onFocus(self, control_id):
|
||||
pass
|
||||
|
||||
def doAction(self, action_id):
|
||||
pass
|
||||
|
||||
def onMessage(self, message):
|
||||
log.debug("ActionMenu: onMessage: {0}".format(message))
|
||||
|
||||
def onAction(self, action):
|
||||
|
||||
bitrate_label_string = str(self.slider_control.getInt()) + " Kbs"
|
||||
self.bitrate_label.setLabel(bitrate_label_string)
|
||||
|
||||
if action.getId() == 10: # ACTION_PREVIOUS_MENU
|
||||
self.close()
|
||||
elif action.getId() == 92: # ACTION_NAV_BACK
|
||||
self.close()
|
||||
elif action.getId() == 7: # ENTER
|
||||
self.selected_transcode_value = self.slider_control.getInt()
|
||||
self.close()
|
||||
|
||||
def onClick(self, control_id):
|
||||
if control_id == 3000:
|
||||
log.debug("ActionMenu: Selected Item: {0}".format(control_id))
|
||||
@@ -1,9 +1,7 @@
|
||||
# coding=utf-8
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
from six.moves.urllib.parse import unquote
|
||||
import requests
|
||||
import base64
|
||||
import sys
|
||||
import threading
|
||||
@@ -13,16 +11,16 @@ import xbmcgui
|
||||
import xbmcplugin
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
import requests
|
||||
from six.moves.urllib.parse import unquote
|
||||
|
||||
from .downloadutils import DownloadUtils
|
||||
from .loghandler import LazyLogger
|
||||
from .jellyfin import api
|
||||
from .lazylogger import LazyLogger
|
||||
from .jsonrpc import JsonRpc, get_value
|
||||
from .translation import string_load
|
||||
from .datamanager import DataManager
|
||||
from .utils import get_art
|
||||
from .utils import translate_string, load_user_details
|
||||
from .kodi_utils import HomeWindow
|
||||
from .item_functions import get_art
|
||||
|
||||
downloadUtils = DownloadUtils()
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
|
||||
@@ -70,8 +68,8 @@ class CacheArtwork(threading.Thread):
|
||||
log.debug("cache_delete_for_links")
|
||||
|
||||
progress = xbmcgui.DialogProgress()
|
||||
progress.create(string_load(30281))
|
||||
progress.update(30, string_load(30347))
|
||||
progress.create(translate_string(30281))
|
||||
progress.update(30, translate_string(30347))
|
||||
|
||||
item_image_url_part = "Items/%s/Images/" % item_id
|
||||
item_image_url_part = item_image_url_part.replace("/", "%2f")
|
||||
@@ -82,7 +80,7 @@ class CacheArtwork(threading.Thread):
|
||||
result = JsonRpc('Settings.GetSettingValue').execute(web_query)
|
||||
xbmc_webserver_enabled = result['result']['value']
|
||||
if not xbmc_webserver_enabled:
|
||||
xbmcgui.Dialog().ok(string_load(30294), string_load(30295))
|
||||
xbmcgui.Dialog().ok(translate_string(30294), translate_string(30295))
|
||||
return
|
||||
|
||||
params = {"properties": ["url"]}
|
||||
@@ -90,7 +88,7 @@ class CacheArtwork(threading.Thread):
|
||||
textures = json_result.get("result", {}).get("textures", [])
|
||||
log.debug("texture ids: {0}".format(textures))
|
||||
|
||||
progress.update(70, string_load(30346))
|
||||
progress.update(70, translate_string(30346))
|
||||
|
||||
delete_count = 0
|
||||
for texture in textures:
|
||||
@@ -104,10 +102,10 @@ class CacheArtwork(threading.Thread):
|
||||
|
||||
del textures
|
||||
|
||||
progress.update(100, string_load(30125))
|
||||
progress.update(100, translate_string(30125))
|
||||
progress.close()
|
||||
|
||||
xbmcgui.Dialog().ok(string_load(30281), '{}: {}'.format(string_load(30344), delete_count))
|
||||
xbmcgui.Dialog().ok(translate_string(30281), '{}: {}'.format(translate_string(30344), delete_count))
|
||||
|
||||
def cache_artwork_interactive(self):
|
||||
log.debug("cache_artwork_interactive")
|
||||
@@ -119,21 +117,21 @@ class CacheArtwork(threading.Thread):
|
||||
result = JsonRpc('Settings.GetSettingValue').execute(web_query)
|
||||
xbmc_webserver_enabled = result['result']['value']
|
||||
if not xbmc_webserver_enabled:
|
||||
xbmcgui.Dialog().ok(string_load(30294), '{} - {}'.format(string_load(30295), string_load(30355)))
|
||||
xbmcgui.Dialog().ok(translate_string(30294), '{} - {}'.format(translate_string(30295), translate_string(30355)))
|
||||
xbmc.executebuiltin('ActivateWindow(servicesettings)')
|
||||
return
|
||||
|
||||
result_report = []
|
||||
|
||||
# ask questions
|
||||
question_delete_unused = xbmcgui.Dialog().yesno(string_load(30296), string_load(30297))
|
||||
question_cache_images = xbmcgui.Dialog().yesno(string_load(30299), string_load(30300))
|
||||
question_delete_unused = xbmcgui.Dialog().yesno(translate_string(30296), translate_string(30297))
|
||||
question_cache_images = xbmcgui.Dialog().yesno(translate_string(30299), translate_string(30300))
|
||||
|
||||
delete_canceled = False
|
||||
# now do work - delete unused
|
||||
if question_delete_unused:
|
||||
delete_pdialog = xbmcgui.DialogProgress()
|
||||
delete_pdialog.create(string_load(30298), "")
|
||||
delete_pdialog.create(translate_string(30298), "")
|
||||
index = 0
|
||||
|
||||
params = {"properties": ["url"]}
|
||||
@@ -171,9 +169,9 @@ class CacheArtwork(threading.Thread):
|
||||
delete_canceled = True
|
||||
break
|
||||
|
||||
result_report.append(string_load(30385) + str(len(textures)))
|
||||
result_report.append(string_load(30386) + str(len(unused_texture_ids)))
|
||||
result_report.append(string_load(30387) + str(index))
|
||||
result_report.append(translate_string(30385) + str(len(textures)))
|
||||
result_report.append(translate_string(30386) + str(len(unused_texture_ids)))
|
||||
result_report.append(translate_string(30387) + str(index))
|
||||
|
||||
del textures
|
||||
del jellyfin_texture_urls
|
||||
@@ -187,7 +185,7 @@ class CacheArtwork(threading.Thread):
|
||||
# now do work - cache images
|
||||
if question_cache_images:
|
||||
cache_pdialog = xbmcgui.DialogProgress()
|
||||
cache_pdialog.create(string_load(30301), "")
|
||||
cache_pdialog.create(translate_string(30301), "")
|
||||
cache_report = self.cache_artwork(cache_pdialog)
|
||||
cache_pdialog.close()
|
||||
del cache_pdialog
|
||||
@@ -196,12 +194,12 @@ class CacheArtwork(threading.Thread):
|
||||
|
||||
if len(result_report) > 0:
|
||||
msg = "\r\n".join(result_report)
|
||||
xbmcgui.Dialog().textviewer(string_load(30125), msg, usemono=True)
|
||||
xbmcgui.Dialog().textviewer(translate_string(30125), msg, usemono=True)
|
||||
|
||||
def cache_artwork_background(self):
|
||||
log.debug("cache_artwork_background")
|
||||
dp = xbmcgui.DialogProgressBG()
|
||||
dp.create(string_load(30301), "")
|
||||
dp.create(translate_string(30301), "")
|
||||
result_text = None
|
||||
try:
|
||||
result_text = self.cache_artwork(dp)
|
||||
@@ -210,13 +208,15 @@ class CacheArtwork(threading.Thread):
|
||||
dp.close()
|
||||
del dp
|
||||
if result_text is not None:
|
||||
log.debug("Cache Images reuslt : {0}".format(" - ".join(result_text)))
|
||||
log.debug("Cache Images result : {0}".format(" - ".join(result_text)))
|
||||
|
||||
def get_jellyfin_artwork(self, progress):
|
||||
log.debug("get_jellyfin_artwork")
|
||||
user_details = load_user_details()
|
||||
user_id = user_details.get('user_id')
|
||||
|
||||
url = ""
|
||||
url += "{server}/Users/{userid}/Items"
|
||||
url += "/Users/{}/Items".format(user_id)
|
||||
url += "?Recursive=true"
|
||||
url += "&EnableUserData=False"
|
||||
url += "&Fields=BasicSyncInfo"
|
||||
@@ -224,21 +224,21 @@ class CacheArtwork(threading.Thread):
|
||||
url += "&ImageTypeLimit=1"
|
||||
url += "&format=json"
|
||||
|
||||
data_manager = DataManager()
|
||||
results = data_manager.get_content(url)
|
||||
results = api.get(url)
|
||||
if results is None:
|
||||
results = []
|
||||
|
||||
if isinstance(results, dict):
|
||||
results = results.get("Items")
|
||||
|
||||
server = downloadUtils.get_server()
|
||||
settings = xbmcaddon.Addon()
|
||||
server = settings.getSetting('server_address')
|
||||
log.debug("Jellyfin Item Count Count: {0}".format(len(results)))
|
||||
|
||||
if self.stop_all_activity:
|
||||
return None
|
||||
|
||||
progress.update(0, string_load(30359))
|
||||
progress.update(0, translate_string(30359))
|
||||
|
||||
texture_urls = set()
|
||||
|
||||
@@ -268,7 +268,7 @@ class CacheArtwork(threading.Thread):
|
||||
# get the password
|
||||
xbmc_password = get_value("services.webserverpassword")
|
||||
|
||||
progress.update(0, string_load(30356))
|
||||
progress.update(0, translate_string(30356))
|
||||
|
||||
params = {"properties": ["url"]}
|
||||
json_result = JsonRpc('Textures.GetTextures').execute(params)
|
||||
@@ -278,7 +278,7 @@ class CacheArtwork(threading.Thread):
|
||||
if self.stop_all_activity:
|
||||
return
|
||||
|
||||
progress.update(0, string_load(30357))
|
||||
progress.update(0, translate_string(30357))
|
||||
|
||||
texture_urls = set()
|
||||
for texture in textures:
|
||||
@@ -296,7 +296,7 @@ class CacheArtwork(threading.Thread):
|
||||
if self.stop_all_activity:
|
||||
return
|
||||
|
||||
progress.update(0, string_load(30358))
|
||||
progress.update(0, translate_string(30358))
|
||||
|
||||
jellyfin_texture_urls = self.get_jellyfin_artwork(progress)
|
||||
if jellyfin_texture_urls is None:
|
||||
@@ -347,7 +347,7 @@ class CacheArtwork(threading.Thread):
|
||||
break
|
||||
|
||||
result_report = []
|
||||
result_report.append(string_load(30302) + str(len(texture_urls)))
|
||||
result_report.append(string_load(30303) + str(len(missing_texture_urls)))
|
||||
result_report.append(string_load(30304) + str(count_done))
|
||||
result_report.append(translate_string(30302) + str(len(texture_urls)))
|
||||
result_report.append(translate_string(30303) + str(len(missing_texture_urls)))
|
||||
result_report.append(translate_string(30304) + str(count_done))
|
||||
return result_report
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
from uuid import uuid4
|
||||
from kodi_six.utils import py2_decode
|
||||
import xbmcaddon
|
||||
import xbmc
|
||||
import xbmcvfs
|
||||
|
||||
from .kodi_utils import HomeWindow
|
||||
from .loghandler import LazyLogger
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
|
||||
class ClientInformation:
|
||||
|
||||
@staticmethod
|
||||
def get_device_id():
|
||||
|
||||
window = HomeWindow()
|
||||
client_id = window.get_property("client_id")
|
||||
|
||||
if client_id:
|
||||
return client_id
|
||||
|
||||
jellyfin_guid_path = py2_decode(xbmc.translatePath("special://temp/jellycon_guid"))
|
||||
log.debug("jellyfin_guid_path: {0}".format(jellyfin_guid_path))
|
||||
guid = xbmcvfs.File(jellyfin_guid_path)
|
||||
client_id = guid.read()
|
||||
guid.close()
|
||||
|
||||
if not client_id:
|
||||
# Needs to be captilized for backwards compat
|
||||
client_id = uuid4().hex.upper()
|
||||
log.debug("Generating a new guid: {0}".format(client_id))
|
||||
guid = xbmcvfs.File(jellyfin_guid_path, 'w')
|
||||
guid.write(client_id)
|
||||
guid.close()
|
||||
log.debug("jellyfin_client_id (NEW): {0}".format(client_id))
|
||||
else:
|
||||
log.debug("jellyfin_client_id: {0}".format(client_id))
|
||||
|
||||
window.set_property("client_id", client_id)
|
||||
return client_id
|
||||
|
||||
@staticmethod
|
||||
def get_version():
|
||||
addon = xbmcaddon.Addon()
|
||||
version = addon.getAddonInfo("version")
|
||||
return version
|
||||
|
||||
@staticmethod
|
||||
def get_client():
|
||||
return 'Kodi JellyCon'
|
||||
@@ -1,41 +0,0 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
import threading
|
||||
import xbmc
|
||||
|
||||
from .loghandler import LazyLogger
|
||||
from resources.lib.functions import show_menu
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
|
||||
class ContextMonitor(threading.Thread):
|
||||
|
||||
stop_thread = False
|
||||
|
||||
def run(self):
|
||||
|
||||
item_id = None
|
||||
log.debug("ContextMonitor Thread Started")
|
||||
|
||||
while not xbmc.Monitor().abortRequested() and not self.stop_thread:
|
||||
|
||||
if xbmc.getCondVisibility("Window.IsActive(fullscreenvideo) | Window.IsActive(visualisation)"):
|
||||
xbmc.sleep(1000)
|
||||
else:
|
||||
if xbmc.getCondVisibility("Window.IsVisible(contextmenu)"):
|
||||
if item_id:
|
||||
xbmc.executebuiltin("Dialog.Close(contextmenu,true)")
|
||||
params = {}
|
||||
params["item_id"] = item_id
|
||||
show_menu(params)
|
||||
|
||||
container_id = xbmc.getInfoLabel("System.CurrentControlID")
|
||||
item_id = xbmc.getInfoLabel("Container(" + str(container_id) + ").ListItem.Property(id)")
|
||||
|
||||
xbmc.sleep(100)
|
||||
|
||||
log.debug("ContextMonitor Thread Exited")
|
||||
|
||||
def stop_monitor(self):
|
||||
log.debug("ContextMonitor Stop Called")
|
||||
self.stop_thread = True
|
||||
@@ -1,25 +1,25 @@
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
from collections import defaultdict
|
||||
import threading
|
||||
import hashlib
|
||||
import os
|
||||
import time
|
||||
from six.moves import cPickle
|
||||
|
||||
from .downloadutils import DownloadUtils
|
||||
from .loghandler import LazyLogger
|
||||
from .item_functions import extract_item_info
|
||||
from .kodi_utils import HomeWindow
|
||||
from .translation import string_load
|
||||
from .tracking import timer
|
||||
from .filelock import FileLock
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
import xbmcvfs
|
||||
import xbmcgui
|
||||
from six.moves import cPickle
|
||||
|
||||
from .jellyfin import api
|
||||
from .lazylogger import LazyLogger
|
||||
from .item_functions import extract_item_info
|
||||
from .kodi_utils import HomeWindow
|
||||
from .tracking import timer
|
||||
from .filelock import FileLock
|
||||
from .utils import translate_string, load_user_details, translate_path
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
@@ -40,15 +40,12 @@ class CacheItem:
|
||||
|
||||
class DataManager:
|
||||
|
||||
addon_dir = xbmc.translatePath(xbmcaddon.Addon().getAddonInfo('profile'))
|
||||
addon_dir = translate_path(xbmcaddon.Addon().getAddonInfo('profile'))
|
||||
|
||||
def __init__(self, *args):
|
||||
# log.debug("DataManager __init__")
|
||||
pass
|
||||
self.user_details = load_user_details()
|
||||
|
||||
@timer
|
||||
def get_content(self, url):
|
||||
return DownloadUtils().download_url(url)
|
||||
self.api = api
|
||||
|
||||
@timer
|
||||
def get_items(self, url, gui_options, use_cache=False):
|
||||
@@ -57,19 +54,14 @@ class DataManager:
|
||||
log.debug("last_content_url : use_cache={0} url={1}".format(use_cache, url))
|
||||
home_window.set_property("last_content_url", url)
|
||||
|
||||
download_utils = DownloadUtils()
|
||||
user_id = download_utils.get_user_id()
|
||||
server = download_utils.get_server()
|
||||
user_id = self.user_details.get('user_id')
|
||||
server = self.api.server
|
||||
|
||||
m = hashlib.md5()
|
||||
m.update('{}|{}|{}'.format(user_id, server, url).encode())
|
||||
url_hash = m.hexdigest()
|
||||
cache_file = os.path.join(self.addon_dir, "cache_" + url_hash + ".pickle")
|
||||
|
||||
# changed_url = url + "&MinDateLastSavedForUser=" + urllib.unquote("2019-09-16T13:45:30")
|
||||
# results = self.GetContent(changed_url)
|
||||
# log.debug("DataManager Changes Since Date : {0}", results)
|
||||
|
||||
item_list = None
|
||||
total_records = 0
|
||||
baseline_name = None
|
||||
@@ -103,7 +95,7 @@ class DataManager:
|
||||
if item_list is None or len(item_list) == 0:
|
||||
log.debug("Loading url data from server")
|
||||
|
||||
results = self.get_content(url)
|
||||
results = self.api.get(url)
|
||||
|
||||
if results is None:
|
||||
results = []
|
||||
@@ -135,7 +127,6 @@ class DataManager:
|
||||
cache_item.total_records = total_records
|
||||
|
||||
cache_thread.cached_item = cache_item
|
||||
# copy.deepcopy(item_list)
|
||||
|
||||
if not use_cache:
|
||||
cache_thread = None
|
||||
@@ -171,7 +162,6 @@ class CacheManagerThread(threading.Thread):
|
||||
def run(self):
|
||||
|
||||
log.debug("CacheManagerThread : Started")
|
||||
# log.debug("CacheManagerThread : Cache Item : {0}", self.cached_item.__dict__)
|
||||
|
||||
home_window = HomeWindow()
|
||||
is_fresh = False
|
||||
@@ -203,7 +193,7 @@ class CacheManagerThread(threading.Thread):
|
||||
log.debug("CacheManagerThread : Cache Hash : {0}".format(cached_hash))
|
||||
|
||||
data_manager = DataManager()
|
||||
results = data_manager.get_content(self.cached_item.items_url)
|
||||
results = data_manager.api.get(self.cached_item.items_url)
|
||||
if results is None:
|
||||
results = []
|
||||
|
||||
@@ -264,25 +254,25 @@ class CacheManagerThread(threading.Thread):
|
||||
def clear_cached_server_data():
|
||||
log.debug("clear_cached_server_data() called")
|
||||
|
||||
addon_dir = xbmc.translatePath(xbmcaddon.Addon().getAddonInfo('profile'))
|
||||
addon_dir = translate_path(xbmcaddon.Addon().getAddonInfo('profile'))
|
||||
dirs, files = xbmcvfs.listdir(addon_dir)
|
||||
|
||||
del_count = 0
|
||||
for filename in files:
|
||||
if filename.startswith("cache_") and filename.endswith(".pickle"):
|
||||
log.debug("Deleteing CacheFile: {0}".format(filename))
|
||||
log.debug("Deleting CacheFile: {0}".format(filename))
|
||||
xbmcvfs.delete(os.path.join(addon_dir, filename))
|
||||
del_count += 1
|
||||
|
||||
log.debug('Deleted {} files'.format(del_count))
|
||||
msg = string_load(30394)
|
||||
xbmcgui.Dialog().ok(string_load(30393), msg)
|
||||
msg = translate_string(30394)
|
||||
xbmcgui.Dialog().ok(translate_string(30393), msg)
|
||||
|
||||
|
||||
def clear_old_cache_data():
|
||||
log.debug("clear_old_cache_data() : called")
|
||||
|
||||
addon_dir = xbmc.translatePath(xbmcaddon.Addon().getAddonInfo('profile'))
|
||||
addon_dir = translate_path(xbmcaddon.Addon().getAddonInfo('profile'))
|
||||
dirs, files = xbmcvfs.listdir(addon_dir)
|
||||
|
||||
del_count = 0
|
||||
|
||||
208
resources/lib/dialogs.py
Normal file
208
resources/lib/dialogs.py
Normal file
@@ -0,0 +1,208 @@
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import xbmcgui
|
||||
|
||||
from .lazylogger import LazyLogger
|
||||
from .utils import translate_string, send_event_notification
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
|
||||
class BitrateDialog(xbmcgui.WindowXMLDialog):
|
||||
|
||||
slider_control = None
|
||||
bitrate_label = None
|
||||
initial_bitrate_value = 0
|
||||
selected_transcode_value = 0
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
log.debug("BitrateDialog: __init__")
|
||||
xbmcgui.WindowXML.__init__(self, *args, **kwargs)
|
||||
|
||||
def onInit(self):
|
||||
log.debug("ActionMenu: onInit")
|
||||
self.action_exitkeys_id = [10, 13]
|
||||
|
||||
self.slider_control = self.getControl(3000)
|
||||
self.slider_control.setInt(self.initial_bitrate_value, 400, 100, 15000)
|
||||
|
||||
self.bitrate_label = self.getControl(3030)
|
||||
bitrate_label_string = str(self.slider_control.getInt()) + " Kbs"
|
||||
self.bitrate_label.setLabel(bitrate_label_string)
|
||||
self.getControl(3011).setLabel(translate_string(30314))
|
||||
|
||||
def onFocus(self, control_id):
|
||||
pass
|
||||
|
||||
def doAction(self, action_id):
|
||||
pass
|
||||
|
||||
def onMessage(self, message):
|
||||
log.debug("ActionMenu: onMessage: {0}".format(message))
|
||||
|
||||
def onAction(self, action):
|
||||
|
||||
bitrate_label_string = str(self.slider_control.getInt()) + " Kbs"
|
||||
self.bitrate_label.setLabel(bitrate_label_string)
|
||||
|
||||
if action.getId() == 10: # ACTION_PREVIOUS_MENU
|
||||
self.close()
|
||||
elif action.getId() == 92: # ACTION_NAV_BACK
|
||||
self.close()
|
||||
elif action.getId() == 7: # ENTER
|
||||
self.selected_transcode_value = self.slider_control.getInt()
|
||||
self.close()
|
||||
|
||||
def onClick(self, control_id):
|
||||
if control_id == 3000:
|
||||
log.debug("ActionMenu: Selected Item: {0}".format(control_id))
|
||||
|
||||
|
||||
class ResumeDialog(xbmcgui.WindowXMLDialog):
|
||||
resumePlay = -1
|
||||
resumeTimeStamp = ""
|
||||
action_exitkeys_id = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs)
|
||||
log.debug("ResumeDialog INITIALISED")
|
||||
|
||||
def onInit(self):
|
||||
self.action_exitkeys_id = [10, 13]
|
||||
self.getControl(3010).setLabel(self.resumeTimeStamp)
|
||||
self.getControl(3011).setLabel(translate_string(30237))
|
||||
|
||||
def onFocus(self, controlId):
|
||||
pass
|
||||
|
||||
def doAction(self, actionID):
|
||||
pass
|
||||
|
||||
def onClick(self, controlID):
|
||||
|
||||
if controlID == 3010:
|
||||
self.resumePlay = 0
|
||||
self.close()
|
||||
if controlID == 3011:
|
||||
self.resumePlay = 1
|
||||
self.close()
|
||||
|
||||
def setResumeTime(self, timeStamp):
|
||||
self.resumeTimeStamp = timeStamp
|
||||
|
||||
def getResumeAction(self):
|
||||
return self.resumePlay
|
||||
|
||||
|
||||
class SafeDeleteDialog(xbmcgui.WindowXMLDialog):
|
||||
|
||||
confirm = False
|
||||
message = "Demo Message"
|
||||
heading = "Demo Heading"
|
||||
action_exitkeys_id = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
log.debug("SafeDeleteDialog: __init__")
|
||||
xbmcgui.WindowXML.__init__(self, *args, **kwargs)
|
||||
|
||||
def onInit(self):
|
||||
log.debug("SafeDeleteDialog: onInit")
|
||||
self.action_exitkeys_id = [10, 13]
|
||||
|
||||
message_control = self.getControl(3)
|
||||
message_control.setText(self.message)
|
||||
|
||||
message_control = self.getControl(4)
|
||||
message_control.setLabel(self.heading)
|
||||
|
||||
def onFocus(self, controlId):
|
||||
pass
|
||||
|
||||
def doAction(self, actionID):
|
||||
pass
|
||||
|
||||
def onMessage(self, message):
|
||||
log.debug("SafeDeleteDialog: onMessage: {0}".format(message))
|
||||
|
||||
def onAction(self, action):
|
||||
|
||||
if action.getId() == 10: # ACTION_PREVIOUS_MENU
|
||||
self.close()
|
||||
elif action.getId() == 92: # ACTION_NAV_BACK
|
||||
self.close()
|
||||
else:
|
||||
log.debug("SafeDeleteDialog: onAction: {0}".format(action.getId()))
|
||||
|
||||
def onClick(self, controlID):
|
||||
if controlID == 1:
|
||||
self.confirm = True
|
||||
self.close()
|
||||
elif controlID == 2:
|
||||
self.confirm = False
|
||||
self.close()
|
||||
|
||||
|
||||
class PlayNextDialog(xbmcgui.WindowXMLDialog):
|
||||
|
||||
action_exitkeys_id = None
|
||||
episode_info = None
|
||||
play_called = False
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
log.debug("PlayNextDialog: __init__")
|
||||
xbmcgui.WindowXML.__init__(self, *args, **kwargs)
|
||||
|
||||
def onInit(self):
|
||||
log.debug("PlayNextDialog: onInit")
|
||||
self.action_exitkeys_id = [10, 13]
|
||||
|
||||
index = self.episode_info.get("IndexNumber", -1)
|
||||
series_name = self.episode_info.get("SeriesName")
|
||||
next_epp_name = "Episode %02d - (%s)" % (index, self.episode_info.get("Name", "n/a"))
|
||||
|
||||
series_label = self.getControl(3011)
|
||||
series_label.setLabel(series_name)
|
||||
|
||||
series_label = self.getControl(3012)
|
||||
series_label.setLabel(next_epp_name)
|
||||
|
||||
def onFocus(self, control_id):
|
||||
pass
|
||||
|
||||
def doAction(self, action_id):
|
||||
pass
|
||||
|
||||
def onMessage(self, message):
|
||||
log.debug("PlayNextDialog: onMessage: {0}".format(message))
|
||||
|
||||
def onAction(self, action):
|
||||
|
||||
if action.getId() == 10: # ACTION_PREVIOUS_MENU
|
||||
self.close()
|
||||
elif action.getId() == 92: # ACTION_NAV_BACK
|
||||
self.close()
|
||||
else:
|
||||
log.debug("PlayNextDialog: onAction: {0}".format(action.getId()))
|
||||
|
||||
def onClick(self, control_id):
|
||||
if control_id == 3013:
|
||||
log.debug("PlayNextDialog: Play Next Episode")
|
||||
self.play_called
|
||||
self.close()
|
||||
next_item_id = self.episode_info.get("Id")
|
||||
log.debug("Playing Next Episode: {0}".format(next_item_id))
|
||||
play_info = {}
|
||||
play_info["item_id"] = next_item_id
|
||||
play_info["auto_resume"] = "-1"
|
||||
play_info["force_transcode"] = False
|
||||
send_event_notification("jellycon_play_action", play_info)
|
||||
elif control_id == 3014:
|
||||
self.close()
|
||||
|
||||
def set_episode_info(self, info):
|
||||
self.episode_info = info
|
||||
|
||||
def get_play_called(self):
|
||||
return self.play_called
|
||||
@@ -1,22 +1,23 @@
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import sys
|
||||
import re
|
||||
|
||||
import xbmcaddon
|
||||
import xbmcplugin
|
||||
import xbmcgui
|
||||
|
||||
from six.moves.urllib.parse import quote, unquote
|
||||
import sys
|
||||
import re
|
||||
|
||||
from .datamanager import DataManager
|
||||
from .kodi_utils import HomeWindow
|
||||
from .downloadutils import DownloadUtils
|
||||
from .translation import string_load
|
||||
from .loghandler import LazyLogger
|
||||
from .lazylogger import LazyLogger
|
||||
from .item_functions import add_gui_item, ItemDetails
|
||||
from .utils import send_event_notification
|
||||
from .tracking import timer
|
||||
from .utils import (
|
||||
send_event_notification, translate_string,
|
||||
load_user_details, get_default_filters
|
||||
)
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
@@ -28,7 +29,7 @@ def get_content(url, params):
|
||||
default_sort = params.get("sort")
|
||||
media_type = params.get("media_type", None)
|
||||
if not media_type:
|
||||
xbmcgui.Dialog().ok(string_load(30135), string_load(30139))
|
||||
xbmcgui.Dialog().ok(translate_string(30135), translate_string(30139))
|
||||
|
||||
log.debug("URL: {0}".format(url))
|
||||
log.debug("MediaType: {0}".format(media_type))
|
||||
@@ -71,6 +72,11 @@ def get_content(url, params):
|
||||
content_type = 'episodes'
|
||||
elif media_type == "playlists":
|
||||
view_type = "Playlists"
|
||||
elif media_type == "musicvideos":
|
||||
view_type = "Music Videos"
|
||||
content_type = 'musicvideos'
|
||||
elif media_type == "mixed":
|
||||
content_type = 'videos'
|
||||
|
||||
log.debug("media_type:{0} content_type:{1} view_type:{2} ".format(media_type, content_type, view_type))
|
||||
|
||||
@@ -78,8 +84,8 @@ def get_content(url, params):
|
||||
progress = None
|
||||
if settings.getSetting('showLoadProgress') == "true":
|
||||
progress = xbmcgui.DialogProgress()
|
||||
progress.create(string_load(30112))
|
||||
progress.update(0, string_load(30113))
|
||||
progress.create(translate_string(30112))
|
||||
progress.update(0, translate_string(30113))
|
||||
|
||||
# update url for paging
|
||||
start_index = 0
|
||||
@@ -106,13 +112,6 @@ def get_content(url, params):
|
||||
url = url + "&StartIndex=" + str(start_index) + "&Limit=" + str(page_limit)
|
||||
log.debug("ADDING NEXT URL: {0}".format(url_next))
|
||||
|
||||
# use the data manager to get the data
|
||||
# result = dataManager.GetContent(url)
|
||||
|
||||
# total_records = 0
|
||||
# if result is not None and isinstance(result, dict):
|
||||
# total_records = result.get("TotalRecordCount", 0)
|
||||
|
||||
use_cache = params.get("use_cache", "true") == "true"
|
||||
|
||||
dir_items, detected_type, total_records = process_directory(url, progress, params, use_cache)
|
||||
@@ -174,7 +173,7 @@ def get_content(url, params):
|
||||
log.debug("No view id for view type:{0}".format(view_key))
|
||||
|
||||
if progress is not None:
|
||||
progress.update(100, string_load(30125))
|
||||
progress.update(100, translate_string(30125))
|
||||
progress.close()
|
||||
|
||||
return
|
||||
@@ -227,8 +226,9 @@ def process_directory(url, progress, params, use_cache_data=False):
|
||||
|
||||
data_manager = DataManager()
|
||||
settings = xbmcaddon.Addon()
|
||||
download_utils = DownloadUtils()
|
||||
server = download_utils.get_server()
|
||||
server = settings.getSetting('server_address')
|
||||
user_details = load_user_details()
|
||||
user_id = user_details.get('user_id')
|
||||
|
||||
name_format = params.get("name_format", None)
|
||||
name_format_type = None
|
||||
@@ -248,22 +248,34 @@ def process_directory(url, progress, params, use_cache_data=False):
|
||||
gui_options["name_format_type"] = name_format_type
|
||||
|
||||
use_cache = settings.getSetting("use_cache") == "true" and use_cache_data
|
||||
default_filters = get_default_filters()
|
||||
|
||||
# Fix skin shortcuts from pre-0.5.0
|
||||
item_limit = int(settings.getSetting("show_x_filtered_items"))
|
||||
url = url.replace('{server}', '')
|
||||
url = url.replace('{field_filters}', default_filters)
|
||||
url = url.replace('{ItemLimit}', str(item_limit))
|
||||
|
||||
# Need to replace at runtime so it always pulls the current user
|
||||
url = unquote(url)
|
||||
url = url.replace('{userid}', user_id)
|
||||
|
||||
cache_file, item_list, total_records, cache_thread = data_manager.get_items(url, gui_options, use_cache)
|
||||
|
||||
# flatten single season
|
||||
# if there is only one result and it is a season and you have flatten signle season turned on then
|
||||
# if there is only one result and it is a season and you have flatten single season turned on then
|
||||
# build a new url, set the content media type and call get content again
|
||||
flatten_single_season = settings.getSetting("flatten_single_season") == "true"
|
||||
if flatten_single_season and len(item_list) == 1 and item_list[0].item_type == "Season":
|
||||
season_id = item_list[0].id
|
||||
series_id = item_list[0].series_id
|
||||
season_url = ('{server}/Shows/' + series_id +
|
||||
season_url = ('/Shows/' + series_id +
|
||||
'/Episodes'
|
||||
'?userId={userid}' +
|
||||
'&seasonId=' + season_id +
|
||||
'&IsVirtualUnAired=false' +
|
||||
'&IsMissing=false' +
|
||||
'&Fields=SpecialEpisodeNumbers,{field_filters}' +
|
||||
'&Fields=SpecialEpisodeNumbers,{}'.format(default_filters) +
|
||||
'&format=json')
|
||||
if progress is not None:
|
||||
progress.close()
|
||||
@@ -290,14 +302,15 @@ def process_directory(url, progress, params, use_cache_data=False):
|
||||
|
||||
detected_type = None
|
||||
dir_items = []
|
||||
|
||||
OnlyTotallyUnwatchedTvShow = params.get("OnlyTotallyUnwatchedTvShow", None)
|
||||
for item_details in item_list:
|
||||
|
||||
if OnlyTotallyUnwatchedTvShow == "1" and item_details.watched_episodes > 0:
|
||||
continue
|
||||
item_details.total_items = item_count
|
||||
|
||||
if progress is not None:
|
||||
percent_done = (float(current_item) / float(item_count)) * 100
|
||||
progress.update(int(percent_done), string_load(30126) + str(current_item))
|
||||
progress.update(int(percent_done), translate_string(30126) + str(current_item))
|
||||
current_item = current_item + 1
|
||||
|
||||
if detected_type is not None:
|
||||
@@ -322,28 +335,30 @@ def process_directory(url, progress, params, use_cache_data=False):
|
||||
|
||||
if item_details.is_folder is True:
|
||||
if item_details.item_type == "Series":
|
||||
u = ('{server}/Shows/' + item_details.id +
|
||||
u = ('/Shows/' + item_details.id +
|
||||
'/Seasons'
|
||||
'?userId={userid}' +
|
||||
'&Fields={field_filters}' +
|
||||
'&Fields={}'.format(default_filters) +
|
||||
'&format=json')
|
||||
if not show_empty_folders:
|
||||
u = u + '&isMissing=False'
|
||||
|
||||
elif item_details.item_type == "Season":
|
||||
u = ('{server}/Shows/' + item_details.series_id +
|
||||
u = ('/Shows/' + item_details.series_id +
|
||||
'/Episodes'
|
||||
'?userId={userid}' +
|
||||
'&seasonId=' + item_details.id +
|
||||
'&IsVirtualUnAired=false' +
|
||||
'&IsMissing=false' +
|
||||
'&Fields=SpecialEpisodeNumbers,{field_filters}' +
|
||||
'&Fields=SpecialEpisodeNumbers,{}'.format(default_filters) +
|
||||
'&format=json')
|
||||
|
||||
else:
|
||||
u = ('{server}/Users/{userid}/items' +
|
||||
u = ('/Users/{userid}/items' +
|
||||
'?ParentId=' + item_details.id +
|
||||
'&IsVirtualUnAired=false' +
|
||||
'&IsMissing=false' +
|
||||
'&Fields={field_filters}' +
|
||||
'&Fields={}'.format(default_filters) +
|
||||
'&format=json')
|
||||
|
||||
default_sort = item_details.item_type == "Playlist"
|
||||
@@ -356,7 +371,7 @@ def process_directory(url, progress, params, use_cache_data=False):
|
||||
log.debug("Dropping empty folder item : {0}".format(item_details.__dict__))
|
||||
|
||||
elif item_details.item_type == "MusicArtist":
|
||||
u = ('{server}/Users/{userid}/items' +
|
||||
u = ('/Users/{userid}/items' +
|
||||
'?ArtistIds=' + item_details.id +
|
||||
'&IncludeItemTypes=MusicAlbum' +
|
||||
'&CollapseBoxSetItems=false' +
|
||||
@@ -378,13 +393,12 @@ def process_directory(url, progress, params, use_cache_data=False):
|
||||
and first_season_item is not None
|
||||
and len(dir_items) > 1
|
||||
and first_season_item.series_id is not None):
|
||||
series_url = ('{server}/Shows/' + first_season_item.series_id +
|
||||
series_url = ('/Shows/' + first_season_item.series_id +
|
||||
'/Episodes'
|
||||
'?userId={userid}' +
|
||||
# '&seasonId=' + season_id +
|
||||
'&IsVirtualUnAired=false' +
|
||||
'&IsMissing=false' +
|
||||
'&Fields=SpecialEpisodeNumbers,{field_filters}' +
|
||||
'&Fields=SpecialEpisodeNumbers,{}'.format(default_filters) +
|
||||
'&format=json')
|
||||
played = 0
|
||||
overlay = "7"
|
||||
@@ -395,7 +409,7 @@ def process_directory(url, progress, params, use_cache_data=False):
|
||||
item_details = ItemDetails()
|
||||
|
||||
item_details.id = first_season_item.id
|
||||
item_details.name = string_load(30290)
|
||||
item_details.name = translate_string(30290)
|
||||
item_details.art = first_season_item.art
|
||||
item_details.play_count = played
|
||||
item_details.overlay = overlay
|
||||
|
||||
@@ -1,724 +0,0 @@
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
import xbmcgui
|
||||
import xbmcaddon
|
||||
|
||||
import requests
|
||||
import hashlib
|
||||
import ssl
|
||||
import gzip
|
||||
import json
|
||||
from six.moves.urllib.parse import urlparse
|
||||
from base64 import b64encode
|
||||
from collections import defaultdict
|
||||
from traceback import format_exc
|
||||
from kodi_six.utils import py2_decode
|
||||
from six import ensure_text
|
||||
|
||||
from .kodi_utils import HomeWindow
|
||||
from .clientinfo import ClientInformation
|
||||
from .loghandler import LazyLogger
|
||||
from .translation import string_load
|
||||
from .tracking import timer
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
|
||||
def save_user_details(settings, user_name, user_password):
|
||||
save_user_to_settings = settings.getSetting("save_user_to_settings") == "true"
|
||||
if save_user_to_settings:
|
||||
settings.setSetting("username", user_name)
|
||||
settings.setSetting("password", user_password)
|
||||
else:
|
||||
settings.setSetting("username", "")
|
||||
settings.setSetting("password", "")
|
||||
home_window = HomeWindow()
|
||||
home_window.set_property("username", user_name)
|
||||
home_window.set_property("password", user_password)
|
||||
|
||||
|
||||
def load_user_details(settings):
|
||||
save_user_to_settings = settings.getSetting("save_user_to_settings") == "true"
|
||||
if save_user_to_settings:
|
||||
user_name = settings.getSetting("username")
|
||||
user_password = settings.getSetting("password")
|
||||
else:
|
||||
home_window = HomeWindow()
|
||||
user_name = home_window.get_property("username")
|
||||
user_password = home_window.get_property("password")
|
||||
|
||||
user_details = {}
|
||||
user_details["username"] = user_name
|
||||
user_details["password"] = user_password
|
||||
return user_details
|
||||
|
||||
|
||||
def get_details_string():
|
||||
|
||||
addon_settings = xbmcaddon.Addon()
|
||||
include_media = addon_settings.getSetting("include_media") == "true"
|
||||
include_people = addon_settings.getSetting("include_people") == "true"
|
||||
include_overview = addon_settings.getSetting("include_overview") == "true"
|
||||
|
||||
filer_list = [
|
||||
"DateCreated",
|
||||
"EpisodeCount",
|
||||
"SeasonCount",
|
||||
"Path",
|
||||
"Genres",
|
||||
"Studios",
|
||||
"Etag",
|
||||
"Taglines",
|
||||
"SortName",
|
||||
"RecursiveItemCount",
|
||||
"ChildCount",
|
||||
"ProductionLocations",
|
||||
"CriticRating",
|
||||
"OfficialRating",
|
||||
"CommunityRating",
|
||||
"PremiereDate",
|
||||
"ProductionYear",
|
||||
"AirTime",
|
||||
"Status",
|
||||
"Tags"
|
||||
]
|
||||
|
||||
if include_media:
|
||||
filer_list.append("MediaStreams")
|
||||
|
||||
if include_people:
|
||||
filer_list.append("People")
|
||||
|
||||
if include_overview:
|
||||
filer_list.append("Overview")
|
||||
|
||||
return ",".join(filer_list)
|
||||
|
||||
|
||||
class DownloadUtils:
|
||||
use_https = False
|
||||
verify_cert = False
|
||||
|
||||
def __init__(self, *args):
|
||||
settings = xbmcaddon.Addon()
|
||||
|
||||
self.use_https = False
|
||||
if settings.getSetting('protocol') == "1":
|
||||
self.use_https = True
|
||||
log.debug("use_https: {0}".format(self.use_https))
|
||||
|
||||
self.verify_cert = settings.getSetting('verify_cert') == 'true'
|
||||
log.debug("verify_cert: {0}".format(self.verify_cert))
|
||||
|
||||
def post_capabilities(self):
|
||||
|
||||
url = "{server}/Sessions/Capabilities/Full?format=json"
|
||||
data = {
|
||||
'SupportsMediaControl': True,
|
||||
'PlayableMediaTypes': ["Video", "Audio"],
|
||||
'SupportedCommands': ["MoveUp",
|
||||
"MoveDown",
|
||||
"MoveLeft",
|
||||
"MoveRight",
|
||||
"Select",
|
||||
"Back",
|
||||
"ToggleContextMenu",
|
||||
"ToggleFullscreen",
|
||||
"ToggleOsdMenu",
|
||||
"GoHome",
|
||||
"PageUp",
|
||||
"NextLetter",
|
||||
"GoToSearch",
|
||||
"GoToSettings",
|
||||
"PageDown",
|
||||
"PreviousLetter",
|
||||
"TakeScreenshot",
|
||||
"VolumeUp",
|
||||
"VolumeDown",
|
||||
"ToggleMute",
|
||||
"SendString",
|
||||
"DisplayMessage",
|
||||
"SetAudioStreamIndex",
|
||||
"SetSubtitleStreamIndex",
|
||||
"SetRepeatMode",
|
||||
"Mute",
|
||||
"Unmute",
|
||||
"SetVolume",
|
||||
"PlayNext",
|
||||
"Play",
|
||||
"Playstate",
|
||||
"PlayMediaSource"]
|
||||
}
|
||||
|
||||
self.download_url(url, post_body=data, method="POST")
|
||||
log.debug("Posted Capabilities: {0}".format(data))
|
||||
|
||||
def get_item_playback_info(self, item_id, force_transcode):
|
||||
|
||||
addon_settings = xbmcaddon.Addon()
|
||||
|
||||
filtered_codecs = []
|
||||
if addon_settings.getSetting("force_transcode_h265") == "true":
|
||||
filtered_codecs.append("hevc")
|
||||
filtered_codecs.append("h265")
|
||||
if addon_settings.getSetting("force_transcode_mpeg2") == "true":
|
||||
filtered_codecs.append("mpeg2video")
|
||||
if addon_settings.getSetting("force_transcode_msmpeg4v3") == "true":
|
||||
filtered_codecs.append("msmpeg4v3")
|
||||
if addon_settings.getSetting("force_transcode_mpeg4") == "true":
|
||||
filtered_codecs.append("mpeg4")
|
||||
|
||||
playback_bitrate = addon_settings.getSetting("max_stream_bitrate")
|
||||
force_playback_bitrate = addon_settings.getSetting("force_max_stream_bitrate")
|
||||
if force_transcode:
|
||||
playback_bitrate = force_playback_bitrate
|
||||
|
||||
audio_codec = addon_settings.getSetting("audio_codec")
|
||||
audio_playback_bitrate = addon_settings.getSetting("audio_playback_bitrate")
|
||||
audio_max_channels = addon_settings.getSetting("audio_max_channels")
|
||||
|
||||
audio_bitrate = int(audio_playback_bitrate) * 1000
|
||||
bitrate = int(playback_bitrate) * 1000
|
||||
|
||||
profile = {
|
||||
"Name": "Kodi",
|
||||
"MaxStaticBitrate": bitrate,
|
||||
"MaxStreamingBitrate": bitrate,
|
||||
"MusicStreamingTranscodingBitrate": audio_bitrate,
|
||||
"TimelineOffsetSeconds": 5,
|
||||
"TranscodingProfiles": [
|
||||
{
|
||||
"Type": "Audio"
|
||||
},
|
||||
{
|
||||
"Container": "ts",
|
||||
"Protocol": "hls",
|
||||
"Type": "Video",
|
||||
"AudioCodec": audio_codec,
|
||||
"VideoCodec": "h264",
|
||||
"MaxAudioChannels": audio_max_channels
|
||||
},
|
||||
{
|
||||
"Container": "jpeg",
|
||||
"Type": "Photo"
|
||||
}
|
||||
],
|
||||
"DirectPlayProfiles": [
|
||||
{
|
||||
"Type": "Video"
|
||||
},
|
||||
{
|
||||
"Type": "Audio"
|
||||
},
|
||||
{
|
||||
"Type": "Photo"
|
||||
}
|
||||
],
|
||||
"ResponseProfiles": [],
|
||||
"ContainerProfiles": [],
|
||||
"CodecProfiles": [],
|
||||
"SubtitleProfiles": [
|
||||
{
|
||||
"Format": "srt",
|
||||
"Method": "External"
|
||||
},
|
||||
{
|
||||
"Format": "srt",
|
||||
"Method": "Embed"
|
||||
},
|
||||
{
|
||||
"Format": "ass",
|
||||
"Method": "External"
|
||||
},
|
||||
{
|
||||
"Format": "ass",
|
||||
"Method": "Embed"
|
||||
},
|
||||
{
|
||||
"Format": "sub",
|
||||
"Method": "Embed"
|
||||
},
|
||||
{
|
||||
"Format": "sub",
|
||||
"Method": "External"
|
||||
},
|
||||
{
|
||||
"Format": "ssa",
|
||||
"Method": "Embed"
|
||||
},
|
||||
{
|
||||
"Format": "ssa",
|
||||
"Method": "External"
|
||||
},
|
||||
{
|
||||
"Format": "smi",
|
||||
"Method": "Embed"
|
||||
},
|
||||
{
|
||||
"Format": "smi",
|
||||
"Method": "External"
|
||||
},
|
||||
{
|
||||
"Format": "pgssub",
|
||||
"Method": "Embed"
|
||||
},
|
||||
{
|
||||
"Format": "pgssub",
|
||||
"Method": "External"
|
||||
},
|
||||
{
|
||||
"Format": "dvdsub",
|
||||
"Method": "Embed"
|
||||
},
|
||||
{
|
||||
"Format": "dvdsub",
|
||||
"Method": "External"
|
||||
},
|
||||
{
|
||||
"Format": "pgs",
|
||||
"Method": "Embed"
|
||||
},
|
||||
{
|
||||
"Format": "pgs",
|
||||
"Method": "External"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
if len(filtered_codecs) > 0:
|
||||
profile['DirectPlayProfiles'][0]['VideoCodec'] = "-%s" % ",".join(filtered_codecs)
|
||||
|
||||
if force_transcode:
|
||||
profile['DirectPlayProfiles'] = []
|
||||
|
||||
if addon_settings.getSetting("playback_video_force_8") == "true":
|
||||
profile['CodecProfiles'].append(
|
||||
{
|
||||
"Type": "Video",
|
||||
"Codec": "h264",
|
||||
"Conditions": [
|
||||
{
|
||||
"Condition": "LessThanEqual",
|
||||
"Property": "VideoBitDepth",
|
||||
"Value": "8",
|
||||
"IsRequired": False
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
profile['CodecProfiles'].append(
|
||||
{
|
||||
"Type": "Video",
|
||||
"Codec": "h265,hevc",
|
||||
"Conditions": [
|
||||
{
|
||||
"Condition": "EqualsAny",
|
||||
"Property": "VideoProfile",
|
||||
"Value": "main"
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
playback_info = {
|
||||
'UserId': self.get_user_id(),
|
||||
'DeviceProfile': profile,
|
||||
'AutoOpenLiveStream': True
|
||||
}
|
||||
|
||||
if force_transcode:
|
||||
url = "{server}/Items/%s/PlaybackInfo?MaxStreamingBitrate=%s&EnableDirectPlay=false&EnableDirectStream=false" % (item_id, bitrate)
|
||||
else:
|
||||
url = "{server}/Items/%s/PlaybackInfo?MaxStreamingBitrate=%s" % (item_id, bitrate)
|
||||
|
||||
log.debug("PlaybackInfo : {0}".format(url))
|
||||
log.debug("PlaybackInfo : {0}".format(profile))
|
||||
play_info_result = self.download_url(url, post_body=playback_info, method="POST")
|
||||
log.debug("PlaybackInfo : {0}".format(play_info_result))
|
||||
|
||||
return play_info_result
|
||||
|
||||
def get_server(self):
|
||||
settings = xbmcaddon.Addon()
|
||||
|
||||
#For migration from storing URL parts to just one URL
|
||||
if settings.getSetting('ipaddress') != "" and settings.getSetting('ipaddress') != "<none>":
|
||||
log.info("Migrating to new server url storage")
|
||||
url = ("http://" if settings.getSetting('protocol') == "0" else "https://") + settings.getSetting('ipaddress') + ":" + settings.getSetting('port')
|
||||
settings.setSetting('server_address', url)
|
||||
settings.setSetting('ipaddress', "")
|
||||
|
||||
return settings.getSetting('server_address')
|
||||
|
||||
@staticmethod
|
||||
def get_all_artwork(item, server):
|
||||
all_art = defaultdict(lambda: "")
|
||||
|
||||
item_id = item["Id"]
|
||||
item_type = item["Type"]
|
||||
image_tags = item["ImageTags"]
|
||||
|
||||
# All the image tags
|
||||
for tag_name in image_tags:
|
||||
tag = image_tags[tag_name]
|
||||
art_url = "%s/Items/%s/Images/%s/0?Format=original&Tag=%s" % (server, item_id, tag_name, tag)
|
||||
all_art[tag_name] = art_url
|
||||
|
||||
# Series images
|
||||
if item_type in ["Episode", "Season"]:
|
||||
image_tag = item["SeriesPrimaryImageTag"]
|
||||
series_id = item["SeriesId"]
|
||||
if image_tag and series_id:
|
||||
art_url = "%s/Items/%s/Images/Primary/0?Format=original&Tag=%s" % (server, series_id, image_tag)
|
||||
all_art["Primary.Series"] = art_url
|
||||
|
||||
return all_art
|
||||
|
||||
def get_artwork(self, data, art_type, parent=False, index=0, server=None):
|
||||
|
||||
item_id = data["Id"]
|
||||
item_type = data["Type"]
|
||||
|
||||
if item_type in ["Episode", "Season"]:
|
||||
if art_type != "Primary" or parent is True:
|
||||
item_id = data["SeriesId"]
|
||||
|
||||
image_tag = ""
|
||||
|
||||
# for episodes always use the parent BG
|
||||
if item_type == "Episode" and art_type == "Backdrop":
|
||||
item_id = data.get("ParentBackdropItemId")
|
||||
bg_item_tags = data.get("ParentBackdropImageTags", [])
|
||||
if bg_item_tags:
|
||||
image_tag = bg_item_tags[0]
|
||||
elif art_type == "Backdrop" and parent is True:
|
||||
item_id = data.get("ParentBackdropItemId")
|
||||
bg_item_tags = data.get("ParentBackdropImageTags", [])
|
||||
if bg_item_tags:
|
||||
image_tag = bg_item_tags[0]
|
||||
elif art_type == "Backdrop":
|
||||
bg_tags = data.get("BackdropImageTags", [])
|
||||
if bg_tags:
|
||||
image_tag = bg_tags[index]
|
||||
elif parent is False:
|
||||
image_tags = data.get("ImageTags", [])
|
||||
if image_tags:
|
||||
image_tag_type = image_tags.get(art_type)
|
||||
if image_tag_type:
|
||||
image_tag = image_tag_type
|
||||
elif parent is True:
|
||||
if (item_type == "Episode" or item_type == "Season") and art_type == 'Primary':
|
||||
tag_name = 'SeriesPrimaryImageTag'
|
||||
id_name = 'SeriesId'
|
||||
else:
|
||||
tag_name = 'Parent%sImageTag' % art_type
|
||||
id_name = 'Parent%sItemId' % art_type
|
||||
parent_image_id = data.get(id_name)
|
||||
parent_image_tag = data.get(tag_name)
|
||||
if parent_image_id is not None and parent_image_tag is not None:
|
||||
item_id = parent_image_id
|
||||
image_tag = parent_image_tag
|
||||
|
||||
# ParentTag not passed for Banner and Art
|
||||
if not image_tag and not ((art_type == 'Banner' or art_type == 'Art') and parent is True):
|
||||
return ""
|
||||
|
||||
artwork = "%s/Items/%s/Images/%s/%s?Format=original&Tag=%s" % (server, item_id, art_type, index, image_tag)
|
||||
|
||||
if self.use_https and not self.verify_cert:
|
||||
artwork += "|verifypeer=false"
|
||||
|
||||
return artwork
|
||||
|
||||
|
||||
def image_url(self, item_id, art_type, index, width, height, image_tag, server):
|
||||
|
||||
# test imageTag e3ab56fe27d389446754d0fb04910a34
|
||||
artwork = "%s/Items/%s/Images/%s/%s?Format=original&Tag=%s" % (server, item_id, art_type, index, image_tag)
|
||||
if int(width) > 0:
|
||||
artwork += '&MaxWidth=%s' % width
|
||||
if int(height) > 0:
|
||||
artwork += '&MaxHeight=%s' % height
|
||||
|
||||
if self.use_https and not self.verify_cert:
|
||||
artwork += "|verifypeer=false"
|
||||
|
||||
return artwork
|
||||
|
||||
def get_user_artwork(self, user, item_type):
|
||||
|
||||
if "PrimaryImageTag" not in user:
|
||||
return ""
|
||||
user_id = user.get("Id")
|
||||
tag = user.get("PrimaryImageTag")
|
||||
server = self.get_server()
|
||||
|
||||
artwork = "%s/Users/%s/Images/%s?Format=original&tag=%s" % (server, user_id, item_type, tag)
|
||||
|
||||
if self.use_https and not self.verify_cert:
|
||||
artwork += "|verifypeer=false"
|
||||
|
||||
return artwork
|
||||
|
||||
def get_user_id(self):
|
||||
|
||||
window = HomeWindow()
|
||||
userid = window.get_property("userid")
|
||||
user_image = window.get_property("userimage")
|
||||
|
||||
if userid:
|
||||
log.debug("JellyCon DownloadUtils -> Returning saved UserID: {0}".format(userid))
|
||||
return userid
|
||||
|
||||
settings = xbmcaddon.Addon()
|
||||
user_details = load_user_details(settings)
|
||||
user_name = user_details.get("username", "")
|
||||
|
||||
if not user_name:
|
||||
return ""
|
||||
log.debug("Looking for user name: {0}".format(user_name))
|
||||
|
||||
try:
|
||||
result = self.download_url("{server}/Users/Public?format=json", suppress=True, authenticate=False)
|
||||
except Exception as msg:
|
||||
log.error("Get User unable to connect: {0}".format(msg))
|
||||
return ""
|
||||
|
||||
log.debug("GETUSER_JSONDATA_01: {0}".format(py2_decode(result)))
|
||||
|
||||
if not result:
|
||||
return ""
|
||||
|
||||
log.debug("GETUSER_JSONDATA_02: {0}".format(result))
|
||||
|
||||
secure = False
|
||||
for user in result:
|
||||
if user.get("Name") == ensure_text(user_name, "utf-8"):
|
||||
userid = user.get("Id")
|
||||
user_image = self.get_user_artwork(user, 'Primary')
|
||||
log.debug("Username Found: {0}".format(user.get("Name")))
|
||||
if user.get("HasPassword", False):
|
||||
secure = True
|
||||
log.debug("Username Is Secure (HasPassword=True)")
|
||||
break
|
||||
|
||||
if secure or not userid:
|
||||
auth_ok = self.authenticate()
|
||||
if auth_ok == "":
|
||||
xbmcgui.Dialog().notification(string_load(30316),
|
||||
string_load(30044),
|
||||
icon="special://home/addons/plugin.video.jellycon/icon.png")
|
||||
return ""
|
||||
if not userid:
|
||||
userid = window.get_property("userid")
|
||||
|
||||
if userid and not user_image:
|
||||
user_image = 'DefaultUser.png'
|
||||
|
||||
if userid == "":
|
||||
xbmcgui.Dialog().notification(string_load(30316),
|
||||
string_load(30045),
|
||||
icon="special://home/addons/plugin.video.jellycon/icon.png")
|
||||
|
||||
log.debug("userid: {0}".format(userid))
|
||||
|
||||
window.set_property("userid", userid)
|
||||
window.set_property("userimage", user_image)
|
||||
|
||||
return userid
|
||||
|
||||
def authenticate(self):
|
||||
|
||||
window = HomeWindow()
|
||||
|
||||
token = window.get_property("AccessToken")
|
||||
if token is not None and token != "":
|
||||
log.debug("JellyCon DownloadUtils -> Returning saved AccessToken: {0}".format(token))
|
||||
return token
|
||||
|
||||
settings = xbmcaddon.Addon()
|
||||
server_address = settings.getSetting("server_address")
|
||||
|
||||
url = "{server}/Users/AuthenticateByName?format=json"
|
||||
|
||||
user_details = load_user_details(settings)
|
||||
user_name = user_details.get("username", "")
|
||||
pwd_text = user_details.get("password", "")
|
||||
|
||||
message_data = {'username': user_name, 'pw': pwd_text}
|
||||
|
||||
result = self.download_url(url, post_body=message_data, method="POST", suppress=True, authenticate=False)
|
||||
log.debug("AuthenticateByName: {0}".format(result))
|
||||
|
||||
access_token = None
|
||||
userid = None
|
||||
access_token = result.get("AccessToken")
|
||||
userid = result["User"].get("Id")
|
||||
|
||||
if access_token is not None:
|
||||
log.debug("User Authenticated: {0}".format(access_token))
|
||||
log.debug("User Id: {0}".format(userid))
|
||||
window.set_property("AccessToken", access_token)
|
||||
window.set_property("userid", userid)
|
||||
|
||||
self.post_capabilities()
|
||||
|
||||
return access_token
|
||||
else:
|
||||
log.debug("User NOT Authenticated")
|
||||
window.set_property("AccessToken", "")
|
||||
window.set_property("userid", "")
|
||||
window.set_property("userimage", "")
|
||||
return ""
|
||||
|
||||
def get_auth_header(self, authenticate=True):
|
||||
client_info = ClientInformation()
|
||||
txt_mac = client_info.get_device_id()
|
||||
version = client_info.get_version()
|
||||
client = client_info.get_client()
|
||||
|
||||
settings = xbmcaddon.Addon()
|
||||
device_name = settings.getSetting('deviceName')
|
||||
# remove none ascii chars
|
||||
device_name = py2_decode(device_name)
|
||||
# remove some chars not valid for names
|
||||
device_name = device_name.replace("\"", "_")
|
||||
if len(device_name) == 0:
|
||||
device_name = "JellyCon"
|
||||
|
||||
headers = {}
|
||||
headers["Accept-encoding"] = "gzip"
|
||||
headers["Accept-Charset"] = "UTF-8,*"
|
||||
|
||||
if authenticate is False:
|
||||
auth_string = "MediaBrowser Client=\"" + client + "\",Device=\"" + device_name + "\",DeviceId=\"" + txt_mac + "\",Version=\"" + version + "\""
|
||||
headers['X-Emby-Authorization'] = auth_string
|
||||
return headers
|
||||
else:
|
||||
userid = self.get_user_id()
|
||||
auth_string = "MediaBrowser UserId=\"" + userid + "\",Client=\"" + client + "\",Device=\"" + device_name + "\",DeviceId=\"" + txt_mac + "\",Version=\"" + version + "\""
|
||||
headers['X-Emby-Authorization'] = auth_string
|
||||
|
||||
auth_token = self.authenticate()
|
||||
if auth_token != "":
|
||||
headers["X-MediaBrowser-Token"] = auth_token
|
||||
|
||||
log.debug("JellyCon Authentication Header: {0}".format(headers))
|
||||
return headers
|
||||
|
||||
@timer
|
||||
def download_url(self, url, suppress=False, post_body=None, method="GET", authenticate=True, headers=None):
|
||||
log.debug("downloadUrl")
|
||||
|
||||
settings = xbmcaddon.Addon()
|
||||
user_details = load_user_details(settings)
|
||||
username = user_details.get("username", "")
|
||||
server = None
|
||||
|
||||
http_timeout = int(settings.getSetting("http_timeout"))
|
||||
|
||||
if authenticate and username == "":
|
||||
return {}
|
||||
|
||||
if settings.getSetting("suppressErrors") == "true":
|
||||
suppress = True
|
||||
|
||||
log.debug("Before: {0}".format(url))
|
||||
|
||||
if url.find("{server}") != -1:
|
||||
server = self.get_server()
|
||||
if server is None:
|
||||
return {}
|
||||
url = url.replace("{server}", server)
|
||||
|
||||
if url.find("{userid}") != -1:
|
||||
userid = self.get_user_id()
|
||||
if not userid:
|
||||
return {}
|
||||
url = url.replace("{userid}", userid)
|
||||
|
||||
if url.find("{ItemLimit}") != -1:
|
||||
show_x_filtered_items = settings.getSetting("show_x_filtered_items")
|
||||
url = url.replace("{ItemLimit}", show_x_filtered_items)
|
||||
|
||||
if url.find("{field_filters}") != -1:
|
||||
filter_string = get_details_string()
|
||||
url = url.replace("{field_filters}", filter_string)
|
||||
|
||||
if url.find("{random_movies}") != -1:
|
||||
home_window = HomeWindow()
|
||||
random_movies = home_window.get_property("random-movies")
|
||||
if not random_movies:
|
||||
return {}
|
||||
url = url.replace("{random_movies}", random_movies)
|
||||
|
||||
log.debug("After: {0}".format(url))
|
||||
|
||||
try:
|
||||
url_bits = urlparse(url.strip())
|
||||
user_name = url_bits.username
|
||||
user_password = url_bits.password
|
||||
|
||||
head = self.get_auth_header(authenticate)
|
||||
|
||||
if user_name and user_password:
|
||||
log.info("Replacing username & Password info")
|
||||
# add basic auth headers
|
||||
user_and_pass = b64encode(b"%s:%s" % (user_name, user_password)).decode("ascii")
|
||||
head["Authorization"] = 'Basic %s' % user_and_pass
|
||||
|
||||
head["User-Agent"] = "JellyCon-" + ClientInformation().get_version()
|
||||
|
||||
http_request = getattr(requests, method.lower())
|
||||
|
||||
if post_body:
|
||||
|
||||
if isinstance(post_body, dict):
|
||||
head["Content-Type"] = "application/json"
|
||||
post_body = json.dumps(post_body)
|
||||
else:
|
||||
head["Content-Type"] = "application/x-www-form-urlencoded"
|
||||
|
||||
log.debug("Content-Type: {0}".format(head["Content-Type"]))
|
||||
log.debug("POST DATA: {0}".format(post_body))
|
||||
|
||||
data = http_request(url, data=post_body, headers=head)
|
||||
else:
|
||||
data = http_request(url, headers=head)
|
||||
|
||||
|
||||
if data.status_code == 200:
|
||||
|
||||
if headers is not None and isinstance(headers, dict):
|
||||
headers.update(data.headers)
|
||||
log.debug("{0}".format(data.json()))
|
||||
|
||||
elif data.status_code >= 400:
|
||||
|
||||
if data.status_code == 401:
|
||||
# remove any saved password
|
||||
m = hashlib.md5()
|
||||
m.update(username)
|
||||
hashed_username = m.hexdigest()
|
||||
log.error("HTTP response error 401 auth error, removing any saved passwords for user: {0}".format(hashed_username))
|
||||
settings.setSetting("saved_user_password_" + hashed_username, "")
|
||||
save_user_details(settings, "", "")
|
||||
|
||||
log.error("HTTP response error for {0}: {1} {2}".format(url, data.status_code, data.content))
|
||||
if suppress is False:
|
||||
xbmcgui.Dialog().notification(string_load(30316),
|
||||
'{}: {}'.format(string_load(30200), data.content),
|
||||
icon="special://home/addons/plugin.video.jellycon/icon.png")
|
||||
try:
|
||||
result = data.json()
|
||||
except:
|
||||
result = {}
|
||||
return result
|
||||
except Exception as msg:
|
||||
log.error("{0}".format(format_exc()))
|
||||
log.error("Unable to connect to {0} : {1}".format(server, msg))
|
||||
if not suppress:
|
||||
xbmcgui.Dialog().notification(string_load(30316),
|
||||
str(msg),
|
||||
icon="special://home/addons/plugin.video.jellycon/icon.png")
|
||||
@@ -90,6 +90,7 @@ import sys
|
||||
import time
|
||||
import errno
|
||||
|
||||
|
||||
class FileLock(object):
|
||||
""" A file locking mechanism that has context-manager support so
|
||||
you can use it in a ``with`` statement. This should be relatively cross
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,28 +1,31 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import xbmcvfs
|
||||
import xbmc
|
||||
import threading
|
||||
import io
|
||||
import base64
|
||||
import re
|
||||
from random import shuffle
|
||||
|
||||
import xbmcvfs
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
import requests
|
||||
from six.moves.BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
|
||||
from six.moves.urllib.parse import urlparse
|
||||
from six import ensure_text
|
||||
|
||||
import threading
|
||||
import requests
|
||||
import io
|
||||
|
||||
from .loghandler import LazyLogger
|
||||
from .datamanager import DataManager
|
||||
from .downloadutils import DownloadUtils
|
||||
from .utils import get_art
|
||||
from .jellyfin import api
|
||||
from .lazylogger import LazyLogger
|
||||
from .item_functions import get_art
|
||||
from .utils import translate_path
|
||||
|
||||
pil_loaded = False
|
||||
try:
|
||||
from PIL import ImageFilter, Image, ImageOps
|
||||
from PIL import Image, ImageOps
|
||||
pil_loaded = True
|
||||
except Exception as err:
|
||||
except ImportError:
|
||||
pil_loaded = False
|
||||
|
||||
PORT_NUMBER = 24276
|
||||
@@ -31,8 +34,8 @@ log = LazyLogger(__name__)
|
||||
|
||||
def get_image_links(url):
|
||||
|
||||
download_utils = DownloadUtils()
|
||||
server = download_utils.get_server()
|
||||
settings = xbmcaddon.Addon()
|
||||
server = settings.getSetting('server_address')
|
||||
if server is None:
|
||||
return []
|
||||
|
||||
@@ -50,8 +53,7 @@ def get_image_links(url):
|
||||
if not re.search('EnableUserData=', url, re.IGNORECASE):
|
||||
url += "&EnableUserData=False"
|
||||
|
||||
data_manager = DataManager()
|
||||
result = data_manager.get_content(url)
|
||||
result = api.get(url)
|
||||
|
||||
items = result.get("Items")
|
||||
if not items:
|
||||
@@ -171,7 +173,7 @@ class HttpImageHandler(BaseHTTPRequestHandler):
|
||||
|
||||
else:
|
||||
|
||||
image_path = xbmc.translatePath("special://home/addons/plugin.video.jellycon/icon.png").decode('utf-8')
|
||||
image_path = translate_path("special://home/addons/plugin.video.jellycon/icon.png").decode('utf-8')
|
||||
self.send_response(200)
|
||||
self.send_header('Content-type', 'image/png')
|
||||
modified = xbmcvfs.Stat(image_path).st_mtime()
|
||||
@@ -187,7 +189,6 @@ class HttpImageHandler(BaseHTTPRequestHandler):
|
||||
|
||||
class HttpImageServerThread(threading.Thread):
|
||||
|
||||
|
||||
def __init__(self):
|
||||
threading.Thread.__init__(self)
|
||||
self.keep_running = True
|
||||
|
||||
@@ -1,32 +1,20 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
from dateutil import tz
|
||||
from six import ensure_text
|
||||
from six.moves.urllib.parse import quote
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
import xbmcgui
|
||||
|
||||
from .utils import get_art, datetime_from_string
|
||||
from .loghandler import LazyLogger
|
||||
from .downloadutils import DownloadUtils
|
||||
from .kodi_utils import HomeWindow
|
||||
from six import ensure_text
|
||||
from .utils import (
|
||||
datetime_from_string, get_art_url, image_url, get_current_datetime
|
||||
)
|
||||
from .lazylogger import LazyLogger
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
kodi_version = int(xbmc.getInfoLabel('System.BuildVersion')[:2])
|
||||
|
||||
addon_instance = xbmcaddon.Addon()
|
||||
addon_path = addon_instance.getAddonInfo('path')
|
||||
PLUGINPATH = xbmc.translatePath(os.path.join(addon_path))
|
||||
|
||||
download_utils = DownloadUtils()
|
||||
home_window = HomeWindow()
|
||||
|
||||
|
||||
class ItemDetails:
|
||||
@@ -220,12 +208,12 @@ def extract_item_info(item, gui_options):
|
||||
media_info["height"] = mediaStream.get("Height")
|
||||
media_info["width"] = mediaStream.get("Width")
|
||||
aspect_ratio = mediaStream.get("AspectRatio")
|
||||
media_info["apect"] = aspect_ratio
|
||||
media_info["aspect"] = aspect_ratio
|
||||
if aspect_ratio and len(aspect_ratio) >= 3:
|
||||
try:
|
||||
aspect_width, aspect_height = aspect_ratio.split(':')
|
||||
media_info["apect_ratio"] = float(aspect_width) / float(aspect_height)
|
||||
except:
|
||||
except: # noqa
|
||||
media_info["apect_ratio"] = 1.85
|
||||
else:
|
||||
media_info["apect_ratio"] = 1.85
|
||||
@@ -262,10 +250,9 @@ def extract_item_info(item, gui_options):
|
||||
person_id = person.get("Id")
|
||||
person_tag = person.get("PrimaryImageTag")
|
||||
if person_tag:
|
||||
person_thumbnail = download_utils.image_url(person_id,
|
||||
"Primary", 0, 400, 400,
|
||||
person_tag,
|
||||
server=gui_options["server"])
|
||||
person_thumbnail = image_url(person_id, "Primary", 0, 400,
|
||||
400, person_tag,
|
||||
server=gui_options["server"])
|
||||
else:
|
||||
person_thumbnail = ""
|
||||
person = {"name": person_name, "role": person_role, "thumbnail": person_thumbnail}
|
||||
@@ -375,9 +362,6 @@ def add_gui_item(url, item_details, display_options, folder=True, default_sort=F
|
||||
else:
|
||||
u = sys.argv[0] + "?item_id=" + url + "&mode=PLAY"
|
||||
|
||||
# Create the ListItem that will be displayed
|
||||
thumb_path = item_details.art["thumb"]
|
||||
|
||||
list_item_name = item_details.name
|
||||
item_type = item_details.item_type.lower()
|
||||
is_video = item_type not in ['musicalbum', 'audio', 'music']
|
||||
@@ -418,20 +402,27 @@ def add_gui_item(url, item_details, display_options, folder=True, default_sort=F
|
||||
end_time = datetime_from_string(item_details.program_end_date)
|
||||
|
||||
duration = (end_time - start_time).total_seconds()
|
||||
time_done = (datetime.now() - start_time).total_seconds()
|
||||
now = get_current_datetime()
|
||||
time_done = (now - start_time).total_seconds()
|
||||
percentage_done = (float(time_done) / float(duration)) * 100.0
|
||||
capped_percentage = int(percentage_done)
|
||||
|
||||
start_time_string = start_time.strftime("%H:%M")
|
||||
end_time_string = end_time.strftime("%H:%M")
|
||||
# Convert dates to local timezone for display
|
||||
local = tz.tzlocal()
|
||||
start_time_string = start_time.astimezone(local).strftime("%H:%M")
|
||||
end_time_string = end_time.astimezone(local).strftime("%H:%M")
|
||||
|
||||
item_details.duration = int(duration)
|
||||
item_details.resume_time = int(time_done)
|
||||
|
||||
list_item_name = (item_details.program_channel_name +
|
||||
" - " + list_item_name +
|
||||
" - " + start_time_string + " to " + end_time_string +
|
||||
" (" + str(int(percentage_done)) + "%)")
|
||||
if item_details.program_channel_name:
|
||||
list_item_name = '{} - {} - {} to {} ({}%)'.format(
|
||||
item_details.program_channel_name, list_item_name,
|
||||
start_time_string, end_time_string, capped_percentage)
|
||||
else:
|
||||
list_item_name = '{} - {} to {} ({}%)'.format(
|
||||
list_item_name, start_time_string, end_time_string,
|
||||
capped_percentage)
|
||||
|
||||
time_info = "Start : " + start_time_string + "\n"
|
||||
time_info += "End : " + end_time_string + "\n"
|
||||
@@ -441,10 +432,7 @@ def add_gui_item(url, item_details, display_options, folder=True, default_sort=F
|
||||
else:
|
||||
item_details.plot = time_info
|
||||
|
||||
if kodi_version > 17:
|
||||
list_item = xbmcgui.ListItem(list_item_name, offscreen=True)
|
||||
else:
|
||||
list_item = xbmcgui.ListItem(list_item_name, iconImage=thumb_path, thumbnailImage=thumb_path)
|
||||
list_item = xbmcgui.ListItem(list_item_name, offscreen=True)
|
||||
|
||||
item_properties = {}
|
||||
|
||||
@@ -471,11 +459,8 @@ def add_gui_item(url, item_details, display_options, folder=True, default_sort=F
|
||||
info_labels = {}
|
||||
|
||||
# add cast
|
||||
if item_details.cast is not None:
|
||||
if kodi_version >= 17:
|
||||
list_item.setCast(item_details.cast)
|
||||
else:
|
||||
info_labels['cast'] = info_labels['castandrole'] = [(cast_member['name'], cast_member['role']) for cast_member in item_details.cast]
|
||||
if item_details.cast:
|
||||
list_item.setCast(item_details.cast)
|
||||
|
||||
info_labels["title"] = list_item_name
|
||||
if item_details.sort_name:
|
||||
@@ -517,6 +502,8 @@ def add_gui_item(url, item_details, display_options, folder=True, default_sort=F
|
||||
mediatype = 'artist'
|
||||
elif item_type == 'audio' or item_type == 'music':
|
||||
mediatype = 'song'
|
||||
elif item_type == 'musicvideo':
|
||||
mediatype = 'musicvideo'
|
||||
|
||||
info_labels["mediatype"] = mediatype
|
||||
|
||||
@@ -584,8 +571,6 @@ def add_gui_item(url, item_details, display_options, folder=True, default_sort=F
|
||||
|
||||
item_properties["TotalSeasons"] = str(item_details.total_seasons)
|
||||
item_properties["TotalEpisodes"] = str(item_details.total_episodes)
|
||||
item_properties["WatchedEpisodes"] = str(item_details.watched_episodes)
|
||||
item_properties["UnWatchedEpisodes"] = str(item_details.unwatched_episodes)
|
||||
item_properties["NumEpisodes"] = str(item_details.number_episodes)
|
||||
|
||||
list_item.setRating("imdb", item_details.community_rating, 0, True)
|
||||
@@ -608,10 +593,89 @@ def add_gui_item(url, item_details, display_options, folder=True, default_sort=F
|
||||
if item_details.baseline_itemname is not None:
|
||||
item_properties["suggested_from_watching"] = item_details.baseline_itemname
|
||||
|
||||
if kodi_version > 17:
|
||||
list_item.setProperties(item_properties)
|
||||
else:
|
||||
for key, value in item_properties.iteritems():
|
||||
list_item.setProperty(key, value)
|
||||
list_item.setProperties(item_properties)
|
||||
|
||||
return u, list_item, folder
|
||||
|
||||
|
||||
def get_art(item, server):
|
||||
|
||||
art = {
|
||||
'thumb': '',
|
||||
'fanart': '',
|
||||
'poster': '',
|
||||
'banner': '',
|
||||
'clearlogo': '',
|
||||
'clearart': '',
|
||||
'discart': '',
|
||||
'landscape': '',
|
||||
'tvshow.fanart': '',
|
||||
'tvshow.poster': '',
|
||||
'tvshow.clearart': '',
|
||||
'tvshow.clearlogo': '',
|
||||
'tvshow.banner': '',
|
||||
'tvshow.landscape': ''
|
||||
}
|
||||
|
||||
image_tags = item.get("ImageTags", {})
|
||||
if image_tags and image_tags.get("Primary"):
|
||||
art['thumb'] = get_art_url(item, "Primary", server=server)
|
||||
|
||||
item_type = item["Type"]
|
||||
|
||||
if item_type == "Genre":
|
||||
art['poster'] = get_art_url(item, "Primary", server=server)
|
||||
elif item_type == "Episode":
|
||||
art['tvshow.poster'] = get_art_url(item, "Primary", parent=True, server=server)
|
||||
art['tvshow.clearart'] = get_art_url(item, "Art", parent=True, server=server)
|
||||
art['clearart'] = get_art_url(item, "Art", parent=True, server=server)
|
||||
art['tvshow.clearlogo'] = get_art_url(item, "Logo", parent=True, server=server)
|
||||
art['clearlogo'] = get_art_url(item, "Logo", parent=True, server=server)
|
||||
art['tvshow.banner'] = get_art_url(item, "Banner", parent=True, server=server)
|
||||
art['banner'] = get_art_url(item, "Banner", parent=True, server=server)
|
||||
art['tvshow.landscape'] = get_art_url(item, "Thumb", parent=True, server=server)
|
||||
art['landscape'] = get_art_url(item, "Thumb", parent=True, server=server)
|
||||
art['tvshow.fanart'] = get_art_url(item, "Backdrop", parent=True, server=server)
|
||||
art['fanart'] = get_art_url(item, "Backdrop", parent=True, server=server)
|
||||
elif item_type == "Season":
|
||||
art['tvshow.poster'] = get_art_url(item, "Primary", parent=True, server=server)
|
||||
art['season.poster'] = get_art_url(item, "Primary", parent=False, server=server)
|
||||
art['poster'] = get_art_url(item, "Primary", parent=False, server=server)
|
||||
art['tvshow.clearart'] = get_art_url(item, "Art", parent=True, server=server)
|
||||
art['clearart'] = get_art_url(item, "Art", parent=True, server=server)
|
||||
art['tvshow.clearlogo'] = get_art_url(item, "Logo", parent=True, server=server)
|
||||
art['clearlogo'] = get_art_url(item, "Logo", parent=True, server=server)
|
||||
art['tvshow.banner'] = get_art_url(item, "Banner", parent=True, server=server)
|
||||
art['season.banner'] = get_art_url(item, "Banner", parent=False, server=server)
|
||||
art['banner'] = get_art_url(item, "Banner", parent=False, server=server)
|
||||
art['tvshow.landscape'] = get_art_url(item, "Thumb", parent=True, server=server)
|
||||
art['season.landscape'] = get_art_url(item, "Thumb", parent=False, server=server)
|
||||
art['landscape'] = get_art_url(item, "Thumb", parent=False, server=server)
|
||||
art['tvshow.fanart'] = get_art_url(item, "Backdrop", parent=True, server=server)
|
||||
art['fanart'] = get_art_url(item, "Backdrop", parent=True, server=server)
|
||||
elif item_type == "Series":
|
||||
art['tvshow.poster'] = get_art_url(item, "Primary", parent=False, server=server)
|
||||
art['poster'] = get_art_url(item, "Primary", parent=False, server=server)
|
||||
art['tvshow.clearart'] = get_art_url(item, "Art", parent=False, server=server)
|
||||
art['clearart'] = get_art_url(item, "Art", parent=False, server=server)
|
||||
art['tvshow.clearlogo'] = get_art_url(item, "Logo", parent=False, server=server)
|
||||
art['clearlogo'] = get_art_url(item, "Logo", parent=False, server=server)
|
||||
art['tvshow.banner'] = get_art_url(item, "Banner", parent=False, server=server)
|
||||
art['banner'] = get_art_url(item, "Banner", parent=False, server=server)
|
||||
art['tvshow.landscape'] = get_art_url(item, "Thumb", parent=False, server=server)
|
||||
art['landscape'] = get_art_url(item, "Thumb", parent=False, server=server)
|
||||
art['tvshow.fanart'] = get_art_url(item, "Backdrop", parent=False, server=server)
|
||||
art['fanart'] = get_art_url(item, "Backdrop", parent=False, server=server)
|
||||
elif item_type == "Movie" or item_type == "BoxSet":
|
||||
art['poster'] = get_art_url(item, "Primary", server=server)
|
||||
art['landscape'] = get_art_url(item, "Thumb", server=server)
|
||||
art['banner'] = get_art_url(item, "Banner", server=server)
|
||||
art['clearlogo'] = get_art_url(item, "Logo", server=server)
|
||||
art['clearart'] = get_art_url(item, "Art", server=server)
|
||||
art['discart'] = get_art_url(item, "Disc", server=server)
|
||||
|
||||
art['fanart'] = get_art_url(item, "Backdrop", server=server)
|
||||
if not art['fanart']:
|
||||
art['fanart'] = get_art_url(item, "Backdrop", parent=True, server=server)
|
||||
|
||||
return art
|
||||
|
||||
196
resources/lib/jellyfin.py
Normal file
196
resources/lib/jellyfin.py
Normal file
@@ -0,0 +1,196 @@
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import json
|
||||
|
||||
import requests
|
||||
import xbmcaddon
|
||||
from kodi_six.utils import py2_decode
|
||||
|
||||
from .utils import get_device_id, get_version, load_user_details
|
||||
from .lazylogger import LazyLogger
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
|
||||
class API:
|
||||
def __init__(self, server=None, user_id=None, token=None):
|
||||
self.server = server
|
||||
self.user_id = user_id
|
||||
self.token = token
|
||||
|
||||
self.settings = xbmcaddon.Addon()
|
||||
|
||||
self.headers = {}
|
||||
self.create_headers()
|
||||
self.verify_cert = settings.getSetting('verify_cert') == 'true'
|
||||
|
||||
def get(self, path):
|
||||
if 'x-mediabrowser-token' not in self.headers or self.token not in self.headers:
|
||||
self.create_headers(True)
|
||||
|
||||
# Fixes initial login where class is initialized before wizard completes
|
||||
if not self.server:
|
||||
self.settings = xbmcaddon.Addon()
|
||||
self.server = self.settings.getSetting('server_address')
|
||||
|
||||
url = '{}{}'.format(self.server, path)
|
||||
|
||||
r = requests.get(url, headers=self.headers, verify=self.verify_cert)
|
||||
try:
|
||||
try:
|
||||
'''
|
||||
The requests library defaults to using simplejson to handle
|
||||
json decoding. On low power devices and using Py3, this is
|
||||
significantly slower than the builtin json library. Skip that
|
||||
and just parse the json ourselves. Fall back to using
|
||||
requests/simplejson if there's a parsing error.
|
||||
'''
|
||||
r.raise_for_status()
|
||||
response_data = json.loads(r.text)
|
||||
except ValueError:
|
||||
response_data = r.json()
|
||||
except: # noqa
|
||||
response_data = {}
|
||||
return response_data
|
||||
|
||||
def post(self, url, payload={}):
|
||||
if 'x-mediabrowser-token' not in self.headers or self.token not in self.headers:
|
||||
self.create_headers(True)
|
||||
|
||||
url = '{}{}'.format(self.server, url)
|
||||
|
||||
r = requests.post(url, json=payload, headers=self.headers, verify=self.verify_cert)
|
||||
try:
|
||||
try:
|
||||
# Much faster on low power devices, see above comment
|
||||
response_data = json.loads(r.text)
|
||||
except ValueError:
|
||||
response_data = r.json()
|
||||
except: # noqa
|
||||
response_data = {}
|
||||
return response_data
|
||||
|
||||
def delete(self, url):
|
||||
if 'x-mediabrowser-token' not in self.headers or self.token not in self.headers:
|
||||
self.create_headers(True)
|
||||
|
||||
url = '{}{}'.format(self.server, url)
|
||||
|
||||
requests.delete(url, headers=self.headers, verify=self.verify_cert)
|
||||
|
||||
def authenticate(self, auth_data):
|
||||
# Always force create fresh headers during authentication
|
||||
self.create_headers(True)
|
||||
response = self.post('/Users/AuthenticateByName', auth_data)
|
||||
token = response.get('AccessToken')
|
||||
if token:
|
||||
self.token = token
|
||||
self.user_id = response.get('User').get('Id')
|
||||
# Create headers again to include auth token
|
||||
self.create_headers()
|
||||
return response
|
||||
else:
|
||||
log.error('Unable to authenticate to Jellyfin server')
|
||||
return {}
|
||||
|
||||
def create_headers(self, force=False):
|
||||
|
||||
# If the headers already exist with an auth token, return unless we're regenerating
|
||||
if self.headers and 'x-mediabrowser-token' in self.headers and force is False:
|
||||
return
|
||||
|
||||
headers = {}
|
||||
device_name = self.settings.getSetting('deviceName')
|
||||
if len(device_name) == 0:
|
||||
device_name = "JellyCon"
|
||||
# Ensure ascii and remove invalid characters
|
||||
device_name = py2_decode(device_name).replace('"', '_').replace(',', '_')
|
||||
device_id = get_device_id()
|
||||
version = get_version()
|
||||
|
||||
authorization = (
|
||||
'MediaBrowser Client="Kodi JellyCon", Device="{device}", '
|
||||
'DeviceId="{device_id}", Version="{version}"'
|
||||
).format(
|
||||
device=device_name,
|
||||
device_id=device_id,
|
||||
version=version
|
||||
)
|
||||
|
||||
headers['x-emby-authorization'] = authorization
|
||||
|
||||
# If we have a valid token, ensure it's included in the headers unless we're regenerating
|
||||
if self.token and force is False:
|
||||
headers['x-mediabrowser-token'] = self.token
|
||||
else:
|
||||
# Check for updated credentials since initialization
|
||||
user_details = load_user_details()
|
||||
token = user_details.get('token')
|
||||
if token:
|
||||
self.token = token
|
||||
headers['x-mediabrowser-token'] = self.token
|
||||
|
||||
# Make headers available to api calls
|
||||
self.headers = headers
|
||||
|
||||
def post_capabilities(self):
|
||||
url = '/Sessions/Capabilities/Full'
|
||||
|
||||
data = {
|
||||
'SupportsMediaControl': True,
|
||||
'PlayableMediaTypes': ["Video", "Audio"],
|
||||
'SupportedCommands': ["MoveUp",
|
||||
"MoveDown",
|
||||
"MoveLeft",
|
||||
"MoveRight",
|
||||
"Select",
|
||||
"Back",
|
||||
"ToggleContextMenu",
|
||||
"ToggleFullscreen",
|
||||
"ToggleOsdMenu",
|
||||
"GoHome",
|
||||
"PageUp",
|
||||
"NextLetter",
|
||||
"GoToSearch",
|
||||
"GoToSettings",
|
||||
"PageDown",
|
||||
"PreviousLetter",
|
||||
"TakeScreenshot",
|
||||
"VolumeUp",
|
||||
"VolumeDown",
|
||||
"ToggleMute",
|
||||
"SendString",
|
||||
"DisplayMessage",
|
||||
"SetAudioStreamIndex",
|
||||
"SetSubtitleStreamIndex",
|
||||
"SetRepeatMode",
|
||||
"Mute",
|
||||
"Unmute",
|
||||
"SetVolume",
|
||||
"PlayNext",
|
||||
"Play",
|
||||
"Playstate",
|
||||
"PlayMediaSource"]
|
||||
}
|
||||
|
||||
self.post(url, data)
|
||||
|
||||
def speedtest(self, test_data_size):
|
||||
self.create_headers()
|
||||
|
||||
url = '{}/playback/bitratetest?size={}'.format(self.server, test_data_size)
|
||||
# Because this needs the stream argument, this doesn't go through self.get()
|
||||
response = requests.get(url, stream=True, headers=self.headers, verify=self.verify_cert)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
settings = xbmcaddon.Addon()
|
||||
user_details = load_user_details()
|
||||
api = API(
|
||||
settings.getSetting('server_address'),
|
||||
user_details.get('user_id'),
|
||||
user_details.get('token')
|
||||
)
|
||||
@@ -1,6 +1,9 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import json
|
||||
|
||||
import xbmc
|
||||
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import sys
|
||||
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
import xbmcplugin
|
||||
import xbmcaddon
|
||||
|
||||
import sys
|
||||
import json
|
||||
|
||||
from .loghandler import LazyLogger
|
||||
from .lazylogger import LazyLogger
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
addon = xbmcaddon.Addon()
|
||||
@@ -37,30 +37,13 @@ class HomeWindow:
|
||||
self.window.clearProperty(key)
|
||||
|
||||
|
||||
def add_menu_directory_item(label, path, folder=True, art=None):
|
||||
li = xbmcgui.ListItem(label, path=path)
|
||||
def add_menu_directory_item(label, path, folder=True, art=None, properties=None):
|
||||
li = xbmcgui.ListItem(label, path=path, offscreen=True)
|
||||
if art is None:
|
||||
art = {}
|
||||
art["thumb"] = addon.getAddonInfo('icon')
|
||||
if properties is not None:
|
||||
li.setProperties(properties)
|
||||
li.setArt(art)
|
||||
|
||||
xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=path, listitem=li, isFolder=folder)
|
||||
|
||||
|
||||
def get_kodi_version():
|
||||
|
||||
json_data = xbmc.executeJSONRPC(
|
||||
'{ "jsonrpc": "2.0", "method": "Application.GetProperties", "params": {"properties": ["version", "name"]}, "id": 1 }')
|
||||
|
||||
result = json.loads(json_data)
|
||||
|
||||
try:
|
||||
result = result.get("result")
|
||||
version_data = result.get("version")
|
||||
version = float(str(version_data.get("major")) + "." + str(version_data.get("minor")))
|
||||
log.debug("Version: {0} - {1}".format(version, version_data))
|
||||
except:
|
||||
version = 0.0
|
||||
log.error("Version Error : RAW Version Data: {0}".format(result))
|
||||
|
||||
return version
|
||||
|
||||
20
resources/lib/lazylogger.py
Normal file
20
resources/lib/lazylogger.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
|
||||
class LazyLogger(object):
|
||||
"""`helper.loghandler.getLogger()` is used everywhere.
|
||||
This class helps avoiding import errors.
|
||||
"""
|
||||
__logger = None
|
||||
__logger_name = None
|
||||
|
||||
def __init__(self, logger_name=None):
|
||||
self.__logger_name = logger_name
|
||||
|
||||
def __getattr__(self, name):
|
||||
if self.__logger is None:
|
||||
from .loghandler import getLogger
|
||||
self.__logger = getLogger(self.__logger_name)
|
||||
return getattr(self.__logger, name)
|
||||
@@ -1,47 +0,0 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
import threading
|
||||
import time
|
||||
|
||||
import xbmc
|
||||
|
||||
from .loghandler import LazyLogger
|
||||
from .widgets import check_for_new_content
|
||||
from .tracking import timer
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
|
||||
class LibraryChangeMonitor(threading.Thread):
|
||||
|
||||
last_library_change_check = 0
|
||||
library_check_triggered = False
|
||||
exit_now = False
|
||||
time_between_checks = 10
|
||||
|
||||
def __init__(self):
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
def stop(self):
|
||||
self.exit_now = True
|
||||
|
||||
@timer
|
||||
def check_for_updates(self):
|
||||
log.debug("Trigger check for updates")
|
||||
self.library_check_triggered = True
|
||||
|
||||
def run(self):
|
||||
log.debug("Library Monitor Started")
|
||||
monitor = xbmc.Monitor()
|
||||
while not self.exit_now and not monitor.abortRequested():
|
||||
|
||||
if self.library_check_triggered and not xbmc.Player().isPlaying():
|
||||
log.debug("Doing new content check")
|
||||
check_for_new_content()
|
||||
self.library_check_triggered = False
|
||||
self.last_library_change_check = time.time()
|
||||
|
||||
if self.exit_now or monitor.waitForAbort(self.time_between_checks):
|
||||
break
|
||||
|
||||
log.debug("Library Monitor Exited")
|
||||
@@ -1,7 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
##################################################################################################
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import os
|
||||
import logging
|
||||
@@ -10,14 +9,11 @@ import traceback
|
||||
|
||||
from six import ensure_text
|
||||
from kodi_six import xbmc, xbmcaddon
|
||||
from six.moves.urllib.parse import urlparse
|
||||
|
||||
##################################################################################################
|
||||
from .utils import translate_path
|
||||
|
||||
__addon__ = xbmcaddon.Addon(id='plugin.video.jellycon')
|
||||
__pluginpath__ = xbmc.translatePath(__addon__.getAddonInfo('path'))
|
||||
|
||||
##################################################################################################
|
||||
__pluginpath__ = translate_path(__addon__.getAddonInfo('path'))
|
||||
|
||||
|
||||
def getLogger(name=None):
|
||||
@@ -46,7 +42,9 @@ class LogHandler(logging.StreamHandler):
|
||||
string = self.format(record)
|
||||
|
||||
# Hide server URL in logs
|
||||
string = string.replace(self.server or "{server}", "{jellyfin-server}")
|
||||
string = string.replace(
|
||||
self.server or "{server}", "{jellyfin-server}"
|
||||
)
|
||||
|
||||
py_version = sys.version_info.major
|
||||
# Log level notation changed in Kodi v19
|
||||
@@ -74,12 +72,17 @@ class LogHandler(logging.StreamHandler):
|
||||
|
||||
class MyFormatter(logging.Formatter):
|
||||
|
||||
def __init__(self, fmt='%(name)s -> %(levelname)s::%(relpath)s:%(lineno)s %(message)s'):
|
||||
def __init__(
|
||||
self,
|
||||
fmt='%(name)s -> %(levelname)s::%(relpath)s:%(lineno)s %(message)s'
|
||||
):
|
||||
logging.Formatter.__init__(self, fmt)
|
||||
|
||||
def format(self, record):
|
||||
if record.pathname:
|
||||
record.pathname = ensure_text(record.pathname, get_filesystem_encoding())
|
||||
record.pathname = ensure_text(
|
||||
record.pathname, get_filesystem_encoding()
|
||||
)
|
||||
|
||||
self._gen_rel_path(record)
|
||||
|
||||
@@ -96,7 +99,10 @@ class MyFormatter(logging.Formatter):
|
||||
o = ensure_text(o, get_filesystem_encoding())
|
||||
|
||||
if o.startswith(' File "'):
|
||||
# If this split can't handle your file names, you should seriously consider renaming your files.
|
||||
"""
|
||||
If this split can't handle your file names,
|
||||
you should seriously consider renaming your files.
|
||||
"""
|
||||
fn = o.split(' File "', 2)[1].split('", line ', 1)[0]
|
||||
rfn = os.path.realpath(fn)
|
||||
if rfn.startswith(_pluginpath_real):
|
||||
@@ -111,22 +117,6 @@ class MyFormatter(logging.Formatter):
|
||||
record.relpath = os.path.relpath(record.pathname, __pluginpath__)
|
||||
|
||||
|
||||
class LazyLogger(object):
|
||||
"""`helper.loghandler.getLogger()` is used everywhere.
|
||||
This class helps avoiding import errors.
|
||||
"""
|
||||
__logger = None
|
||||
__logger_name = None
|
||||
|
||||
def __init__(self, logger_name=None):
|
||||
self.__logger_name = logger_name
|
||||
|
||||
def __getattr__(self, name):
|
||||
if self.__logger is None:
|
||||
self.__logger = getLogger(self.__logger_name)
|
||||
return getattr(self.__logger, name)
|
||||
|
||||
|
||||
def get_filesystem_encoding():
|
||||
enc = sys.getfilesystemencoding()
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
89
resources/lib/monitors.py
Normal file
89
resources/lib/monitors.py
Normal file
@@ -0,0 +1,89 @@
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import threading
|
||||
import time
|
||||
|
||||
import xbmc
|
||||
|
||||
from .functions import show_menu
|
||||
from .lazylogger import LazyLogger
|
||||
from .widgets import check_for_new_content
|
||||
from .tracking import timer
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
|
||||
class ContextMonitor(threading.Thread):
|
||||
|
||||
stop_thread = False
|
||||
|
||||
def run(self):
|
||||
|
||||
item_id = None
|
||||
log.debug("ContextMonitor Thread Started")
|
||||
|
||||
while not xbmc.Monitor().abortRequested() and not self.stop_thread:
|
||||
|
||||
visibility_check = (
|
||||
"Window.IsActive(fullscreenvideo) | "
|
||||
"Window.IsActive(visualisation)"
|
||||
)
|
||||
if xbmc.getCondVisibility(visibility_check):
|
||||
xbmc.sleep(1000)
|
||||
else:
|
||||
if xbmc.getCondVisibility("Window.IsVisible(contextmenu)"):
|
||||
if item_id:
|
||||
xbmc.executebuiltin("Dialog.Close(contextmenu,true)")
|
||||
params = {}
|
||||
params["item_id"] = item_id
|
||||
show_menu(params)
|
||||
|
||||
container_id = xbmc.getInfoLabel("System.CurrentControlID")
|
||||
item_id = xbmc.getInfoLabel(
|
||||
"Container({}).ListItem.Property(id)".format(container_id)
|
||||
)
|
||||
|
||||
xbmc.sleep(100)
|
||||
|
||||
log.debug("ContextMonitor Thread Exited")
|
||||
|
||||
def stop_monitor(self):
|
||||
log.debug("ContextMonitor Stop Called")
|
||||
self.stop_thread = True
|
||||
|
||||
|
||||
class LibraryChangeMonitor(threading.Thread):
|
||||
|
||||
last_library_change_check = 0
|
||||
library_check_triggered = False
|
||||
exit_now = False
|
||||
time_between_checks = 10
|
||||
|
||||
def __init__(self):
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
def stop(self):
|
||||
self.exit_now = True
|
||||
|
||||
@timer
|
||||
def check_for_updates(self):
|
||||
log.debug("Trigger check for updates")
|
||||
self.library_check_triggered = True
|
||||
|
||||
def run(self):
|
||||
log.debug("Library Monitor Started")
|
||||
monitor = xbmc.Monitor()
|
||||
while not self.exit_now and not monitor.abortRequested():
|
||||
|
||||
if self.library_check_triggered and not xbmc.Player().isPlaying():
|
||||
log.debug("Doing new content check")
|
||||
check_for_new_content()
|
||||
self.library_check_triggered = False
|
||||
self.last_library_change_check = time.time()
|
||||
|
||||
if self.exit_now or monitor.waitForAbort(self.time_between_checks):
|
||||
break
|
||||
|
||||
log.debug("Library Monitor Exited")
|
||||
@@ -1,13 +1,14 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
import xbmcgui
|
||||
|
||||
from .loghandler import LazyLogger
|
||||
from .lazylogger import LazyLogger
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
|
||||
class PictureViewer(xbmcgui.WindowXMLDialog):
|
||||
picture_url = None
|
||||
action_exitkeys_id = None
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,16 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import json
|
||||
import os
|
||||
import threading
|
||||
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
import xbmcaddon
|
||||
|
||||
from .loghandler import LazyLogger
|
||||
from .play_utils import send_event_notification
|
||||
from .kodi_utils import HomeWindow
|
||||
from .lazylogger import LazyLogger
|
||||
from .dialogs import PlayNextDialog
|
||||
from .utils import translate_path
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
@@ -72,7 +72,7 @@ class PlayNextService(threading.Thread):
|
||||
|
||||
settings = xbmcaddon.Addon()
|
||||
plugin_path = settings.getAddonInfo('path')
|
||||
plugin_path_real = xbmc.translatePath(os.path.join(plugin_path))
|
||||
plugin_path_real = translate_path(os.path.join(plugin_path))
|
||||
|
||||
play_next_dialog = PlayNextDialog("PlayNextDialog.xml", plugin_path_real, "default", "720p")
|
||||
play_next_dialog.set_episode_info(next_episode)
|
||||
@@ -94,70 +94,6 @@ class PlayNextService(threading.Thread):
|
||||
if xbmc.Monitor().waitForAbort(1):
|
||||
break
|
||||
|
||||
def stop_servcie(self):
|
||||
def stop_service(self):
|
||||
log.debug("PlayNextService Stop Called")
|
||||
self.stop_thread = True
|
||||
|
||||
|
||||
class PlayNextDialog(xbmcgui.WindowXMLDialog):
|
||||
|
||||
action_exitkeys_id = None
|
||||
episode_info = None
|
||||
play_called = False
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
log.debug("PlayNextDialog: __init__")
|
||||
xbmcgui.WindowXML.__init__(self, *args, **kwargs)
|
||||
|
||||
def onInit(self):
|
||||
log.debug("PlayNextDialog: onInit")
|
||||
self.action_exitkeys_id = [10, 13]
|
||||
|
||||
index = self.episode_info.get("IndexNumber", -1)
|
||||
series_name = self.episode_info.get("SeriesName")
|
||||
next_epp_name = "Episode %02d - (%s)" % (index, self.episode_info.get("Name", "n/a"))
|
||||
|
||||
series_label = self.getControl(3011)
|
||||
series_label.setLabel(series_name)
|
||||
|
||||
series_label = self.getControl(3012)
|
||||
series_label.setLabel(next_epp_name)
|
||||
|
||||
def onFocus(self, control_id):
|
||||
pass
|
||||
|
||||
def doAction(self, action_id):
|
||||
pass
|
||||
|
||||
def onMessage(self, message):
|
||||
log.debug("PlayNextDialog: onMessage: {0}".format(message))
|
||||
|
||||
def onAction(self, action):
|
||||
|
||||
if action.getId() == 10: # ACTION_PREVIOUS_MENU
|
||||
self.close()
|
||||
elif action.getId() == 92: # ACTION_NAV_BACK
|
||||
self.close()
|
||||
else:
|
||||
log.debug("PlayNextDialog: onAction: {0}".format(action.getId()))
|
||||
|
||||
def onClick(self, control_id):
|
||||
if control_id == 3013:
|
||||
log.debug("PlayNextDialog: Play Next Episode")
|
||||
self.play_called
|
||||
self.close()
|
||||
next_item_id = self.episode_info.get("Id")
|
||||
log.debug("Playing Next Episode: {0}".format(next_item_id))
|
||||
play_info = {}
|
||||
play_info["item_id"] = next_item_id
|
||||
play_info["auto_resume"] = "-1"
|
||||
play_info["force_transcode"] = False
|
||||
send_event_notification("jellycon_play_action", play_info)
|
||||
elif control_id == 3014:
|
||||
self.close()
|
||||
|
||||
def set_episode_info(self, info):
|
||||
self.episode_info = info
|
||||
|
||||
def get_play_called(self):
|
||||
return self.play_called
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
import xbmcgui
|
||||
|
||||
from .loghandler import LazyLogger
|
||||
from .translation import string_load
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
|
||||
class ResumeDialog(xbmcgui.WindowXMLDialog):
|
||||
resumePlay = -1
|
||||
resumeTimeStamp = ""
|
||||
action_exitkeys_id = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs)
|
||||
log.debug("ResumeDialog INITIALISED")
|
||||
|
||||
def onInit(self):
|
||||
self.action_exitkeys_id = [10, 13]
|
||||
self.getControl(3010).setLabel(self.resumeTimeStamp)
|
||||
self.getControl(3011).setLabel(string_load(30237))
|
||||
|
||||
def onFocus(self, controlId):
|
||||
pass
|
||||
|
||||
def doAction(self, actionID):
|
||||
pass
|
||||
|
||||
def onClick(self, controlID):
|
||||
|
||||
if controlID == 3010:
|
||||
self.resumePlay = 0
|
||||
self.close()
|
||||
if controlID == 3011:
|
||||
self.resumePlay = 1
|
||||
self.close()
|
||||
|
||||
def setResumeTime(self, timeStamp):
|
||||
self.resumeTimeStamp = timeStamp
|
||||
|
||||
def getResumeAction(self):
|
||||
return self.resumePlay
|
||||
@@ -1,57 +0,0 @@
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
|
||||
from .loghandler import LazyLogger
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
|
||||
class SafeDeleteDialog(xbmcgui.WindowXMLDialog):
|
||||
|
||||
confirm = False
|
||||
message = "Demo Message"
|
||||
heading = "Demo Heading"
|
||||
action_exitkeys_id = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
log.debug("SafeDeleteDialog: __init__")
|
||||
xbmcgui.WindowXML.__init__(self, *args, **kwargs)
|
||||
|
||||
def onInit(self):
|
||||
log.debug("SafeDeleteDialog: onInit")
|
||||
self.action_exitkeys_id = [10, 13]
|
||||
|
||||
message_control = self.getControl(3)
|
||||
message_control.setText(self.message)
|
||||
|
||||
message_control = self.getControl(4)
|
||||
message_control.setLabel(self.heading)
|
||||
|
||||
def onFocus(self, controlId):
|
||||
pass
|
||||
|
||||
def doAction(self, actionID):
|
||||
pass
|
||||
|
||||
def onMessage(self, message):
|
||||
log.debug("SafeDeleteDialog: onMessage: {0}".format(message))
|
||||
|
||||
def onAction(self, action):
|
||||
|
||||
if action.getId() == 10: # ACTION_PREVIOUS_MENU
|
||||
self.close()
|
||||
elif action.getId() == 92: # ACTION_NAV_BACK
|
||||
self.close()
|
||||
else:
|
||||
log.debug("SafeDeleteDialog: onAction: {0}".format(action.getId()))
|
||||
|
||||
def onClick(self, controlID):
|
||||
if controlID == 1:
|
||||
self.confirm = True
|
||||
self.close()
|
||||
elif controlID == 2:
|
||||
self.confirm = False
|
||||
self.close()
|
||||
@@ -1,27 +1,22 @@
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import socket
|
||||
import json
|
||||
from six.moves.urllib.parse import urlparse
|
||||
import requests
|
||||
import ssl
|
||||
import time
|
||||
import hashlib
|
||||
from datetime import datetime
|
||||
|
||||
import xbmcaddon
|
||||
import xbmcgui
|
||||
import xbmc
|
||||
from six import ensure_binary
|
||||
from kodi_six.utils import py2_decode
|
||||
|
||||
from .kodi_utils import HomeWindow
|
||||
from .downloadutils import DownloadUtils, save_user_details, load_user_details
|
||||
from .loghandler import LazyLogger
|
||||
from .translation import string_load
|
||||
from .utils import datetime_from_string
|
||||
from .clientinfo import ClientInformation
|
||||
from .jellyfin import API
|
||||
from .lazylogger import LazyLogger
|
||||
from .utils import (
|
||||
datetime_from_string, translate_string, save_user_details,
|
||||
load_user_details, get_current_datetime, get_saved_users
|
||||
)
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
@@ -33,26 +28,15 @@ def check_connection_speed():
|
||||
log.debug("check_connection_speed")
|
||||
|
||||
settings = xbmcaddon.Addon()
|
||||
verify_cert = settings.getSetting('verify_cert') == 'true'
|
||||
http_timeout = int(settings.getSetting("http_timeout"))
|
||||
speed_test_data_size = int(settings.getSetting("speed_test_data_size"))
|
||||
test_data_size = speed_test_data_size * 1000000
|
||||
user_details = load_user_details()
|
||||
|
||||
du = DownloadUtils()
|
||||
server = du.get_server()
|
||||
|
||||
url = server + "/playback/bitratetest?size=%s" % test_data_size
|
||||
|
||||
head = du.get_auth_header(True)
|
||||
head["User-Agent"] = "JellyCon-" + ClientInformation().get_version()
|
||||
|
||||
request_details = {
|
||||
"stream": True,
|
||||
"headers": head
|
||||
}
|
||||
|
||||
if not verify_cert:
|
||||
request_details["verify"] = False
|
||||
api = API(
|
||||
settings.getSetting('server_address'),
|
||||
user_details.get('user_id'),
|
||||
user_details.get('token')
|
||||
)
|
||||
|
||||
progress_dialog = xbmcgui.DialogProgress()
|
||||
message = 'Testing with {0} MB of data'.format(speed_test_data_size)
|
||||
@@ -60,8 +44,7 @@ def check_connection_speed():
|
||||
start_time = time.time()
|
||||
|
||||
log.debug("Starting Connection Speed Test")
|
||||
|
||||
response = requests.get(url, **request_details)
|
||||
response = api.speedtest(test_data_size)
|
||||
|
||||
last_percentage_done = 0
|
||||
total_data_read = 0
|
||||
@@ -97,38 +80,12 @@ def check_connection_speed():
|
||||
return speed
|
||||
|
||||
|
||||
def check_safe_delete_available():
|
||||
log.debug("check_safe_delete_available")
|
||||
|
||||
du = DownloadUtils()
|
||||
result = du.download_url("{server}/Plugins")
|
||||
if result:
|
||||
log.debug("Server Plugin List: {0}".format(result))
|
||||
|
||||
safe_delete_found = False
|
||||
for plugin in result:
|
||||
if plugin["Name"] == "Safe Delete":
|
||||
safe_delete_found = True
|
||||
break
|
||||
|
||||
log.debug("Safe Delete Plugin Available: {0}".format(safe_delete_found))
|
||||
home_window = HomeWindow()
|
||||
if safe_delete_found:
|
||||
home_window.set_property("safe_delete_plugin_available", "true")
|
||||
else:
|
||||
home_window.clear_property("safe_delete_plugin_available")
|
||||
|
||||
else:
|
||||
log.debug("Error getting server plugin list")
|
||||
|
||||
|
||||
def get_server_details():
|
||||
log.debug("Getting Server Details from Network")
|
||||
servers = []
|
||||
|
||||
message = b"who is JellyfinServer?"
|
||||
multi_group = ("<broadcast>", 7359)
|
||||
# multi_group = ("127.0.0.1", 7359)
|
||||
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.settimeout(4.0)
|
||||
@@ -139,22 +96,21 @@ def get_server_details():
|
||||
log.debug("Sending UDP Data: {0}".format(message))
|
||||
|
||||
progress = xbmcgui.DialogProgress()
|
||||
progress.create('{} : {}'.format(__addon_name__, string_load(30373)))
|
||||
progress.update(0, string_load(30374))
|
||||
progress.create('{} : {}'.format(__addon_name__, translate_string(30373)))
|
||||
progress.update(0, translate_string(30374))
|
||||
xbmc.sleep(1000)
|
||||
server_count = 0
|
||||
|
||||
# while True:
|
||||
try:
|
||||
sock.sendto(message, multi_group)
|
||||
while True:
|
||||
try:
|
||||
server_count += 1
|
||||
progress.update(server_count * 10, '{}: {}'.format(string_load(30375), server_count))
|
||||
progress.update(server_count * 10, '{}: {}'.format(translate_string(30375), server_count))
|
||||
xbmc.sleep(1000)
|
||||
data, addr = sock.recvfrom(1024)
|
||||
servers.append(json.loads(data))
|
||||
except:
|
||||
except: # noqa
|
||||
break
|
||||
except Exception as e:
|
||||
log.error("UPD Discovery Error: {0}".format(e))
|
||||
@@ -169,18 +125,17 @@ def check_server(force=False, change_user=False, notify=False):
|
||||
log.debug("checkServer Called")
|
||||
|
||||
settings = xbmcaddon.Addon()
|
||||
server_url = ""
|
||||
something_changed = False
|
||||
du = DownloadUtils()
|
||||
|
||||
# Initialize api object
|
||||
api = API()
|
||||
|
||||
if force is False:
|
||||
# if not forcing use server details from settings
|
||||
svr = du.get_server()
|
||||
if svr is not None:
|
||||
server_url = svr
|
||||
api.server = settings.getSetting('server_address')
|
||||
|
||||
# if the server is not set then try to detect it
|
||||
if server_url == "":
|
||||
if not api.server:
|
||||
|
||||
# scan for local server
|
||||
server_info = get_server_details()
|
||||
@@ -190,7 +145,7 @@ def check_server(force=False, change_user=False, notify=False):
|
||||
|
||||
server_list = []
|
||||
for server in server_info:
|
||||
server_item = xbmcgui.ListItem(server.get("Name", string_load(30063)))
|
||||
server_item = xbmcgui.ListItem(server.get("Name", translate_string(30063)))
|
||||
sub_line = server.get("Address")
|
||||
server_item.setLabel2(sub_line)
|
||||
server_item.setProperty("address", server.get("Address"))
|
||||
@@ -199,234 +154,280 @@ def check_server(force=False, change_user=False, notify=False):
|
||||
server_list.append(server_item)
|
||||
|
||||
if len(server_list) > 0:
|
||||
return_index = xbmcgui.Dialog().select('{} : {}'.format(__addon_name__, string_load(30166)),
|
||||
return_index = xbmcgui.Dialog().select('{} : {}'.format(__addon_name__, translate_string(30166)),
|
||||
server_list,
|
||||
useDetails=True)
|
||||
if return_index != -1:
|
||||
server_url = server_info[return_index]["Address"]
|
||||
api.server = server_info[return_index]["Address"]
|
||||
|
||||
if not server_url:
|
||||
return_index = xbmcgui.Dialog().yesno(__addon_name__, '{}\n{}'.format(string_load(30282), string_load(30370)))
|
||||
if not api.server:
|
||||
return_index = xbmcgui.Dialog().yesno(__addon_name__, '{}\n{}'.format(translate_string(30282), translate_string(30370)))
|
||||
if not return_index:
|
||||
xbmc.executebuiltin("ActivateWindow(Home)")
|
||||
return
|
||||
|
||||
while True:
|
||||
kb = xbmc.Keyboard()
|
||||
kb.setHeading(string_load(30372))
|
||||
if server_url:
|
||||
kb.setDefault(server_url)
|
||||
kb.setHeading(translate_string(30372))
|
||||
if api.server:
|
||||
kb.setDefault(api.server)
|
||||
else:
|
||||
kb.setDefault("http://<server address>:8096")
|
||||
kb.setDefault("http://")
|
||||
kb.doModal()
|
||||
if kb.isConfirmed():
|
||||
server_url = kb.getText()
|
||||
api.server = kb.getText()
|
||||
else:
|
||||
xbmc.executebuiltin("ActivateWindow(Home)")
|
||||
return
|
||||
|
||||
public_lookup_url = "%s/System/Info/Public?format=json" % (server_url)
|
||||
|
||||
log.debug("Testing_Url: {0}".format(public_lookup_url))
|
||||
progress = xbmcgui.DialogProgress()
|
||||
progress.create('{} : {}'.format(__addon_name__, string_load(30376)))
|
||||
progress.update(0, string_load(30377))
|
||||
result = du.download_url(public_lookup_url, authenticate=False)
|
||||
progress.create('{} : {}'.format(__addon_name__, translate_string(30376)))
|
||||
progress.update(0, translate_string(30377))
|
||||
result = api.get('/System/Info/Public')
|
||||
progress.close()
|
||||
|
||||
if result:
|
||||
xbmcgui.Dialog().ok('{} : {}'.format(__addon_name__, string_load(30167)),
|
||||
server_url)
|
||||
xbmcgui.Dialog().ok('{} : {}'.format(__addon_name__, translate_string(30167)),
|
||||
api.server)
|
||||
break
|
||||
else:
|
||||
return_index = xbmcgui.Dialog().yesno('{} : {}'.format(__addon_name__, string_load(30135)),
|
||||
server_url,
|
||||
string_load(30371))
|
||||
return_index = xbmcgui.Dialog().yesno('{} : {}'.format(__addon_name__, translate_string(30135)),
|
||||
api.server,
|
||||
translate_string(30371))
|
||||
if not return_index:
|
||||
xbmc.executebuiltin("ActivateWindow(Home)")
|
||||
return
|
||||
|
||||
log.debug("Selected server: {0}".format(server_url))
|
||||
settings.setSetting("server_address", server_url)
|
||||
log.debug("Selected server: {0}".format(api.server))
|
||||
settings.setSetting("server_address", api.server)
|
||||
something_changed = True
|
||||
|
||||
# do we need to change the user
|
||||
user_details = load_user_details(settings)
|
||||
current_username = user_details.get("username", "")
|
||||
current_username = py2_decode(current_username)
|
||||
current_username = settings.getSetting('username')
|
||||
user_details = load_user_details()
|
||||
home_window = HomeWindow()
|
||||
home_window.set_property('user_name', current_username)
|
||||
|
||||
# if asked or we have no current user then show user selection screen
|
||||
if something_changed or change_user or len(current_username) == 0:
|
||||
if something_changed or change_user or len(current_username) == 0 or not user_details:
|
||||
|
||||
# stop playback when switching users
|
||||
xbmc.Player().stop()
|
||||
du = DownloadUtils()
|
||||
|
||||
# get a list of users
|
||||
log.debug("Getting user list")
|
||||
result = du.download_url(server_url + "/Users/Public?format=json", authenticate=False)
|
||||
# Initialize auth variable
|
||||
auth = {}
|
||||
|
||||
log.debug("jsonData: {0}".format(py2_decode(result)))
|
||||
|
||||
selected_id = -1
|
||||
users = []
|
||||
for user in result:
|
||||
config = user.get("Configuration")
|
||||
if config is not None:
|
||||
if config.get("IsHidden", False) is False:
|
||||
name = user.get("Name")
|
||||
admin = user.get("Policy", {}).get("IsAdministrator", False)
|
||||
|
||||
time_ago = ""
|
||||
last_active = user.get("LastActivityDate")
|
||||
if last_active:
|
||||
last_active_date = datetime_from_string(last_active)
|
||||
log.debug("LastActivityDate: {0}".format(last_active_date))
|
||||
ago = datetime.now() - last_active_date
|
||||
log.debug("LastActivityDate: {0}".format(ago))
|
||||
days = divmod(ago.seconds, 86400)
|
||||
hours = divmod(days[1], 3600)
|
||||
minutes = divmod(hours[1], 60)
|
||||
log.debug("LastActivityDate: {0} {1} {2}".format(days[0], hours[0], minutes[0]))
|
||||
if days[0]:
|
||||
time_ago += " %sd" % days[0]
|
||||
if hours[0]:
|
||||
time_ago += " %sh" % hours[0]
|
||||
if minutes[0]:
|
||||
time_ago += " %sm" % minutes[0]
|
||||
time_ago = time_ago.strip()
|
||||
if not time_ago:
|
||||
time_ago = "Active: now"
|
||||
else:
|
||||
time_ago = "Active: %s ago" % time_ago
|
||||
log.debug("LastActivityDate: {0}".format(time_ago))
|
||||
|
||||
user_item = xbmcgui.ListItem(name)
|
||||
user_image = du.get_user_artwork(user, 'Primary')
|
||||
if not user_image:
|
||||
user_image = "DefaultUser.png"
|
||||
art = {"Thumb": user_image}
|
||||
user_item.setArt(art)
|
||||
user_item.setLabel2("TEST")
|
||||
|
||||
sub_line = time_ago
|
||||
|
||||
if user.get("HasPassword", False) is True:
|
||||
sub_line += ", Password"
|
||||
user_item.setProperty("secure", "true")
|
||||
|
||||
m = hashlib.md5()
|
||||
m.update(ensure_binary(name))
|
||||
hashed_username = m.hexdigest()
|
||||
saved_password = settings.getSetting("saved_user_password_" + hashed_username)
|
||||
if saved_password:
|
||||
sub_line += ": Saved"
|
||||
|
||||
else:
|
||||
user_item.setProperty("secure", "false")
|
||||
|
||||
if admin:
|
||||
sub_line += ", Admin"
|
||||
else:
|
||||
sub_line += ", User"
|
||||
|
||||
user_item.setProperty("manual", "false")
|
||||
user_item.setLabel2(sub_line)
|
||||
users.append(user_item)
|
||||
|
||||
if current_username == name:
|
||||
selected_id = len(users) - 1
|
||||
|
||||
if current_username:
|
||||
selection_title = string_load(30180) + " (" + current_username + ")"
|
||||
else:
|
||||
selection_title = string_load(30180)
|
||||
|
||||
# add manual login
|
||||
user_item = xbmcgui.ListItem(string_load(30365))
|
||||
art = {"Thumb": "DefaultUser.png"}
|
||||
user_item.setArt(art)
|
||||
user_item.setLabel2(string_load(30366))
|
||||
user_item.setProperty("secure", "true")
|
||||
user_item.setProperty("manual", "true")
|
||||
users.append(user_item)
|
||||
|
||||
return_value = xbmcgui.Dialog().select(selection_title,
|
||||
users,
|
||||
preselect=selected_id,
|
||||
autoclose=20000,
|
||||
useDetails=True)
|
||||
|
||||
if return_value > -1 and return_value != selected_id:
|
||||
# Check if quick connect is active on the server, initiate connection
|
||||
quick = api.get('/QuickConnect/Initiate')
|
||||
code = quick.get('Code')
|
||||
secret = quick.get('Secret')
|
||||
users, user_selection = user_select(api, current_username, code)
|
||||
|
||||
if user_selection > -1:
|
||||
# The user made a selection in the dialog
|
||||
something_changed = True
|
||||
selected_user = users[return_value]
|
||||
secured = selected_user.getProperty("secure") == "true"
|
||||
manual = selected_user.getProperty("manual") == "true"
|
||||
selected_user_name = selected_user.getLabel()
|
||||
selected_user = users[user_selection]
|
||||
quick_connect = selected_user.getProperty("quickconnect") == "true"
|
||||
count = 0
|
||||
if quick_connect:
|
||||
# Try to authenticate to server with secret code 10 times
|
||||
while count < 10:
|
||||
log.debug('Checking for quick connect auth: attempt {}'.format(count))
|
||||
check = api.get('/QuickConnect/Connect?secret={}'.format(secret))
|
||||
if check.get('Authenticated'):
|
||||
break
|
||||
count += 1
|
||||
xbmc.sleep(1000)
|
||||
|
||||
log.debug("Selected User Name: {0} : {1}".format(return_value, selected_user_name))
|
||||
auth = api.post('/Users/AuthenticateWithQuickConnect',
|
||||
{'secret': secret})
|
||||
|
||||
if manual:
|
||||
kb = xbmc.Keyboard()
|
||||
kb.setHeading(string_load(30005))
|
||||
if current_username:
|
||||
kb.setDefault(current_username)
|
||||
kb.doModal()
|
||||
if kb.isConfirmed():
|
||||
selected_user_name = kb.getText()
|
||||
log.debug("Manual entered username: {0}".format(selected_user_name))
|
||||
# If authentication was successful, save the username
|
||||
if auth:
|
||||
selected_user_name = auth['User'].get('Name')
|
||||
else:
|
||||
return
|
||||
# Login failed, we don't want to change anything
|
||||
something_changed = False
|
||||
log.info("There was an error logging in with quick connect")
|
||||
|
||||
if secured:
|
||||
# we need a password, check the settings first
|
||||
m = hashlib.md5()
|
||||
m.update(selected_user_name.encode())
|
||||
hashed_username = m.hexdigest()
|
||||
saved_password = settings.getSetting("saved_user_password_" + hashed_username)
|
||||
allow_password_saving = settings.getSetting("allow_password_saving") == "true"
|
||||
else:
|
||||
selected_user_name = selected_user.getLabel()
|
||||
secured = selected_user.getProperty("secure") == "true"
|
||||
manual = selected_user.getProperty("manual") == "true"
|
||||
|
||||
# if not saving passwords but have a saved ask to clear it
|
||||
if not allow_password_saving and saved_password:
|
||||
clear_password = xbmcgui.Dialog().yesno(string_load(30368), string_load(30369))
|
||||
if clear_password:
|
||||
settings.setSetting("saved_user_password_" + hashed_username, "")
|
||||
|
||||
if saved_password:
|
||||
log.debug("Saving username and password: {0}".format(selected_user_name))
|
||||
log.debug("Using stored password for user: {0}".format(hashed_username))
|
||||
save_user_details(settings, selected_user_name, saved_password)
|
||||
|
||||
else:
|
||||
# If using a manual login, ask for username
|
||||
if manual:
|
||||
kb = xbmc.Keyboard()
|
||||
kb.setHeading(string_load(30006))
|
||||
kb.setHiddenInput(True)
|
||||
kb.setHeading(translate_string(30005))
|
||||
if current_username:
|
||||
kb.setDefault(current_username)
|
||||
kb.doModal()
|
||||
if kb.isConfirmed():
|
||||
log.debug("Saving username and password: {0}".format(selected_user_name))
|
||||
save_user_details(settings, selected_user_name, kb.getText())
|
||||
selected_user_name = kb.getText()
|
||||
log.debug("Manual entered username: {0}".format(selected_user_name))
|
||||
else:
|
||||
return
|
||||
|
||||
# should we save the password
|
||||
if allow_password_saving:
|
||||
save_password = xbmcgui.Dialog().yesno(string_load(30363), string_load(30364))
|
||||
if save_password:
|
||||
log.debug("Saving password for fast user switching: {0}".format(hashed_username))
|
||||
settings.setSetting("saved_user_password_" + hashed_username, kb.getText())
|
||||
else:
|
||||
log.debug("Saving username with no password: {0}".format(selected_user_name))
|
||||
save_user_details(settings, selected_user_name, "")
|
||||
home_window.set_property('user_name', selected_user_name)
|
||||
settings.setSetting('username', selected_user_name)
|
||||
user_details = load_user_details()
|
||||
|
||||
if not user_details:
|
||||
# Ask for password if user has one
|
||||
password = ''
|
||||
if secured and not user_details.get('token'):
|
||||
kb = xbmc.Keyboard()
|
||||
kb.setHeading(translate_string(30006))
|
||||
kb.setHiddenInput(True)
|
||||
kb.doModal()
|
||||
if kb.isConfirmed():
|
||||
password = kb.getText()
|
||||
|
||||
auth_payload = {'username': selected_user_name, 'pw': password}
|
||||
auth = api.authenticate(auth_payload)
|
||||
if not auth:
|
||||
# Login failed, we don't want to change anything
|
||||
something_changed = False
|
||||
log.info('There was an error logging in with user {}'.format(selected_user_name))
|
||||
xbmcgui.Dialog().ok(__addon_name__, translate_string(30446))
|
||||
|
||||
if something_changed:
|
||||
home_window = HomeWindow()
|
||||
home_window.clear_property("userid")
|
||||
home_window.clear_property("AccessToken")
|
||||
home_window.clear_property("userimage")
|
||||
home_window.clear_property("jellycon_widget_reload")
|
||||
du = DownloadUtils()
|
||||
du.authenticate()
|
||||
du.get_user_id()
|
||||
if auth:
|
||||
token = auth.get('AccessToken')
|
||||
user_id = auth.get('User').get('Id')
|
||||
else:
|
||||
token = user_details.get('token')
|
||||
user_id = user_details.get('user_id')
|
||||
save_user_details(selected_user_name, user_id, token)
|
||||
xbmc.executebuiltin("ActivateWindow(Home)")
|
||||
if "estuary_jellycon" in xbmc.getSkinDir():
|
||||
xbmc.executebuiltin("SetFocus(9000, 0, absolute)")
|
||||
xbmc.executebuiltin("ReloadSkin()")
|
||||
|
||||
|
||||
def user_select(api, current_username, code):
|
||||
'''
|
||||
Display user selection screen
|
||||
'''
|
||||
# Retrieve list of public users from server
|
||||
public = api.get('/Users/Public')
|
||||
|
||||
# Get list of saved users
|
||||
saved_users = get_saved_users()
|
||||
|
||||
# Combine public and saved users
|
||||
for user in saved_users:
|
||||
name = user.get('Name')
|
||||
# Check if saved user is in public list
|
||||
if name not in [x.get('Name', '') for x in public]:
|
||||
# If saved user is not already in list, add it
|
||||
public.append(user)
|
||||
|
||||
# Build user display
|
||||
selected_id = -1
|
||||
users = []
|
||||
# If quick connect is active, make it the first entry
|
||||
if code:
|
||||
user_item = xbmcgui.ListItem(code)
|
||||
user_image = "DefaultUser.png"
|
||||
art = {"Thumb": user_image}
|
||||
user_item.setArt(art)
|
||||
user_item.setLabel2(translate_string(30443))
|
||||
user_item.setProperty('quickconnect', "true")
|
||||
users.append(user_item)
|
||||
|
||||
for user in public:
|
||||
user_item = create_user_listitem(api.server, user)
|
||||
if user_item:
|
||||
users.append(user_item)
|
||||
name = user.get("Name")
|
||||
|
||||
# Highlight currently logged in user
|
||||
if current_username == name:
|
||||
selected_id = len(users) - 1
|
||||
|
||||
if current_username:
|
||||
selection_title = translate_string(30180) + " (" + current_username + ")"
|
||||
else:
|
||||
selection_title = translate_string(30180)
|
||||
|
||||
# Add manual login item
|
||||
user_item = xbmcgui.ListItem(translate_string(30365))
|
||||
art = {"Thumb": "DefaultUser.png"}
|
||||
user_item.setArt(art)
|
||||
user_item.setLabel2(translate_string(30366))
|
||||
user_item.setProperty("secure", "true")
|
||||
user_item.setProperty("manual", "true")
|
||||
users.append(user_item)
|
||||
|
||||
user_selection = xbmcgui.Dialog().select(
|
||||
selection_title,
|
||||
users,
|
||||
preselect=selected_id,
|
||||
autoclose=60000,
|
||||
useDetails=True)
|
||||
|
||||
return (users, user_selection)
|
||||
|
||||
|
||||
def create_user_listitem(server, user):
|
||||
'''
|
||||
Create a user listitem for the user selection screen
|
||||
'''
|
||||
config = user.get("Configuration")
|
||||
now = get_current_datetime()
|
||||
if config is not None:
|
||||
name = user.get("Name")
|
||||
time_ago = ""
|
||||
last_active = user.get("LastActivityDate")
|
||||
# Calculate how long it's been since the user was last active
|
||||
if last_active:
|
||||
last_active_date = datetime_from_string(last_active)
|
||||
ago = now - last_active_date
|
||||
# Check days
|
||||
if ago.days > 0:
|
||||
time_ago += ' {}d'.format(ago.days)
|
||||
# Check minutes
|
||||
if ago.seconds > 60:
|
||||
hours = 0
|
||||
# Check hours
|
||||
if ago.seconds > 3600:
|
||||
hours = int(ago.seconds/3600)
|
||||
time_ago += ' {}h'.format(hours)
|
||||
minutes = int((ago.seconds - (hours * 3600)) / 60)
|
||||
time_ago += ' {}m'.format(minutes)
|
||||
time_ago = time_ago.strip()
|
||||
if not time_ago:
|
||||
time_ago = "Active: now"
|
||||
else:
|
||||
time_ago = "Active: {} ago".format(time_ago)
|
||||
|
||||
user_item = xbmcgui.ListItem(name)
|
||||
|
||||
# If the user doesn't have a profile image, user the default
|
||||
if 'PrimaryImageTag' not in user:
|
||||
user_image = "DefaultUser.png"
|
||||
else:
|
||||
user_id = user.get('Id')
|
||||
tag = user.get('PrimaryImageTag')
|
||||
user_image = '{}/Users/{}/Images/Primary?Format=original&tag={}'.format(
|
||||
server, user_id, tag
|
||||
)
|
||||
|
||||
art = {"Thumb": user_image}
|
||||
user_item.setArt(art)
|
||||
|
||||
sub_line = time_ago
|
||||
|
||||
if user.get("HasPassword", False) is True:
|
||||
user_item.setProperty("secure", "true")
|
||||
else:
|
||||
user_item.setProperty("secure", "false")
|
||||
|
||||
user_item.setProperty("manual", "false")
|
||||
user_item.setLabel2(sub_line)
|
||||
|
||||
return user_item
|
||||
return None
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import sys
|
||||
|
||||
import xbmcgui
|
||||
import xbmcplugin
|
||||
import xbmcaddon
|
||||
|
||||
from .downloadutils import DownloadUtils
|
||||
from .loghandler import LazyLogger
|
||||
from .utils import get_art
|
||||
from .datamanager import DataManager
|
||||
from .jellyfin import api
|
||||
from .lazylogger import LazyLogger
|
||||
from .item_functions import get_art
|
||||
from .utils import load_user_details
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
@@ -16,25 +20,26 @@ def show_server_sessions():
|
||||
log.debug("showServerSessions Called")
|
||||
|
||||
handle = int(sys.argv[1])
|
||||
download_utils = DownloadUtils()
|
||||
data_manager = DataManager()
|
||||
|
||||
url = "{server}/Users/{userid}"
|
||||
results = data_manager.get_content(url)
|
||||
user_details = load_user_details()
|
||||
url = "/Users/{}".format(user_details.get('user_id'))
|
||||
results = api.get(url)
|
||||
|
||||
is_admin = results.get("Policy", {}).get("IsAdministrator", False)
|
||||
if not is_admin:
|
||||
xbmcplugin.endOfDirectory(handle, cacheToDisc=False)
|
||||
return
|
||||
|
||||
url = "{server}/Sessions"
|
||||
results = data_manager.get_content(url)
|
||||
url = "/Sessions"
|
||||
results = api.get(url)
|
||||
log.debug("session_info: {0}".format(results))
|
||||
|
||||
if results is None:
|
||||
return
|
||||
|
||||
list_items = []
|
||||
settings = xbmcaddon.Addon()
|
||||
server = settings.getSetting('server_address')
|
||||
for session in results:
|
||||
device_name = session.get("DeviceName", "na")
|
||||
user_name = session.get("UserName", "na")
|
||||
@@ -45,10 +50,10 @@ def show_server_sessions():
|
||||
now_playing = session.get("NowPlayingItem", None)
|
||||
transcoding_info = session.get("TranscodingInfo", None)
|
||||
|
||||
session_info = user_name + " - " + client_name
|
||||
session_info = "{} - {}".format(user_name, client_name)
|
||||
user_session_details = ""
|
||||
|
||||
percenatge_played = 0
|
||||
percentage_played = 0
|
||||
position_ticks = 0
|
||||
runtime = 0
|
||||
play_method = "na"
|
||||
@@ -59,42 +64,54 @@ def show_server_sessions():
|
||||
|
||||
art = {}
|
||||
if now_playing:
|
||||
server = download_utils.get_server()
|
||||
art = get_art(now_playing, server)
|
||||
|
||||
runtime = now_playing.get("RunTimeTicks", 0)
|
||||
if position_ticks > 0 and runtime > 0:
|
||||
percenatge_played = (position_ticks / float(runtime)) * 100.0
|
||||
percenatge_played = int(percenatge_played)
|
||||
percentage_played = (position_ticks / float(runtime)) * 100.0
|
||||
percentage_played = int(percentage_played)
|
||||
|
||||
session_info += " (" + now_playing.get("Name", "na") + " " + str(percenatge_played) + "%)"
|
||||
user_session_details += now_playing.get("Name", "na") + " " + str(percenatge_played) + "%" + "\n"
|
||||
session_info += " {} {}%".format(
|
||||
now_playing.get("Name", "na"), percentage_played
|
||||
)
|
||||
user_session_details += "{} {}%\n".format(
|
||||
now_playing.get("Name", "na"), percentage_played
|
||||
)
|
||||
|
||||
else:
|
||||
session_info += " (idle)"
|
||||
user_session_details += "Idle" + "\n"
|
||||
user_session_details += "Idle\n"
|
||||
|
||||
transcoding_details = ""
|
||||
if transcoding_info:
|
||||
if not transcoding_info.get("IsVideoDirect", None):
|
||||
transcoding_details += "Video:" + transcoding_info.get("VideoCodec", "") + ":" + str(transcoding_info.get("Width", 0)) + "x" + str(transcoding_info.get("Height", 0)) + "\n"
|
||||
transcoding_details += "Video:{}:{}x{}\n".format(
|
||||
transcoding_info.get("VideoCodec", ""),
|
||||
transcoding_info.get("Width", 0),
|
||||
transcoding_info.get("Height", 0)
|
||||
)
|
||||
else:
|
||||
transcoding_details += "Video:direct\n"
|
||||
|
||||
if not transcoding_info.get("IsAudioDirect", None):
|
||||
transcoding_details += "Audio:" + transcoding_info.get("AudioCodec", "") + ":" + str(transcoding_info.get("AudioChannels", 0)) + "\n"
|
||||
transcoding_details += "Audio:{}:{}\n".format(
|
||||
transcoding_info.get("AudioCodec", ""),
|
||||
transcoding_info.get("AudioChannels", 0)
|
||||
)
|
||||
else:
|
||||
transcoding_details += "Audio:direct\n"
|
||||
|
||||
transcoding_details += "Bitrate:" + str(transcoding_info.get("Bitrate", 0)) + "\n"
|
||||
transcoding_details += "Bitrate:{}\n".format(
|
||||
transcoding_info.get("Bitrate", 0)
|
||||
)
|
||||
|
||||
list_item = xbmcgui.ListItem(label=session_info)
|
||||
list_item.setArt(art)
|
||||
|
||||
user_session_details += device_name + "(" + client_version + ")\n"
|
||||
user_session_details += client_name + "\n"
|
||||
user_session_details += play_method + "\n"
|
||||
user_session_details += transcoding_details + "\n"
|
||||
user_session_details += "{}({})\n".format(device_name, client_version)
|
||||
user_session_details += "{}\n".format(client_name)
|
||||
user_session_details += "{}\n".format(play_method)
|
||||
user_session_details += "{}\n".format(transcoding_details)
|
||||
|
||||
info_labels = {}
|
||||
info_labels["duration"] = str(runtime / 10000000)
|
||||
@@ -104,7 +121,7 @@ def show_server_sessions():
|
||||
|
||||
list_item.setProperty('TotalTime', str(runtime / 10000000))
|
||||
list_item.setProperty('ResumeTime', str(position_ticks / 10000000))
|
||||
list_item.setProperty("complete_percentage", str(percenatge_played))
|
||||
list_item.setProperty("complete_percentage", str(percentage_played))
|
||||
|
||||
item_tuple = ("", list_item, False)
|
||||
list_items.append(item_tuple)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import os
|
||||
import xml.etree.ElementTree as ET
|
||||
@@ -9,19 +10,21 @@ import xbmcgui
|
||||
import xbmcvfs
|
||||
|
||||
from .jsonrpc import JsonRpc, get_value, set_value
|
||||
from .loghandler import LazyLogger
|
||||
from .lazylogger import LazyLogger
|
||||
from .utils import translate_path, kodi_version
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
ver = xbmc.getInfoLabel('System.BuildVersion')[:2]
|
||||
|
||||
|
||||
def clone_default_skin():
|
||||
xbmc.executebuiltin("Dialog.Close(all,true)")
|
||||
xbmc.executebuiltin("ActivateWindow(Home)")
|
||||
|
||||
response = xbmcgui.Dialog().yesno("JellyCon Skin Cloner",
|
||||
"This will clone the default Estuary Kodi skin and add JellyCon functionality to it.",
|
||||
"Do you want to continue?")
|
||||
response = xbmcgui.Dialog().yesno(
|
||||
"JellyCon Skin Cloner",
|
||||
("This will clone the default Estuary Kodi skin and"
|
||||
"add JellyCon functionality to it."),
|
||||
"Do you want to continue?")
|
||||
if not response:
|
||||
return
|
||||
|
||||
@@ -49,7 +52,7 @@ def walk_path(root_path, relative_path, all_files):
|
||||
def clone_skin():
|
||||
log.debug("Cloning Estuary Skin")
|
||||
|
||||
kodi_path = xbmc.translatePath("special://xbmc")
|
||||
kodi_path = translate_path("special://xbmc")
|
||||
kodi_skin_source = os.path.join(kodi_path, "addons", "skin.estuary")
|
||||
log.debug("Kodi Skin Source: {0}".format(kodi_skin_source))
|
||||
|
||||
@@ -61,8 +64,10 @@ def clone_skin():
|
||||
for found in all_files:
|
||||
log.debug("Found Path: {0}".format(found))
|
||||
|
||||
kodi_home_path = xbmc.translatePath("special://home")
|
||||
kodi_skin_destination = os.path.join(kodi_home_path, "addons", "skin.estuary_jellycon")
|
||||
kodi_home_path = translate_path("special://home")
|
||||
kodi_skin_destination = os.path.join(
|
||||
kodi_home_path, "addons", "skin.estuary_jellycon"
|
||||
)
|
||||
log.debug("Kodi Skin Destination: {0}".format(kodi_skin_destination))
|
||||
|
||||
# copy all skin files (clone)
|
||||
@@ -70,7 +75,7 @@ def clone_skin():
|
||||
total = len(all_files)
|
||||
for skin_file in all_files:
|
||||
percentage_done = int(float(count) / float(total) * 100.0)
|
||||
pdialog.update(percentage_done, "%s" % skin_file)
|
||||
pdialog.update(percentage_done, skin_file)
|
||||
|
||||
source = os.path.join(kodi_skin_source, skin_file)
|
||||
destination = os.path.join(kodi_skin_destination, skin_file)
|
||||
@@ -89,9 +94,11 @@ def clone_skin():
|
||||
addon_tree.write(addon_xml_path)
|
||||
|
||||
# get jellycon path
|
||||
jellycon_path = os.path.join(kodi_home_path, "addons", "plugin.video.jellycon")
|
||||
jellycon_path = os.path.join(
|
||||
kodi_home_path, "addons", "plugin.video.jellycon"
|
||||
)
|
||||
|
||||
log.debug("Major Version: {0}".format(ver))
|
||||
log.debug("Major Version: {0}".format(kodi_version()))
|
||||
|
||||
file_list = ["Home.xml",
|
||||
"Includes_Home.xml",
|
||||
@@ -101,7 +108,10 @@ def clone_skin():
|
||||
|
||||
# Copy customized skin files from our addon into cloned skin
|
||||
for file_name in file_list:
|
||||
source = os.path.join(jellycon_path, "resources", "skins", "skin.estuary", ver, "xml", file_name)
|
||||
source = os.path.join(
|
||||
jellycon_path, "resources", "skins", "skin.estuary",
|
||||
str(kodi_version), "xml", file_name
|
||||
)
|
||||
destination = os.path.join(kodi_skin_destination, "xml", file_name)
|
||||
xbmcvfs.copy(source, destination)
|
||||
|
||||
@@ -110,7 +120,10 @@ def clone_skin():
|
||||
pdialog.close()
|
||||
del pdialog
|
||||
|
||||
response = xbmcgui.Dialog().yesno("JellyCon Skin Cloner", "Do you want to switch to the new cloned skin?")
|
||||
response = xbmcgui.Dialog().yesno(
|
||||
"JellyCon Skin Cloner",
|
||||
"Do you want to switch to the new cloned skin?"
|
||||
)
|
||||
if not response:
|
||||
return
|
||||
|
||||
@@ -121,16 +134,19 @@ def clone_skin():
|
||||
result = JsonRpc('Addons.SetAddonEnabled').execute(params)
|
||||
log.debug("Addons.SetAddonEnabled : {0}".format(result))
|
||||
|
||||
log.debug("SkinCloner : Current Skin : " + get_value("lookandfeel.skin"))
|
||||
log.debug("SkinCloner : Current Skin : {}".format(
|
||||
get_value("lookandfeel.skin"))
|
||||
)
|
||||
set_result = set_value("lookandfeel.skin", "skin.estuary_jellycon")
|
||||
log.debug("Save Setting : lookandfeel.skin : {0}".format(set_result))
|
||||
log.debug("SkinCloner : Current Skin : " + get_value("lookandfeel.skin"))
|
||||
log.debug("SkinCloner : Current Skin : {}".format(
|
||||
get_value("lookandfeel.skin"))
|
||||
)
|
||||
|
||||
|
||||
def update_kodi_settings():
|
||||
log.debug("Settings Kodi Settings")
|
||||
|
||||
# set_value("screensaver.mode", "script.screensaver.logoff")
|
||||
set_value("videoplayer.seekdelay", 0)
|
||||
set_value("filelists.showparentdiritems", False)
|
||||
set_value("filelists.showaddsourcebuttons", False)
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import sys
|
||||
import functools
|
||||
import time
|
||||
from .loghandler import LazyLogger
|
||||
|
||||
from .lazylogger import LazyLogger
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
@@ -28,6 +30,8 @@ def timer(func):
|
||||
data = args[1]
|
||||
elif func.__name__ == "main_entry_point" and len(sys.argv) > 2:
|
||||
data = sys.argv[2]
|
||||
log.info("timing_data|{0}|{1}|{2}|{3}".format(func.__name__, started, ended, data))
|
||||
log.info("timing_data|{0}|{1}|{2}|{3}".format(
|
||||
func.__name__, started, ended, data)
|
||||
)
|
||||
return value
|
||||
return wrapper
|
||||
|
||||
@@ -1,249 +0,0 @@
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
from six.moves.urllib.parse import quote, unquote
|
||||
import encodings
|
||||
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
|
||||
from .loghandler import LazyLogger
|
||||
from .datamanager import DataManager
|
||||
|
||||
from .translation import string_load
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
dataManager = DataManager()
|
||||
|
||||
details_string = 'EpisodeCount,SeasonCount,Path,Etag,MediaStreams'
|
||||
icon = xbmc.translatePath('special://home/addons/plugin.video.jellycon/icon.png')
|
||||
|
||||
|
||||
def not_found(content_string):
|
||||
xbmcgui.Dialog().notification('JellyCon', '{}: {}'.format(string_load(30305), content_string), icon=icon, sound=False)
|
||||
|
||||
|
||||
def playback_starting(content_string):
|
||||
xbmcgui.Dialog().notification('JellyCon', '{}: {}'.format(string_load(30306), content_string), icon=icon, sound=False)
|
||||
|
||||
|
||||
def search(item_type, query):
|
||||
content_url = ('{server}/Search/Hints?searchTerm=' + query +
|
||||
'&IncludeItemTypes=' + item_type +
|
||||
'&UserId={userid}'
|
||||
'&StartIndex=0' +
|
||||
'&Limit=25' +
|
||||
'&IncludePeople=false&IncludeMedia=true&IncludeGenres=false&IncludeStudios=false&IncludeArtists=false')
|
||||
|
||||
result = dataManager.get_content(content_url)
|
||||
return result
|
||||
|
||||
|
||||
def get_items(video_type, item_id=None, parent_id=None):
|
||||
content_url = None
|
||||
result = dict()
|
||||
|
||||
if video_type == 'season':
|
||||
content_url = ('{server}/Shows/' + item_id +
|
||||
'/Seasons'
|
||||
'?userId={userid}' +
|
||||
'&Fields=' + details_string +
|
||||
'&format=json')
|
||||
|
||||
elif video_type == 'movie' or video_type == 'episode':
|
||||
content_url = ('{server}/Users/{userid}/items' +
|
||||
'?ParentId=' + parent_id +
|
||||
'&IsVirtualUnAired=false' +
|
||||
'&IsMissing=false' +
|
||||
'&Fields=' + details_string +
|
||||
'&format=json')
|
||||
|
||||
if content_url:
|
||||
result = dataManager.get_content(content_url)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def get_item(item_id):
|
||||
result = dataManager.get_content('{server}/Users/{userid}/Items/' + item_id + '?Fields=ProviderIds&format=json')
|
||||
return result
|
||||
|
||||
|
||||
def get_imdb_id(item_id):
|
||||
item = get_item(item_id)
|
||||
imdb = item.get('ProviderIds', {}).get('Imdb')
|
||||
return imdb
|
||||
|
||||
|
||||
def get_season_id(parent_id, season):
|
||||
season_items = get_items('season', parent_id)
|
||||
season_items = season_items.get('Items')
|
||||
|
||||
if season_items is None:
|
||||
season_items = []
|
||||
|
||||
for season_item in season_items:
|
||||
if season_item.get('IndexNumber') == int(season):
|
||||
season_id = season_item.get('Id')
|
||||
return season_id
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def get_episode_id(parent_id, episode):
|
||||
episode_items = get_items('episode', parent_id=parent_id)
|
||||
episode_items = episode_items.get('Items')
|
||||
|
||||
if episode_items is None:
|
||||
episode_items = []
|
||||
|
||||
for episode_item in episode_items:
|
||||
if episode_item.get('IndexNumber') == int(episode):
|
||||
episode_id = episode_item.get('Id')
|
||||
return episode_id
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def get_match(item_type, title, year, imdb_id):
|
||||
query = quote(title)
|
||||
|
||||
results = search(item_type, query=query)
|
||||
results = results.get('SearchHints')
|
||||
if results is None:
|
||||
results = []
|
||||
log.debug('SearchHints jsonData: {0}'.format(results))
|
||||
|
||||
potential_matches = []
|
||||
|
||||
for item in results:
|
||||
name = item.get('Name')
|
||||
production_year = item.get('ProductionYear')
|
||||
if (name == title and int(year) == production_year) or (int(year) == production_year):
|
||||
potential_matches.append(item)
|
||||
|
||||
log.debug('Potential matches: {0}'.format(potential_matches))
|
||||
|
||||
for item in potential_matches:
|
||||
item_imdb_id = get_imdb_id(item.get('ItemId'))
|
||||
if item_imdb_id == imdb_id:
|
||||
log.debug('Found match: {0}'.format(item))
|
||||
return item
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def entry_point(parameters):
|
||||
item_type = None
|
||||
action = parameters.get('action', None)
|
||||
video_type = parameters.get('video_type', None)
|
||||
|
||||
title = unquote(parameters.get('title', ''))
|
||||
|
||||
year = parameters.get('year', '')
|
||||
episode = parameters.get('episode', '')
|
||||
season = parameters.get('season', '')
|
||||
imdb_id = parameters.get('imdb_id', '')
|
||||
|
||||
if video_type == 'show' or video_type == 'season' or video_type == 'episode':
|
||||
item_type = 'Series'
|
||||
elif video_type == 'movie':
|
||||
item_type = 'Movie'
|
||||
|
||||
if not item_type:
|
||||
return
|
||||
|
||||
match = get_match(item_type, title, year, imdb_id)
|
||||
|
||||
if not match:
|
||||
title_search_word = ''
|
||||
title_words = title.split(' ')
|
||||
|
||||
for word in title_words:
|
||||
if len(word) > len(title_search_word):
|
||||
title_search_word = word
|
||||
|
||||
title_search_word = title_search_word.replace(':', '')
|
||||
|
||||
if title_search_word:
|
||||
match = get_match(item_type, title_search_word, year, imdb_id)
|
||||
|
||||
str_season = str(season)
|
||||
if len(str_season) == 1:
|
||||
str_season = '0' + str_season
|
||||
str_episode = str(episode)
|
||||
if len(str_episode) == 1:
|
||||
str_episode = '0' + str_episode
|
||||
|
||||
if action == 'play':
|
||||
play_item_id = None
|
||||
|
||||
if video_type == 'movie':
|
||||
if match:
|
||||
play_item_id = match.get('ItemId')
|
||||
|
||||
if not play_item_id:
|
||||
not_found('{title} ({year})'.format(title=title, year=year))
|
||||
|
||||
elif video_type == 'episode':
|
||||
if not season or not episode:
|
||||
return
|
||||
|
||||
if match:
|
||||
item_id = match.get('ItemId')
|
||||
season_id = get_season_id(item_id, season)
|
||||
|
||||
if season_id:
|
||||
episode_id = get_episode_id(season_id, episode)
|
||||
if episode_id:
|
||||
play_item_id = episode_id
|
||||
|
||||
if not play_item_id:
|
||||
not_found('{title} ({year}) - S{season}E{episode}'.format(title=title, year=year, season=str_season, episode=str_episode))
|
||||
|
||||
if play_item_id:
|
||||
if video_type == 'episode':
|
||||
playback_starting('{title} ({year}) - S{season}E{episode}'.format(title=title, year=year, season=str_season, episode=str_episode))
|
||||
else:
|
||||
playback_starting('{title} ({year})'.format(title=title, year=year))
|
||||
xbmc.executebuiltin('RunPlugin(plugin://plugin.video.jellycon/?mode=PLAY&item_id={item_id})'.format(item_id=play_item_id))
|
||||
|
||||
elif action == 'open':
|
||||
url = media_type = None
|
||||
|
||||
if video_type == 'show':
|
||||
if match:
|
||||
item_id = match.get('ItemId')
|
||||
media_type = 'series'
|
||||
url = ('{server}/Shows/' + item_id +
|
||||
'/Seasons'
|
||||
'?userId={userid}' +
|
||||
'&Fields=' + details_string +
|
||||
'&format=json')
|
||||
|
||||
if not url:
|
||||
not_found('{title} ({year})'.format(title=title, year=year))
|
||||
|
||||
elif video_type == 'season':
|
||||
if not season:
|
||||
return
|
||||
|
||||
if match:
|
||||
item_id = match.get('ItemId')
|
||||
season_id = get_season_id(item_id, season)
|
||||
|
||||
if season_id:
|
||||
media_type = 'episodes'
|
||||
|
||||
url = ('{server}/Users/{userid}/items' +
|
||||
'?ParentId=' + season_id +
|
||||
'&IsVirtualUnAired=false' +
|
||||
'&IsMissing=false' +
|
||||
'&Fields=' + details_string +
|
||||
'&format=json')
|
||||
|
||||
if not url:
|
||||
not_found('{title} ({year}) - S{season}'.format(title=title, year=year, season=str_season))
|
||||
|
||||
if url and media_type:
|
||||
xbmc.executebuiltin('ActivateWindow(Videos, plugin://plugin.video.jellycon/?mode=GET_CONTENT&url={url}&media_type={media_type})'.format(url=quote(url), media_type=media_type))
|
||||
@@ -1,16 +0,0 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
import xbmcaddon
|
||||
from .loghandler import LazyLogger
|
||||
from kodi_six.utils import py2_encode
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
addon = xbmcaddon.Addon()
|
||||
|
||||
|
||||
def string_load(string_id):
|
||||
try:
|
||||
return py2_encode(addon.getLocalizedString(string_id))
|
||||
except Exception as e:
|
||||
log.error('Failed String Load: {0} ({1})', string_id, e)
|
||||
return str(string_id)
|
||||
@@ -1,191 +1,60 @@
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
import xbmcaddon
|
||||
import xbmc
|
||||
import xbmcvfs
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import sys
|
||||
import binascii
|
||||
import string
|
||||
import random
|
||||
import json
|
||||
import base64
|
||||
import time
|
||||
import math
|
||||
from datetime import datetime
|
||||
import calendar
|
||||
import os
|
||||
import hashlib
|
||||
import re
|
||||
from six import ensure_text, ensure_binary
|
||||
from datetime import datetime
|
||||
from uuid import uuid4
|
||||
|
||||
import requests
|
||||
from dateutil import tz
|
||||
import xbmcaddon
|
||||
import xbmc
|
||||
import xbmcvfs
|
||||
from kodi_six.utils import py2_encode, py2_decode
|
||||
from six import ensure_text, ensure_binary, text_type
|
||||
from six.moves.urllib.parse import urlencode
|
||||
|
||||
from .downloadutils import DownloadUtils
|
||||
from .loghandler import LazyLogger
|
||||
from .clientinfo import ClientInformation
|
||||
from .lazylogger import LazyLogger
|
||||
from .kodi_utils import HomeWindow
|
||||
|
||||
# hack to get datetime strptime loaded
|
||||
throwaway = time.strptime('20110101', '%Y%m%d')
|
||||
|
||||
# define our global download utils
|
||||
downloadUtils = DownloadUtils()
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
|
||||
def get_jellyfin_url(base_url, params):
|
||||
def kodi_version():
|
||||
# Kodistubs returns empty string, causing Python 3 tests to choke on int()
|
||||
# TODO: Make Kodistubs version configurable for testing purposes
|
||||
if sys.version_info.major == 2:
|
||||
default_versionstring = "18"
|
||||
else:
|
||||
default_versionstring = "19.1 (19.1.0) Git:20210509-85e05228b4"
|
||||
|
||||
version_string = xbmc.getInfoLabel(
|
||||
'System.BuildVersion') or default_versionstring
|
||||
return int(version_string.split(' ', 1)[0].split('.', 1)[0])
|
||||
|
||||
|
||||
def get_jellyfin_url(path, params):
|
||||
params["format"] = "json"
|
||||
url_params = urlencode(params)
|
||||
# Filthy hack until I get around to reworking the network flow
|
||||
# It relies on {thing} strings in downloadutils.py
|
||||
url_params = url_params.replace('%7B', '{').replace('%7D', '}')
|
||||
return base_url + "?" + url_params
|
||||
|
||||
|
||||
###########################################################################
|
||||
class PlayUtils:
|
||||
|
||||
@staticmethod
|
||||
def get_play_url(media_source, play_session_id):
|
||||
log.debug("get_play_url - media_source: {0}", media_source)
|
||||
|
||||
# check if strm file Container
|
||||
if media_source.get('Container') == 'strm':
|
||||
log.debug("Detected STRM Container")
|
||||
playurl, listitem_props = PlayUtils().get_strm_details(media_source)
|
||||
if playurl is None:
|
||||
log.debug("Error, no strm content")
|
||||
return None, None, None
|
||||
else:
|
||||
return playurl, "0", listitem_props
|
||||
|
||||
# get all the options
|
||||
addon_settings = xbmcaddon.Addon()
|
||||
server = downloadUtils.get_server()
|
||||
use_https = addon_settings.getSetting('protocol') == "1"
|
||||
verify_cert = addon_settings.getSetting('verify_cert') == 'true'
|
||||
allow_direct_file_play = addon_settings.getSetting('allow_direct_file_play') == 'true'
|
||||
|
||||
can_direct_play = media_source["SupportsDirectPlay"]
|
||||
can_direct_stream = media_source["SupportsDirectStream"]
|
||||
can_transcode = media_source["SupportsTranscoding"]
|
||||
container = media_source["Container"]
|
||||
|
||||
playurl = None
|
||||
playback_type = None
|
||||
|
||||
# check if file can be directly played
|
||||
if allow_direct_file_play and can_direct_play:
|
||||
direct_path = media_source["Path"]
|
||||
direct_path = direct_path.replace("\\", "/")
|
||||
direct_path = direct_path.strip()
|
||||
|
||||
# handle DVD structure
|
||||
if container == "dvd":
|
||||
direct_path = direct_path + "/VIDEO_TS/VIDEO_TS.IFO"
|
||||
elif container == "bluray":
|
||||
direct_path = direct_path + "/BDMV/index.bdmv"
|
||||
|
||||
if direct_path.startswith("//"):
|
||||
direct_path = "smb://" + direct_path[2:]
|
||||
|
||||
log.debug("playback_direct_path: {0}".format(direct_path))
|
||||
|
||||
if xbmcvfs.exists(direct_path):
|
||||
playurl = direct_path
|
||||
playback_type = "0"
|
||||
|
||||
# check if file can be direct streamed/played
|
||||
if (can_direct_stream or can_direct_play) and playurl is None:
|
||||
item_id = media_source.get('Id')
|
||||
playurl = ("%s/Videos/%s/stream" +
|
||||
"?static=true" +
|
||||
"&PlaySessionId=%s" +
|
||||
"&MediaSourceId=%s")
|
||||
playurl = playurl % (server, item_id, play_session_id, item_id)
|
||||
if use_https and not verify_cert:
|
||||
playurl += "|verifypeer=false"
|
||||
playback_type = "1"
|
||||
|
||||
# check is file can be transcoded
|
||||
if can_transcode and playurl is None:
|
||||
item_id = media_source.get('Id')
|
||||
client_info = ClientInformation()
|
||||
device_id = client_info.get_device_id()
|
||||
user_token = downloadUtils.authenticate()
|
||||
playback_bitrate = addon_settings.getSetting("force_max_stream_bitrate")
|
||||
bitrate = int(playback_bitrate) * 1000
|
||||
playback_max_width = addon_settings.getSetting("playback_max_width")
|
||||
audio_codec = addon_settings.getSetting("audio_codec")
|
||||
audio_playback_bitrate = addon_settings.getSetting("audio_playback_bitrate")
|
||||
audio_bitrate = int(audio_playback_bitrate) * 1000
|
||||
audio_max_channels = addon_settings.getSetting("audio_max_channels")
|
||||
playback_video_force_8 = addon_settings.getSetting("playback_video_force_8") == "true"
|
||||
|
||||
transcode_params = {
|
||||
"MediaSourceId": item_id,
|
||||
"DeviceId": device_id,
|
||||
"PlaySessionId": play_session_id,
|
||||
"api_key": user_token,
|
||||
"SegmentContainer": "ts",
|
||||
"VideoCodec": "h264",
|
||||
"VideoBitrate": bitrate,
|
||||
"MaxWidth": playback_max_width,
|
||||
"AudioCodec": audio_codec,
|
||||
"TranscodingMaxAudioChannels": audio_max_channels,
|
||||
"AudioBitrate": audio_bitrate
|
||||
}
|
||||
if playback_video_force_8:
|
||||
transcode_params.update({"MaxVideoBitDepth": "8"})
|
||||
|
||||
transcode_path = urlencode(transcode_params)
|
||||
|
||||
playurl = "%s/Videos/%s/master.m3u8?%s" % (server, item_id, transcode_path)
|
||||
|
||||
if use_https and not verify_cert:
|
||||
playurl += "|verifypeer=false"
|
||||
|
||||
playback_type = "2"
|
||||
|
||||
return playurl, playback_type, []
|
||||
|
||||
@staticmethod
|
||||
def get_strm_details(media_source):
|
||||
playurl = None
|
||||
listitem_props = []
|
||||
|
||||
contents = media_source.get('Path').encode('utf-8') # contains contents of strm file with linebreaks
|
||||
|
||||
line_break = '\r'
|
||||
if '\r\n' in contents:
|
||||
line_break = '\r\n'
|
||||
elif '\n' in contents:
|
||||
line_break = '\n'
|
||||
|
||||
lines = contents.split(line_break)
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
log.debug("STRM Line: {0}".format(line))
|
||||
if line.startswith('#KODIPROP:'):
|
||||
match = re.search('#KODIPROP:(?P<item_property>[^=]+?)=(?P<property_value>.+)', line)
|
||||
if match:
|
||||
item_property = match.group('item_property')
|
||||
property_value = match.group('property_value')
|
||||
log.debug("STRM property found: {0} value: {1}".format(item_property, property_value))
|
||||
listitem_props.append((item_property, property_value))
|
||||
else:
|
||||
log.debug("STRM #KODIPROP incorrect format")
|
||||
elif line.startswith('#'):
|
||||
# unrecognized, treat as comment
|
||||
log.debug("STRM unrecognized line identifier, ignored")
|
||||
elif line != '':
|
||||
playurl = line
|
||||
log.debug("STRM playback url found")
|
||||
|
||||
log.debug("Playback URL: {0} ListItem Properties: {1}".format(playurl, listitem_props))
|
||||
return playurl, listitem_props
|
||||
return '{}?{}'.format(path, url_params)
|
||||
|
||||
|
||||
def get_checksum(item):
|
||||
userdata = item['UserData']
|
||||
checksum = "%s_%s_%s_%s_%s_%s_%s" % (
|
||||
checksum = "{}_{}_{}_{}_{}_{}_{}".format(
|
||||
item['Etag'],
|
||||
userdata['Played'],
|
||||
userdata['IsFavorite'],
|
||||
@@ -198,88 +67,6 @@ def get_checksum(item):
|
||||
return checksum
|
||||
|
||||
|
||||
def get_art(item, server):
|
||||
art = {
|
||||
'thumb': '',
|
||||
'fanart': '',
|
||||
'poster': '',
|
||||
'banner': '',
|
||||
'clearlogo': '',
|
||||
'clearart': '',
|
||||
'discart': '',
|
||||
'landscape': '',
|
||||
'tvshow.fanart': '',
|
||||
'tvshow.poster': '',
|
||||
'tvshow.clearart': '',
|
||||
'tvshow.clearlogo': '',
|
||||
'tvshow.banner': '',
|
||||
'tvshow.landscape': ''
|
||||
}
|
||||
|
||||
image_tags = item.get("ImageTags", {})
|
||||
if image_tags and image_tags.get("Primary"):
|
||||
art['thumb'] = downloadUtils.get_artwork(item, "Primary", server=server)
|
||||
|
||||
item_type = item["Type"]
|
||||
|
||||
if item_type == "Genre":
|
||||
art['poster'] = downloadUtils.get_artwork(item, "Primary", server=server)
|
||||
elif item_type == "Episode":
|
||||
art['tvshow.poster'] = downloadUtils.get_artwork(item, "Primary", parent=True, server=server)
|
||||
art['tvshow.clearart'] = downloadUtils.get_artwork(item, "Art", parent=True, server=server)
|
||||
art['clearart'] = downloadUtils.get_artwork(item, "Art", parent=True, server=server)
|
||||
art['tvshow.clearlogo'] = downloadUtils.get_artwork(item, "Logo", parent=True, server=server)
|
||||
art['clearlogo'] = downloadUtils.get_artwork(item, "Logo", parent=True, server=server)
|
||||
art['tvshow.banner'] = downloadUtils.get_artwork(item, "Banner", parent=True, server=server)
|
||||
art['banner'] = downloadUtils.get_artwork(item, "Banner", parent=True, server=server)
|
||||
art['tvshow.landscape'] = downloadUtils.get_artwork(item, "Thumb", parent=True, server=server)
|
||||
art['landscape'] = downloadUtils.get_artwork(item, "Thumb", parent=True, server=server)
|
||||
art['tvshow.fanart'] = downloadUtils.get_artwork(item, "Backdrop", parent=True, server=server)
|
||||
art['fanart'] = downloadUtils.get_artwork(item, "Backdrop", parent=True, server=server)
|
||||
elif item_type == "Season":
|
||||
art['tvshow.poster'] = downloadUtils.get_artwork(item, "Primary", parent=True, server=server)
|
||||
art['season.poster'] = downloadUtils.get_artwork(item, "Primary", parent=False, server=server)
|
||||
art['poster'] = downloadUtils.get_artwork(item, "Primary", parent=False, server=server)
|
||||
art['tvshow.clearart'] = downloadUtils.get_artwork(item, "Art", parent=True, server=server)
|
||||
art['clearart'] = downloadUtils.get_artwork(item, "Art", parent=True, server=server)
|
||||
art['tvshow.clearlogo'] = downloadUtils.get_artwork(item, "Logo", parent=True, server=server)
|
||||
art['clearlogo'] = downloadUtils.get_artwork(item, "Logo", parent=True, server=server)
|
||||
art['tvshow.banner'] = downloadUtils.get_artwork(item, "Banner", parent=True, server=server)
|
||||
art['season.banner'] = downloadUtils.get_artwork(item, "Banner", parent=False, server=server)
|
||||
art['banner'] = downloadUtils.get_artwork(item, "Banner", parent=False, server=server)
|
||||
art['tvshow.landscape'] = downloadUtils.get_artwork(item, "Thumb", parent=True, server=server)
|
||||
art['season.landscape'] = downloadUtils.get_artwork(item, "Thumb", parent=False, server=server)
|
||||
art['landscape'] = downloadUtils.get_artwork(item, "Thumb", parent=False, server=server)
|
||||
art['tvshow.fanart'] = downloadUtils.get_artwork(item, "Backdrop", parent=True, server=server)
|
||||
art['fanart'] = downloadUtils.get_artwork(item, "Backdrop", parent=True, server=server)
|
||||
elif item_type == "Series":
|
||||
art['tvshow.poster'] = downloadUtils.get_artwork(item, "Primary", parent=False, server=server)
|
||||
art['poster'] = downloadUtils.get_artwork(item, "Primary", parent=False, server=server)
|
||||
art['tvshow.clearart'] = downloadUtils.get_artwork(item, "Art", parent=False, server=server)
|
||||
art['clearart'] = downloadUtils.get_artwork(item, "Art", parent=False, server=server)
|
||||
art['tvshow.clearlogo'] = downloadUtils.get_artwork(item, "Logo", parent=False, server=server)
|
||||
art['clearlogo'] = downloadUtils.get_artwork(item, "Logo", parent=False, server=server)
|
||||
art['tvshow.banner'] = downloadUtils.get_artwork(item, "Banner", parent=False, server=server)
|
||||
art['banner'] = downloadUtils.get_artwork(item, "Banner", parent=False, server=server)
|
||||
art['tvshow.landscape'] = downloadUtils.get_artwork(item, "Thumb", parent=False, server=server)
|
||||
art['landscape'] = downloadUtils.get_artwork(item, "Thumb", parent=False, server=server)
|
||||
art['tvshow.fanart'] = downloadUtils.get_artwork(item, "Backdrop", parent=False, server=server)
|
||||
art['fanart'] = downloadUtils.get_artwork(item, "Backdrop", parent=False, server=server)
|
||||
elif item_type == "Movie" or item_type == "BoxSet":
|
||||
art['poster'] = downloadUtils.get_artwork(item, "Primary", server=server)
|
||||
art['landscape'] = downloadUtils.get_artwork(item, "Thumb", server=server)
|
||||
art['banner'] = downloadUtils.get_artwork(item, "Banner", server=server)
|
||||
art['clearlogo'] = downloadUtils.get_artwork(item, "Logo", server=server)
|
||||
art['clearart'] = downloadUtils.get_artwork(item, "Art", server=server)
|
||||
art['discart'] = downloadUtils.get_artwork(item, "Disc", server=server)
|
||||
|
||||
art['fanart'] = downloadUtils.get_artwork(item, "Backdrop", server=server)
|
||||
if not art['fanart']:
|
||||
art['fanart'] = downloadUtils.get_artwork(item, "Backdrop", parent=True, server=server)
|
||||
|
||||
return art
|
||||
|
||||
|
||||
def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
|
||||
return ''.join(random.choice(chars) for _ in range(size))
|
||||
|
||||
@@ -296,30 +83,55 @@ def send_event_notification(method, data=None, hexlify=False):
|
||||
Send events through Kodi's notification system
|
||||
'''
|
||||
data = data or {}
|
||||
data_str = json.dumps(data)
|
||||
|
||||
if hexlify:
|
||||
# Used exclusively for the upnext plugin
|
||||
data = ensure_text(binascii.hexlify(ensure_binary(json.dumps(data))))
|
||||
sender = 'plugin.video.jellycon'
|
||||
data = '"[%s]"' % json.dumps(data).replace('"', '\\"')
|
||||
data_str = ensure_text(binascii.hexlify(ensure_binary(data_str)))
|
||||
data = '["{}"]'.format(data_str)
|
||||
else:
|
||||
data = '"[{}]"'.format(data_str.replace('"', '\\"'))
|
||||
|
||||
xbmc.executebuiltin('NotifyAll(%s, %s, %s)' % (sender, method, data))
|
||||
sender = 'plugin.video.jellycon'
|
||||
|
||||
xbmc.executebuiltin('NotifyAll({}, {}, {})'.format(sender, method, data))
|
||||
|
||||
|
||||
def datetime_from_string(time_string):
|
||||
|
||||
# Builtin python library can't handle ISO-8601 well. Make it compatible
|
||||
if time_string[-1:] == "Z":
|
||||
time_string = re.sub("[0-9]{1}Z", " UTC", time_string)
|
||||
elif time_string[-6:] == "+00:00":
|
||||
time_string = re.sub("[0-9]{1}\+00:00", " UTC", time_string)
|
||||
log.debug("New Time String : {0}".format(time_string))
|
||||
time_string = re.sub(
|
||||
"[0-9]{1}\+00:00", " UTC", time_string # noqa: W605
|
||||
)
|
||||
|
||||
start_time = time.strptime(time_string, "%Y-%m-%dT%H:%M:%S.%f %Z")
|
||||
dt = datetime(*(start_time[0:6]))
|
||||
timestamp = calendar.timegm(dt.timetuple())
|
||||
local_dt = datetime.fromtimestamp(timestamp)
|
||||
local_dt.replace(microsecond=dt.microsecond)
|
||||
return local_dt
|
||||
try:
|
||||
dt = datetime.strptime(time_string, "%Y-%m-%dT%H:%M:%S.%f %Z")
|
||||
except TypeError:
|
||||
# https://bugs.python.org/issue27400
|
||||
dt = datetime(*(
|
||||
time.strptime(time_string, "%Y-%m-%dT%H:%M:%S.%f %Z")[0:6])
|
||||
)
|
||||
|
||||
"""
|
||||
Dates received from the server are in UTC, but parsing them results
|
||||
in naive objects
|
||||
"""
|
||||
utc = tz.tzutc()
|
||||
utc_dt = dt.replace(tzinfo=utc)
|
||||
|
||||
return utc_dt
|
||||
|
||||
|
||||
def get_current_datetime():
|
||||
# Get current time in UTC
|
||||
now = datetime.utcnow()
|
||||
utc = tz.tzutc()
|
||||
now_dt = now.replace(tzinfo=utc)
|
||||
|
||||
return now_dt
|
||||
|
||||
|
||||
def convert_size(size_bytes):
|
||||
@@ -329,4 +141,320 @@ def convert_size(size_bytes):
|
||||
i = int(math.floor(math.log(size_bytes, 1024)))
|
||||
p = math.pow(1024, i)
|
||||
s = round(size_bytes / p, 2)
|
||||
return "%s %s" % (s, size_name[i])
|
||||
return "{} {}".format(s, size_name[i])
|
||||
|
||||
|
||||
def translate_string(string_id):
|
||||
try:
|
||||
addon = xbmcaddon.Addon()
|
||||
return py2_encode(addon.getLocalizedString(string_id))
|
||||
except Exception as e:
|
||||
log.error('Failed String Load: {0} ({1})', string_id, e)
|
||||
return str(string_id)
|
||||
|
||||
|
||||
def get_device_id():
|
||||
|
||||
window = HomeWindow()
|
||||
username = window.get_property('user_name')
|
||||
client_id = window.get_property("client_id")
|
||||
hashed_name = hashlib.md5(username.encode()).hexdigest()
|
||||
|
||||
if client_id and username:
|
||||
return '{}-{}'.format(client_id, hashed_name)
|
||||
elif client_id and not username:
|
||||
# Quick Connect, needs to be unique so sessions don't overwrite
|
||||
rand_id = uuid4().hex
|
||||
return '{}-{}'.format(client_id, rand_id)
|
||||
|
||||
jellyfin_guid_path = py2_decode(
|
||||
translate_path("special://temp/jellycon_guid")
|
||||
)
|
||||
log.debug("jellyfin_guid_path: {0}".format(jellyfin_guid_path))
|
||||
guid = xbmcvfs.File(jellyfin_guid_path)
|
||||
client_id = guid.read()
|
||||
guid.close()
|
||||
|
||||
if not client_id:
|
||||
client_id = uuid4().hex
|
||||
log.debug("Generating a new guid: {0}".format(client_id))
|
||||
guid = xbmcvfs.File(jellyfin_guid_path, 'w')
|
||||
guid.write(client_id)
|
||||
guid.close()
|
||||
log.debug("jellyfin_client_id (NEW): {0}".format(client_id))
|
||||
else:
|
||||
log.debug("jellyfin_client_id: {0}".format(client_id))
|
||||
|
||||
window.set_property("client_id", client_id)
|
||||
return '{}-{}'.format(client_id, hashed_name)
|
||||
|
||||
|
||||
def get_version():
|
||||
addon = xbmcaddon.Addon()
|
||||
version = addon.getAddonInfo("version")
|
||||
return version
|
||||
|
||||
|
||||
def save_user_details(user_name, user_id, token):
|
||||
settings = xbmcaddon.Addon()
|
||||
save_user_to_settings = settings.getSetting(
|
||||
'save_user_to_settings') == 'true'
|
||||
addon_data = translate_path(xbmcaddon.Addon().getAddonInfo('profile'))
|
||||
|
||||
# Save to a config file for reference later if desired
|
||||
if save_user_to_settings:
|
||||
try:
|
||||
with open(os.path.join(addon_data, 'auth.json'), 'rb') as infile:
|
||||
auth_data = json.load(infile)
|
||||
except: # noqa
|
||||
# File doesn't exist or is empty
|
||||
auth_data = {}
|
||||
|
||||
auth_data[user_name] = {
|
||||
'user_id': user_id,
|
||||
'token': token
|
||||
}
|
||||
|
||||
with open(os.path.join(addon_data, 'auth.json'), 'wb') as outfile:
|
||||
data = json.dumps(
|
||||
auth_data, sort_keys=True, indent=4, ensure_ascii=False)
|
||||
if isinstance(data, text_type):
|
||||
data = data.encode('utf-8')
|
||||
outfile.write(data)
|
||||
|
||||
# Make the username available for easy lookup
|
||||
window = HomeWindow()
|
||||
settings.setSetting('username', user_name)
|
||||
window.set_property('user_name', user_name)
|
||||
|
||||
|
||||
def load_user_details():
|
||||
settings = xbmcaddon.Addon()
|
||||
window = HomeWindow()
|
||||
# Check current variables first, then check settings
|
||||
user_name = window.get_property('user_name')
|
||||
if not user_name:
|
||||
user_name = settings.getSetting('username')
|
||||
save_user = settings.getSetting('save_user_to_settings') == 'true'
|
||||
addon_data = translate_path(xbmcaddon.Addon().getAddonInfo('profile'))
|
||||
|
||||
if save_user:
|
||||
try:
|
||||
with open(os.path.join(addon_data, 'auth.json'), 'rb') as infile:
|
||||
auth_data = json.load(infile)
|
||||
except: # noqa
|
||||
# File doesn't exist yet
|
||||
return {}
|
||||
|
||||
user_data = auth_data.get(user_name, {})
|
||||
# User doesn't exist yet
|
||||
if not user_data:
|
||||
return {}
|
||||
|
||||
user_id = user_data.get('user_id')
|
||||
auth_token = user_data.get('token')
|
||||
|
||||
# Payload to return to calling function
|
||||
user_details = {}
|
||||
user_details['user_name'] = user_name
|
||||
user_details['user_id'] = user_id
|
||||
user_details['token'] = auth_token
|
||||
return user_details
|
||||
|
||||
else:
|
||||
return {}
|
||||
|
||||
|
||||
def get_saved_users():
|
||||
settings = xbmcaddon.Addon()
|
||||
save_user = settings.getSetting('save_user_to_settings') == 'true'
|
||||
addon_data = translate_path(xbmcaddon.Addon().getAddonInfo('profile'))
|
||||
if not save_user:
|
||||
return []
|
||||
|
||||
try:
|
||||
with open(os.path.join(addon_data, 'auth.json'), 'rb') as infile:
|
||||
auth_data = json.load(infile)
|
||||
except: # noqa
|
||||
# File doesn't exist yet
|
||||
return []
|
||||
|
||||
users = []
|
||||
for user, values in auth_data.items():
|
||||
users.append(
|
||||
{
|
||||
'Name': user,
|
||||
'Id': values.get('user_id'),
|
||||
# We need something here for the listitem function
|
||||
'Configuration': {'Dummy': True}
|
||||
}
|
||||
)
|
||||
|
||||
return users
|
||||
|
||||
|
||||
def get_current_user_id():
|
||||
user_details = load_user_details()
|
||||
user_id = user_details.get('user_id')
|
||||
return user_id
|
||||
|
||||
|
||||
def get_art_url(data, art_type, parent=False, index=0, server=None):
|
||||
|
||||
item_id = data["Id"]
|
||||
item_type = data["Type"]
|
||||
|
||||
if item_type in ["Episode", "Season"]:
|
||||
if art_type != "Primary" or parent is True:
|
||||
item_id = data["SeriesId"]
|
||||
|
||||
image_tag = ""
|
||||
|
||||
# for episodes always use the parent BG
|
||||
if item_type == "Episode" and art_type == "Backdrop":
|
||||
item_id = data.get("ParentBackdropItemId")
|
||||
bg_item_tags = data.get("ParentBackdropImageTags", [])
|
||||
if bg_item_tags:
|
||||
image_tag = bg_item_tags[0]
|
||||
elif art_type == "Backdrop" and parent is True:
|
||||
item_id = data.get("ParentBackdropItemId")
|
||||
bg_item_tags = data.get("ParentBackdropImageTags", [])
|
||||
if bg_item_tags:
|
||||
image_tag = bg_item_tags[0]
|
||||
elif art_type == "Backdrop":
|
||||
bg_tags = data.get("BackdropImageTags", [])
|
||||
if bg_tags:
|
||||
image_tag = bg_tags[index]
|
||||
elif parent is False:
|
||||
image_tags = data.get("ImageTags", [])
|
||||
if image_tags:
|
||||
image_tag_type = image_tags.get(art_type)
|
||||
if image_tag_type:
|
||||
image_tag = image_tag_type
|
||||
elif parent is True:
|
||||
if ((item_type == "Episode" or item_type == "Season") and
|
||||
art_type == 'Primary'):
|
||||
tag_name = 'SeriesPrimaryImageTag'
|
||||
id_name = 'SeriesId'
|
||||
else:
|
||||
tag_name = 'Parent{}ImageTag'.format(art_type)
|
||||
id_name = 'Parent{}ItemId'.format(art_type)
|
||||
parent_image_id = data.get(id_name)
|
||||
parent_image_tag = data.get(tag_name)
|
||||
if parent_image_id is not None and parent_image_tag is not None:
|
||||
item_id = parent_image_id
|
||||
image_tag = parent_image_tag
|
||||
|
||||
# ParentTag not passed for Banner and Art
|
||||
if (not image_tag and
|
||||
not ((art_type == 'Banner' or art_type == 'Art') and
|
||||
parent is True)):
|
||||
return ""
|
||||
|
||||
artwork = "{}/Items/{}/Images/{}/{}?Format=original&Tag={}".format(
|
||||
server, item_id, art_type, index, image_tag)
|
||||
return artwork
|
||||
|
||||
|
||||
def image_url(item_id, art_type, index, width, height, image_tag, server):
|
||||
|
||||
# test imageTag e3ab56fe27d389446754d0fb04910a34
|
||||
artwork = "{}/Items/{}/Images/{}/{}?Format=original&Tag={}".format(
|
||||
server, item_id, art_type, index, image_tag
|
||||
)
|
||||
if int(width) > 0:
|
||||
artwork += '&MaxWidth={}'.format(width)
|
||||
if int(height) > 0:
|
||||
artwork += '&MaxHeight={}'.format(height)
|
||||
|
||||
return artwork
|
||||
|
||||
|
||||
def get_default_filters():
|
||||
|
||||
addon_settings = xbmcaddon.Addon()
|
||||
include_media = addon_settings.getSetting("include_media") == "true"
|
||||
include_people = addon_settings.getSetting("include_people") == "true"
|
||||
include_overview = addon_settings.getSetting("include_overview") == "true"
|
||||
|
||||
filer_list = [
|
||||
"DateCreated",
|
||||
"EpisodeCount",
|
||||
"SeasonCount",
|
||||
"Path",
|
||||
"Genres",
|
||||
"Studios",
|
||||
"Etag",
|
||||
"Taglines",
|
||||
"SortName",
|
||||
"RecursiveItemCount",
|
||||
"ChildCount",
|
||||
"ProductionLocations",
|
||||
"CriticRating",
|
||||
"OfficialRating",
|
||||
"CommunityRating",
|
||||
"PremiereDate",
|
||||
"ProductionYear",
|
||||
"AirTime",
|
||||
"Status",
|
||||
"Tags"
|
||||
]
|
||||
|
||||
if include_media:
|
||||
filer_list.append("MediaStreams")
|
||||
|
||||
if include_people:
|
||||
filer_list.append("People")
|
||||
|
||||
if include_overview:
|
||||
filer_list.append("Overview")
|
||||
|
||||
return ','.join(filer_list)
|
||||
|
||||
|
||||
def translate_path(path):
|
||||
'''
|
||||
Use new library location for translate path starting in Kodi 19
|
||||
'''
|
||||
version = kodi_version()
|
||||
|
||||
if version > 18:
|
||||
return xbmcvfs.translatePath(path)
|
||||
else:
|
||||
return xbmc.translatePath(path)
|
||||
|
||||
|
||||
def download_external_sub(language, codec, url):
|
||||
addon_settings = xbmcaddon.Addon()
|
||||
verify_cert = addon_settings.getSetting('verify_cert') == 'true'
|
||||
|
||||
# Download the subtitle file
|
||||
r = requests.get(url, verify=verify_cert)
|
||||
r.raise_for_status()
|
||||
|
||||
# Write the subtitle file to the local filesystem
|
||||
file_name = 'Stream.{}.{}'.format(language, codec)
|
||||
file_path = py2_decode(
|
||||
translate_path('special://temp/{}'.format(file_name))
|
||||
)
|
||||
with open(file_path, 'wb') as f:
|
||||
f.write(r.content)
|
||||
|
||||
return file_path
|
||||
|
||||
|
||||
def get_bitrate(enum_value):
|
||||
''' Get the video quality based on add-on settings.
|
||||
Max bit rate supported by server: 2147483 (max signed 32bit integer)
|
||||
'''
|
||||
bitrate = [500, 1000, 1500, 2000, 2500, 3000, 4000, 5000, 6000,
|
||||
7000, 8000, 9000, 10000, 12000, 14000, 16000, 18000,
|
||||
20000, 25000, 30000, 35000, 40000, 100000, 1000000, 2147483]
|
||||
return bitrate[int(enum_value) if enum_value else 24] * 1000
|
||||
|
||||
def get_filtered_items_count_text():
|
||||
settings = xbmcaddon.Addon()
|
||||
if settings.getSetting("hide_x_filtered_items_count") == 'true' :
|
||||
return ""
|
||||
else:
|
||||
return " (" + settings.getSetting("show_x_filtered_items") + ")"
|
||||
@@ -1,22 +1,22 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
#################################################################################################
|
||||
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
import json
|
||||
import threading
|
||||
import websocket
|
||||
import time
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
import xbmcgui
|
||||
import websocket
|
||||
|
||||
from .jellyfin import API
|
||||
from .functions import play_action
|
||||
from .loghandler import LazyLogger
|
||||
from . import clientinfo
|
||||
from . import downloadutils
|
||||
from .lazylogger import LazyLogger
|
||||
from .jsonrpc import JsonRpc
|
||||
from .kodi_utils import HomeWindow
|
||||
from .utils import get_device_id, load_user_details
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
@@ -35,8 +35,7 @@ class WebSocketClient(threading.Thread):
|
||||
self.monitor = xbmc.Monitor()
|
||||
self.retry_count = 0
|
||||
|
||||
self.client_info = clientinfo.ClientInformation()
|
||||
self.device_id = self.client_info.get_device_id()
|
||||
self.device_id = get_device_id()
|
||||
|
||||
self._library_monitor = library_change_monitor
|
||||
|
||||
@@ -106,7 +105,6 @@ class WebSocketClient(threading.Thread):
|
||||
params["audio_stream_index"] = audio_stream_index
|
||||
play_action(params)
|
||||
|
||||
|
||||
def _playstate(self, data):
|
||||
|
||||
command = data['Command']
|
||||
@@ -159,7 +157,9 @@ class WebSocketClient(threading.Thread):
|
||||
|
||||
elif command == 'SetVolume':
|
||||
volume = arguments['Volume']
|
||||
xbmc.executebuiltin('SetVolume(%s[,showvolumebar])' % volume)
|
||||
xbmc.executebuiltin(
|
||||
'SetVolume({}[,showvolumebar])'.format(volume)
|
||||
)
|
||||
|
||||
elif command == 'SetAudioStreamIndex':
|
||||
index = int(arguments['Index'])
|
||||
@@ -171,7 +171,7 @@ class WebSocketClient(threading.Thread):
|
||||
|
||||
elif command == 'SetRepeatMode':
|
||||
mode = arguments['RepeatMode']
|
||||
xbmc.executebuiltin('xbmc.PlayerControl(%s)' % mode)
|
||||
xbmc.executebuiltin('xbmc.PlayerControl({})'.format(mode))
|
||||
|
||||
elif command == 'DisplayMessage':
|
||||
|
||||
@@ -239,23 +239,24 @@ class WebSocketClient(threading.Thread):
|
||||
|
||||
def run(self):
|
||||
|
||||
# websocket.enableTrace(True)
|
||||
download_utils = downloadutils.DownloadUtils()
|
||||
|
||||
token = None
|
||||
while token is None or token == "":
|
||||
token = download_utils.authenticate()
|
||||
user_details = load_user_details()
|
||||
token = user_details.get('token')
|
||||
if self.monitor.waitForAbort(10):
|
||||
return
|
||||
|
||||
# Get the appropriate prefix for the websocket
|
||||
server = download_utils.get_server()
|
||||
settings = xbmcaddon.Addon()
|
||||
server = settings.getSetting('server_address')
|
||||
if "https://" in server:
|
||||
server = server.replace('https://', 'wss://')
|
||||
else:
|
||||
server = server.replace('http://', 'ws://')
|
||||
|
||||
websocket_url = "%s/socket?api_key=%s&deviceId=%s" % (server, token, self.device_id)
|
||||
websocket_url = "{}/socket?api_key={}&deviceId={}".format(
|
||||
server, token, self.device_id
|
||||
)
|
||||
log.debug("websocket url: {0}".format(websocket_url))
|
||||
|
||||
self._client = websocket.WebSocketApp(
|
||||
@@ -293,5 +294,13 @@ class WebSocketClient(threading.Thread):
|
||||
|
||||
def post_capabilities(self):
|
||||
|
||||
download_utils = downloadutils.DownloadUtils()
|
||||
download_utils.post_capabilities()
|
||||
settings = xbmcaddon.Addon()
|
||||
user_details = load_user_details()
|
||||
|
||||
api = API(
|
||||
settings.getSetting('server_address'),
|
||||
user_details.get('user_id'),
|
||||
user_details.get('token')
|
||||
)
|
||||
|
||||
api.post_capabilities()
|
||||
|
||||
@@ -1,25 +1,27 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import hashlib
|
||||
import random
|
||||
import time
|
||||
import datetime
|
||||
|
||||
import xbmcaddon
|
||||
import xbmcplugin
|
||||
import xbmcgui
|
||||
import xbmc
|
||||
import hashlib
|
||||
import random
|
||||
import time
|
||||
|
||||
from .downloadutils import DownloadUtils
|
||||
from .utils import get_jellyfin_url
|
||||
from .datamanager import DataManager
|
||||
from .loghandler import LazyLogger
|
||||
from .jellyfin import api
|
||||
from .utils import (
|
||||
get_jellyfin_url, image_url, get_current_user_id,
|
||||
get_art_url, get_default_filters
|
||||
)
|
||||
from .lazylogger import LazyLogger
|
||||
from .kodi_utils import HomeWindow
|
||||
from .dir_functions import process_directory
|
||||
from .tracking import timer
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
downloadUtils = DownloadUtils()
|
||||
dataManager = DataManager()
|
||||
kodi_version = int(xbmc.getInfoLabel('System.BuildVersion')[:2])
|
||||
|
||||
background_items = []
|
||||
background_current_item = 0
|
||||
@@ -30,20 +32,22 @@ def set_random_movies():
|
||||
log.debug("set_random_movies Called")
|
||||
|
||||
settings = xbmcaddon.Addon()
|
||||
item_limit = settings.getSetting("show_x_filtered_items")
|
||||
hide_watched = settings.getSetting("hide_watched") == "true"
|
||||
user_id = get_current_user_id()
|
||||
|
||||
url_params = {}
|
||||
url_params["Recursive"] = True
|
||||
url_params["limit"] = 20
|
||||
url_params["limit"] = item_limit
|
||||
if hide_watched:
|
||||
url_params["IsPlayed"] = False
|
||||
url_params["SortBy"] = "Random"
|
||||
url_params["IncludeItemTypes"] = "Movie"
|
||||
url_params["ImageTypeLimit"] = 0
|
||||
|
||||
url = get_jellyfin_url("{server}/Users/{userid}/Items", url_params)
|
||||
url = get_jellyfin_url("/Users/{}/Items".format(user_id), url_params)
|
||||
|
||||
results = downloadUtils.download_url(url, suppress=True)
|
||||
results = api.get(url)
|
||||
|
||||
randon_movies_list = []
|
||||
if results is not None:
|
||||
@@ -70,14 +74,19 @@ def set_background_image(force=False):
|
||||
global background_current_item
|
||||
global background_items
|
||||
|
||||
settings = xbmcaddon.Addon()
|
||||
server = settings.getSetting('server_address')
|
||||
user_id = get_current_user_id()
|
||||
|
||||
if force:
|
||||
background_current_item = 0
|
||||
del background_items
|
||||
background_items = []
|
||||
|
||||
if len(background_items) == 0:
|
||||
log.debug("set_background_image: Need to load more backgrounds {0} - {1}".format(
|
||||
len(background_items), background_current_item))
|
||||
log.debug("Need to load more backgrounds {0} - {1}".format(
|
||||
len(background_items), background_current_item)
|
||||
)
|
||||
|
||||
url_params = {}
|
||||
url_params["Recursive"] = True
|
||||
@@ -86,17 +95,16 @@ def set_background_image(force=False):
|
||||
url_params["IncludeItemTypes"] = "Movie,Series"
|
||||
url_params["ImageTypeLimit"] = 1
|
||||
|
||||
url = get_jellyfin_url('{server}/Users/{userid}/Items', url_params)
|
||||
url = get_jellyfin_url('/Users/{}/Items'.format(user_id), url_params)
|
||||
|
||||
server = downloadUtils.get_server()
|
||||
results = downloadUtils.download_url(url, suppress=True)
|
||||
results = api.get(url)
|
||||
|
||||
if results is not None:
|
||||
items = results.get("Items", [])
|
||||
background_current_item = 0
|
||||
background_items = []
|
||||
for item in items:
|
||||
bg_image = downloadUtils.get_artwork(
|
||||
bg_image = get_art_url(
|
||||
item, "Backdrop", server=server)
|
||||
if bg_image:
|
||||
label = item.get("Name")
|
||||
@@ -106,13 +114,17 @@ def set_background_image(force=False):
|
||||
background_items.append(item_background)
|
||||
|
||||
log.debug("set_background_image: Loaded {0} more backgrounds".format(
|
||||
len(background_items)))
|
||||
len(background_items))
|
||||
)
|
||||
|
||||
if len(background_items) > 0:
|
||||
bg_image = background_items[background_current_item].get("image")
|
||||
label = background_items[background_current_item].get("name")
|
||||
log.debug(
|
||||
"set_background_image: {0} - {1} - {2}".format(background_current_item, label, bg_image))
|
||||
"set_background_image: {0} - {1} - {2}".format(
|
||||
background_current_item, label, bg_image
|
||||
)
|
||||
)
|
||||
|
||||
background_current_item += 1
|
||||
if background_current_item >= len(background_items):
|
||||
@@ -138,6 +150,7 @@ def check_for_new_content():
|
||||
home_window.set_property("jellycon_widget_reload", current_time_stamp)
|
||||
log.debug("Setting New Widget Hash: {0}".format(current_time_stamp))
|
||||
return
|
||||
user_id = get_current_user_id()
|
||||
|
||||
url_params = {}
|
||||
url_params["Recursive"] = True
|
||||
@@ -148,9 +161,9 @@ def check_for_new_content():
|
||||
url_params["IncludeItemTypes"] = "Movie,Episode"
|
||||
url_params["ImageTypeLimit"] = 0
|
||||
|
||||
added_url = get_jellyfin_url('{server}/Users/{userid}/Items', url_params)
|
||||
added_url = get_jellyfin_url('/Users/{}/Items'.format(user_id), url_params)
|
||||
|
||||
result = downloadUtils.download_url(added_url, suppress=True)
|
||||
result = api.get(added_url)
|
||||
log.debug("LATEST_ADDED_ITEM: {0}".format(result))
|
||||
|
||||
last_added_date = ""
|
||||
@@ -170,9 +183,11 @@ def check_for_new_content():
|
||||
url_params["IncludeItemTypes"] = "Movie,Episode"
|
||||
url_params["ImageTypeLimit"] = 0
|
||||
|
||||
played_url = get_jellyfin_url('{server}/Users/{userid}/Items', url_params)
|
||||
played_url = get_jellyfin_url(
|
||||
'/Users/{}/Items'.format(user_id), url_params
|
||||
)
|
||||
|
||||
result = downloadUtils.download_url(played_url, suppress=True)
|
||||
result = api.get(played_url)
|
||||
log.debug("LATEST_PLAYED_ITEM: {0}".format(result))
|
||||
|
||||
last_played_date = ""
|
||||
@@ -190,7 +205,7 @@ def check_for_new_content():
|
||||
log.debug("Current Widget Hash: {0}".format(current_widget_hash))
|
||||
|
||||
m = hashlib.md5()
|
||||
m.update(last_played_date + last_added_date)
|
||||
m.update((last_played_date + last_added_date).encode())
|
||||
new_widget_hash = m.hexdigest()
|
||||
log.debug("New Widget Hash: {0}".format(new_widget_hash))
|
||||
|
||||
@@ -202,18 +217,21 @@ def check_for_new_content():
|
||||
@timer
|
||||
def get_widget_content_cast(handle, params):
|
||||
log.debug("getWigetContentCast Called: {0}".format(params))
|
||||
server = downloadUtils.get_server()
|
||||
settings = xbmcaddon.Addon()
|
||||
server = settings.getSetting('server_address')
|
||||
user_id = get_current_user_id()
|
||||
|
||||
item_id = params["id"]
|
||||
data_manager = DataManager()
|
||||
result = data_manager.get_content(
|
||||
"{server}/Users/{userid}/Items/" + item_id)
|
||||
result = api.get(
|
||||
"/Users/{}/Items/{}".format(user_id, item_id))
|
||||
log.debug("ItemInfo: {0}".format(result))
|
||||
|
||||
if not result:
|
||||
return
|
||||
|
||||
if result.get("Type", "") in ["Episode", "Season"] and params.get("auto", "true") == "true":
|
||||
if (result.get("Type", "") in ["Episode", "Season"] and
|
||||
params.get("auto", "true") == "true"):
|
||||
|
||||
series_id = result.get("SeriesId")
|
||||
if series_id:
|
||||
params["id"] = series_id
|
||||
@@ -233,13 +251,12 @@ def get_widget_content_cast(handle, params):
|
||||
person_tag = person.get("PrimaryImageTag")
|
||||
person_thumbnail = None
|
||||
if person_tag:
|
||||
person_thumbnail = downloadUtils.image_url(
|
||||
person_id, "Primary", 0, 400, 400, person_tag, server=server)
|
||||
person_thumbnail = image_url(
|
||||
person_id, "Primary", 0, 400, 400,
|
||||
person_tag, server=server
|
||||
)
|
||||
|
||||
if kodi_version > 17:
|
||||
list_item = xbmcgui.ListItem(label=person_name, offscreen=True)
|
||||
else:
|
||||
list_item = xbmcgui.ListItem(label=person_name)
|
||||
list_item = xbmcgui.ListItem(label=person_name, offscreen=True)
|
||||
|
||||
list_item.setProperty("id", person_id)
|
||||
|
||||
@@ -256,8 +273,8 @@ def get_widget_content_cast(handle, params):
|
||||
if person_role:
|
||||
list_item.setLabel2(person_role)
|
||||
|
||||
item_tupple = ("", list_item, False)
|
||||
list_items.append(item_tupple)
|
||||
item_tuple = ("", list_item, False)
|
||||
list_items.append(item_tuple)
|
||||
|
||||
xbmcplugin.setContent(handle, 'artists')
|
||||
xbmcplugin.addDirectoryItems(handle, list_items)
|
||||
@@ -269,6 +286,7 @@ def get_widget_content(handle, params):
|
||||
log.debug("getWigetContent Called: {0}".format(params))
|
||||
|
||||
settings = xbmcaddon.Addon()
|
||||
item_limit = int(settings.getSetting("show_x_filtered_items"))
|
||||
hide_watched = settings.getSetting("hide_watched") == "true"
|
||||
use_cached_widget_data = settings.getSetting(
|
||||
"use_cached_widget_data") == "true"
|
||||
@@ -277,16 +295,16 @@ def get_widget_content(handle, params):
|
||||
if widget_type is None:
|
||||
log.error("getWigetContent type not set")
|
||||
return
|
||||
user_id = get_current_user_id()
|
||||
|
||||
log.debug("widget_type: {0}".format(widget_type))
|
||||
|
||||
url_verb = "{server}/Users/{userid}/Items"
|
||||
url_verb = "/Users/{}/Items".format(user_id)
|
||||
url_params = {}
|
||||
url_params["Limit"] = "{ItemLimit}"
|
||||
url_params["Fields"] = "{field_filters}"
|
||||
url_params["Limit"] = item_limit
|
||||
url_params["Fields"] = get_default_filters()
|
||||
url_params["ImageTypeLimit"] = 1
|
||||
url_params["IsMissing"] = False
|
||||
in_progress = False
|
||||
|
||||
if widget_type == "recent_movies":
|
||||
xbmcplugin.setContent(handle, 'movies')
|
||||
@@ -298,7 +316,7 @@ def get_widget_content(handle, params):
|
||||
url_params["IsPlayed"] = False
|
||||
url_params["IsVirtualUnaired"] = False
|
||||
url_params["IncludeItemTypes"] = "Movie"
|
||||
url_params["Limit"] = 20
|
||||
url_params["Limit"] = item_limit
|
||||
|
||||
elif widget_type == "inprogress_movies":
|
||||
xbmcplugin.setContent(handle, 'movies')
|
||||
@@ -308,27 +326,28 @@ def get_widget_content(handle, params):
|
||||
url_params["Filters"] = "IsResumable"
|
||||
url_params["IsVirtualUnaired"] = False
|
||||
url_params["IncludeItemTypes"] = "Movie"
|
||||
url_params["Limit"] = 20
|
||||
url_params["Limit"] = item_limit
|
||||
|
||||
elif widget_type == "random_movies":
|
||||
home_window = HomeWindow()
|
||||
xbmcplugin.setContent(handle, 'movies')
|
||||
url_params["Ids"] = "{random_movies}"
|
||||
url_params["Ids"] = home_window.get_property("random-movies")
|
||||
|
||||
elif widget_type == "recent_tvshows":
|
||||
xbmcplugin.setContent(handle, 'episodes')
|
||||
url_verb = '{server}/Users/{userid}/Items/Latest'
|
||||
url_verb = '/Users/{}/Items/Latest'.format(user_id)
|
||||
url_params["GroupItems"] = True
|
||||
url_params["Limit"] = 45
|
||||
url_params["Recursive"] = True
|
||||
url_params["SortBy"] = "DateCreated"
|
||||
url_params["SortOrder"] = "Descending"
|
||||
url_params["Fields"] = "{field_filters}"
|
||||
url_params["Fields"] = get_default_filters()
|
||||
if hide_watched:
|
||||
url_params["IsPlayed"] = False
|
||||
url_params["IsVirtualUnaired"] = False
|
||||
url_params["IncludeItemTypes"] = "Episode"
|
||||
url_params["ImageTypeLimit"] = 1
|
||||
url_params["Limit"] = 20
|
||||
url_params["Limit"] = item_limit
|
||||
|
||||
elif widget_type == "recent_episodes":
|
||||
xbmcplugin.setContent(handle, 'episodes')
|
||||
@@ -340,7 +359,7 @@ def get_widget_content(handle, params):
|
||||
url_params["IsPlayed"] = False
|
||||
url_params["IsVirtualUnaired"] = False
|
||||
url_params["IncludeItemTypes"] = "Episode"
|
||||
url_params["Limit"] = 20
|
||||
url_params["Limit"] = item_limit
|
||||
|
||||
elif widget_type == "inprogress_episodes":
|
||||
xbmcplugin.setContent(handle, 'episodes')
|
||||
@@ -350,18 +369,25 @@ def get_widget_content(handle, params):
|
||||
url_params["Filters"] = "IsResumable"
|
||||
url_params["IsVirtualUnaired"] = False
|
||||
url_params["IncludeItemTypes"] = "Episode"
|
||||
url_params["Limit"] = 20
|
||||
url_params["Limit"] = item_limit
|
||||
|
||||
elif widget_type == "nextup_episodes":
|
||||
xbmcplugin.setContent(handle, 'episodes')
|
||||
url_verb = "{server}/Shows/NextUp"
|
||||
url_verb = "/Shows/NextUp"
|
||||
url_params = url_params.copy()
|
||||
url_params["Limit"] = "{ItemLimit}"
|
||||
url_params["userid"] = "{userid}"
|
||||
url_params["Limit"] = item_limit
|
||||
url_params["userid"] = user_id
|
||||
url_params["Recursive"] = True
|
||||
url_params["enableResumable"] = False
|
||||
url_params["ImageTypeLimit"] = 1
|
||||
# check if rewatching is enabled and combine is disabled
|
||||
rewatch_days = int(settings.getSetting("rewatch_days"))
|
||||
if rewatch_days > 0 and settings.getSetting("rewatch_combine") != "true":
|
||||
rewatch_since = datetime.datetime.today() - datetime.timedelta(days=rewatch_days)
|
||||
url_params["nextUpDateCutoff"] = rewatch_since.strftime("%Y-%m-%d")
|
||||
url_params["enableRewatching"] = True
|
||||
# Collect InProgress items to be combined with NextUp
|
||||
inprogress_url_verb = "{server}/Users/{userid}/Items"
|
||||
inprogress_url_verb = "/Users/{}/Items".format(user_id)
|
||||
inprogress_url_params = url_params.copy()
|
||||
inprogress_url_params["Recursive"] = True
|
||||
inprogress_url_params["SortBy"] = "DatePlayed"
|
||||
@@ -369,31 +395,36 @@ def get_widget_content(handle, params):
|
||||
inprogress_url_params["Filters"] = "IsResumable"
|
||||
inprogress_url_params["IsVirtualUnaired"] = False
|
||||
inprogress_url_params["IncludeItemTypes"] = "Episode"
|
||||
inprogress_url_params["Limit"] = 20
|
||||
in_progress = True
|
||||
inprogress_url_params["Limit"] = item_limit
|
||||
|
||||
elif widget_type == "movie_recommendations":
|
||||
suggested_items_url_params = {}
|
||||
suggested_items_url_params["userId"] = "{userid}"
|
||||
suggested_items_url_params["userId"] = user_id
|
||||
suggested_items_url_params["categoryLimit"] = 15
|
||||
suggested_items_url_params["ItemLimit"] = 20
|
||||
suggested_items_url_params["ItemLimit"] = item_limit
|
||||
suggested_items_url_params["ImageTypeLimit"] = 0
|
||||
suggested_items_url = get_jellyfin_url(
|
||||
"{server}/Movies/Recommendations", suggested_items_url_params)
|
||||
"/Movies/Recommendations", suggested_items_url_params)
|
||||
|
||||
data_manager = DataManager()
|
||||
suggested_items = data_manager.get_content(suggested_items_url)
|
||||
suggested_items = api.get(suggested_items_url)
|
||||
ids = []
|
||||
set_id = 0
|
||||
while len(ids) < 20 and suggested_items:
|
||||
while len(ids) < item_limit and suggested_items:
|
||||
items = suggested_items[set_id]
|
||||
log.debug(
|
||||
"BaselineItemName : {0} - {1}".format(set_id, items.get("BaselineItemName")))
|
||||
"BaselineItemName : {0} - {1}".format(
|
||||
set_id, items.get("BaselineItemName")
|
||||
)
|
||||
)
|
||||
items = items["Items"]
|
||||
rand = random.randint(0, len(items) - 1)
|
||||
item = items[rand]
|
||||
if item["Type"] == "Movie" and item["Id"] not in ids and (not item["UserData"]["Played"] or not hide_watched):
|
||||
|
||||
if (item["Type"] == "Movie" and item["Id"] not in ids and
|
||||
(not item["UserData"]["Played"] or not hide_watched)):
|
||||
|
||||
ids.append(item["Id"])
|
||||
|
||||
del items[rand]
|
||||
if len(items) == 0:
|
||||
del suggested_items[set_id]
|
||||
@@ -402,23 +433,39 @@ def get_widget_content(handle, params):
|
||||
set_id = 0
|
||||
|
||||
id_list = ",".join(ids)
|
||||
log.debug("Recommended Items : {0}".format(len(ids), id_list))
|
||||
log.debug("Recommended Items : {0}".format(len(ids)))
|
||||
url_params["Ids"] = id_list
|
||||
|
||||
items_url = get_jellyfin_url(url_verb, url_params)
|
||||
|
||||
if (url_params.get('IncludeItemTypes', '') == 'Episode' or
|
||||
params.get('type', '') == 'nextup_episodes'):
|
||||
params["name_format"] = "Episode|episode_name_format"
|
||||
|
||||
list_items, detected_type, total_records = process_directory(
|
||||
items_url, None, params, use_cached_widget_data)
|
||||
|
||||
# Combine In Progress and Next Up Episodes, apend next up after In Progress
|
||||
# Combine In Progress and Next Up Episodes, add next up after In Progress
|
||||
if widget_type == "nextup_episodes":
|
||||
inprogress_url = get_jellyfin_url(
|
||||
inprogress_url_verb, inprogress_url_params)
|
||||
|
||||
list_items_inprogress, detected_type, total_records = process_directory(
|
||||
params["name_format"] = "Episode|episode_name_format"
|
||||
inprogress, detected_type, total_records = process_directory(
|
||||
inprogress_url, None, params, use_cached_widget_data)
|
||||
|
||||
list_items = list_items_inprogress + list_items
|
||||
list_items = inprogress + list_items
|
||||
|
||||
# add rewatch combine is enabled
|
||||
if rewatch_days > 0 and settings.getSetting("rewatch_combine") == "true":
|
||||
rewatch_since = datetime.datetime.today() - datetime.timedelta(days=rewatch_days)
|
||||
url_params["nextUpDateCutoff"] = rewatch_since.strftime("%Y-%m-%d")
|
||||
url_params["enableRewatching"] = True
|
||||
rewatch_items_url = get_jellyfin_url(url_verb, url_params)
|
||||
rewatch_items, detected_type, total_records = process_directory(rewatch_items_url, None, params, use_cached_widget_data)
|
||||
for ri in rewatch_items:
|
||||
if not any(i[1].getProperty("id") == ri[1].getProperty("id") for i in list_items):
|
||||
list_items.append(ri)
|
||||
|
||||
if detected_type is not None:
|
||||
# if the media type is not set then try to use the detected type
|
||||
@@ -431,7 +478,7 @@ def get_widget_content(handle, params):
|
||||
content_type = 'episodes'
|
||||
elif detected_type == "Series":
|
||||
content_type = 'tvshows'
|
||||
elif detected_type == "Music" or detected_type == "Audio" or detected_type == "Musicalbum":
|
||||
elif detected_type in ["Music", "Audio", "Musicalbum"]:
|
||||
content_type = 'songs'
|
||||
|
||||
if content_type:
|
||||
|
||||
@@ -5,16 +5,15 @@
|
||||
<setting label="30388" type="lsep"/>
|
||||
<setting label="30011" type="action" action="RunScript(plugin.video.jellycon,0,?mode=DETECT_SERVER_USER)" option="close"/>
|
||||
<setting id="ipaddress" type="text" label="30000" default="" visible="false" enable="false" />
|
||||
<setting id="protocol" type="select" label="30390" lvalues="30391|30392" default="0" visible="false"/>
|
||||
<setting id="protocol" type="select" label="30390" lvalues="30391|30392" default="0" visible="false"/>
|
||||
<setting id="port" type="text" label="30001" default="8096" visible="false" enable="false" />
|
||||
<setting id="server_address" type="text" label="30000" default="" visible="true" enable="true" />
|
||||
<setting id="verify_cert" type="bool" label="30003" default="false" visible="true" enable="true" />
|
||||
<setting id="verify_cert" type="bool" label="30003" default="true" visible="true" enable="true" />
|
||||
|
||||
<setting label="30389" type="lsep"/>
|
||||
<setting type="sep" />
|
||||
<setting label="30012" type="action" action="RunScript(plugin.video.jellycon,0,?mode=CHANGE_USER)" option="close"/>
|
||||
<setting id="username" type="text" label="30024" />
|
||||
<setting id="password" type="text" option="hidden" label="30025" />
|
||||
<setting id="save_user_to_settings" type="bool" label="30378" default="true" visible="true" enable="true" />
|
||||
<setting id="allow_password_saving" type="bool" label="30367" default="true" visible="true" enable="true" />
|
||||
|
||||
@@ -29,22 +28,24 @@
|
||||
|
||||
<setting label="30238" type="lsep"/>
|
||||
<setting type="sep" />
|
||||
<setting id="max_stream_bitrate" type="slider" label="30208" default="75000" range="400,100,100000" option="int" visible="true"/>
|
||||
<setting id="max_stream_bitrate" type="enum" label="30208" values="0.5 Mbps|1 Mbps|1.5 Mbps|2.0 Mbps|2.5 Mbps|3.0 Mbps|4.0 Mbps|5.0 Mbps|6.0 Mbps|7.0 Mbps|8.0 Mbps|9.0 Mbps|10.0 Mbps|12.0 Mbps|14.0 Mbps|16.0 Mbps|18.0 Mbps|20.0 Mbps|25.0 Mbps|30.0 Mbps|35.0 Mbps|40.0 Mbps|100.0 Mbps|1000.0 Mbps [default]|Maximum" visible="true" default="23" />
|
||||
<setting id="allow_direct_file_play" type="bool" label="30433" default="false" visible="true" enable="true" />
|
||||
<setting id="force_transcode_h265" type="bool" label="30236" default="false" visible="true" enable="true" />
|
||||
<setting id="force_transcode_mpeg2" type="bool" label="30239" default="false" visible="true" enable="true" />
|
||||
<setting id="force_transcode_msmpeg4v3" type="bool" label="30240" default="false" visible="true" enable="true" />
|
||||
<setting id="force_transcode_mpeg4" type="bool" label="30241" default="false" visible="true" enable="true" />
|
||||
<setting id="force_transcode_av1" type="bool" label="30242" default="false" visible="true" enable="true" />
|
||||
<setting id="direct_stream_sub_select" type="select" label="30379" lvalues="30380|30381|30382" default="0" visible="true"/>
|
||||
|
||||
<setting label="30211" type="lsep"/>
|
||||
<setting type="sep" />
|
||||
<setting id="force_max_stream_bitrate" type="slider" label="30434" default="7000" range="400,100,15000" option="int" visible="true"/>
|
||||
<setting id="force_max_stream_bitrate" type="enum" label="30434" values="0.5 Mbps|1 Mbps|1.5 Mbps|2.0 Mbps|2.5 Mbps|3.0 Mbps|4.0 Mbps|5.0 Mbps|6.0 Mbps|7.0 Mbps [default]|8.0 Mbps|9.0 Mbps|10.0 Mbps|12.0 Mbps|14.0 Mbps|16.0 Mbps|18.0 Mbps|20.0 Mbps|25.0 Mbps|30.0 Mbps|35.0 Mbps|40.0 Mbps|100.0 Mbps|1000.0 Mbps|Maximum" visible="true" default="9" />
|
||||
<setting id="playback_max_width" type="select" label="30212" values="640|720|1024|1280|1440|1600|1920|2600|4096" default="1920" visible="true"/>
|
||||
<setting id="playback_video_force_8" type="bool" label="30213" default="false" visible="true" enable="true"/>
|
||||
<setting id="audio_codec" type="select" label="30419" values="ac3|aac" default="ac3"/>
|
||||
<setting id="audio_playback_bitrate" type="select" label="30418" values="128|160|192|256|320|384|448|640" default="256" visible="true"/>
|
||||
<setting id="audio_max_channels" type="slider" label="30420" default="8" range="2,1,8" option="int" visible="true"/>
|
||||
<setting id="max_play_queue" type="slider" label="30447" default="200" range="20, 10, 1000" option="int" visible="true"/>
|
||||
|
||||
</category>
|
||||
<category label="30214">
|
||||
@@ -80,12 +81,13 @@
|
||||
<setting id="addCounts" type="bool" label="30116" default="false" visible="true" enable="true" />
|
||||
<setting id="addResumePercent" type="bool" label="30118" default="false" visible="true" enable="true" />
|
||||
<setting id="addSubtitleAvailable" type="bool" label="30163" default="false" visible="true" enable="true" />
|
||||
<setting id="hide_x_filtered_items_count" type="bool" label="30453" default="false" visible="true" enable="true" />
|
||||
<setting id="include_overview" type="bool" label="30181" default="true" visible="true" enable="true" />
|
||||
<setting id="include_media" type="bool" label="30182" default="true" visible="true" enable="true" />
|
||||
<setting id="add_user_ratings" type="bool" label="30348" default="true" visible="true" enable="true" />
|
||||
<setting id="include_people" type="bool" label="30183" default="false" visible="true" enable="true" />
|
||||
<setting id="hide_unwatched_details" type="bool" label="30023" default="false" visible="true" enable="true" />
|
||||
<setting id="episode_name_format" type="select" label="30019" default="{SeriesName} - {ItemName}" values="{SeriesName} - {ItemName}|{ItemName}|s{SeasonIndex}e{EpisodeIndex} - {ItemName}|{SeriesName} - s{SeasonIndex}e{EpisodeIndex} - {ItemName}" />
|
||||
<setting id="episode_name_format" type="select" label="30019" default="{SeriesName} - {ItemName}" values="{SeriesName} - {ItemName}|{ItemName}|S{SeasonIndex}E{EpisodeIndex} - {ItemName}|{SeriesName} - S{SeasonIndex}E{EpisodeIndex} - {ItemName}" />
|
||||
|
||||
<setting label="30222" type="lsep"/>
|
||||
<setting type="sep" />
|
||||
@@ -95,6 +97,11 @@
|
||||
<setting id="show_empty_folders" type="bool" label="30328" default="false" visible="true" enable="true" />
|
||||
<setting id="hide_watched" type="bool" label="30432" default="true" visible="true" enable="true" />
|
||||
|
||||
<setting label="30450" type="lsep"/>
|
||||
<setting type="sep" />
|
||||
<setting id="rewatch_days" type="slider" label="30451" default="0" range="0,1,365" option="int" visible="true"/>
|
||||
<setting id="rewatch_combine" type="bool" label="30452" default="false" visible="true" enable="true" />
|
||||
|
||||
<setting label="30223" type="lsep"/>
|
||||
<setting type="sep" />
|
||||
<setting id="moviePageSize" type="slider" label="30331" default="0" range="0,1,100" option="int" visible="true"/>
|
||||
@@ -103,6 +110,7 @@
|
||||
<setting label="30224" type="lsep"/>
|
||||
<setting type="sep" />
|
||||
<setting id="widget_select_action" type="select" label="30026" lvalues="30313|30314" default="0" visible="true"/>
|
||||
<setting id="interface_mode" type="select" label="30225" lvalues="30226|30227" default="0" visible="true"/>
|
||||
|
||||
</category>
|
||||
<category label="30111">
|
||||
|
||||
@@ -13,39 +13,53 @@
|
||||
<left>0</left>
|
||||
<top>0</top>
|
||||
<width>380</width>
|
||||
<height>100</height>
|
||||
<height>150</height>
|
||||
<texture border="40">bg.png</texture>
|
||||
</control>
|
||||
|
||||
<control type="label" id="3020">
|
||||
<width>120</width>
|
||||
<left>20</left>
|
||||
<top>5</top>
|
||||
<height>45</height>
|
||||
<label>Bitrate : </label>
|
||||
<textcolor>99FFFFFF</textcolor>
|
||||
<font>font14</font>
|
||||
<align>left</align>
|
||||
</control>
|
||||
<control type="label" id="3020">
|
||||
<width>120</width>
|
||||
<left>20</left>
|
||||
<top>5</top>
|
||||
<height>45</height>
|
||||
<label>Bitrate : </label>
|
||||
<textcolor>99FFFFFF</textcolor>
|
||||
<font>font14</font>
|
||||
<align>left</align>
|
||||
</control>
|
||||
|
||||
<control type="label" id="3030">
|
||||
<width>150</width>
|
||||
<left>120</left>
|
||||
<top>5</top>
|
||||
<height>45</height>
|
||||
<label>100 Mbs</label>
|
||||
<textcolor>99FFFFFF</textcolor>
|
||||
<font>font14</font>
|
||||
<align>left</align>
|
||||
</control>
|
||||
<control type="label" id="3030">
|
||||
<width>150</width>
|
||||
<left>120</left>
|
||||
<top>5</top>
|
||||
<height>45</height>
|
||||
<label>100 Mbs</label>
|
||||
<textcolor>99FFFFFF</textcolor>
|
||||
<font>font14</font>
|
||||
<align>left</align>
|
||||
</control>
|
||||
|
||||
<control type="slider" id="3000">
|
||||
<left>20</left>
|
||||
<top>55</top>
|
||||
<width>340</width>
|
||||
<height>30</height>
|
||||
<visible>true</visible>
|
||||
</control>
|
||||
<control type="slider" id="3000">
|
||||
<left>20</left>
|
||||
<top>55</top>
|
||||
<width>340</width>
|
||||
<height>30</height>
|
||||
<ondown>3011</ondown>
|
||||
<visible>true</visible>
|
||||
</control>
|
||||
|
||||
<control type="button" id="3011">
|
||||
<texturenofocus border="1" colordiffuse="ff161616">white.png</texturenofocus>
|
||||
<texturefocus border="1" colordiffuse="ff525252">white.png</texturefocus>
|
||||
<left>20</left>
|
||||
<top>100</top>
|
||||
<width>340</width>
|
||||
<height>40</height>
|
||||
<label></label>
|
||||
<onup>3000</onup>
|
||||
<font>font14</font>
|
||||
<align>center</align>
|
||||
</control>
|
||||
|
||||
</controls>
|
||||
</window>
|
||||
</window>
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
|
||||
$string_ids = @()
|
||||
|
||||
Select-String -path resources\language\resource.language.en_gb\strings.po -pattern "msgctxt " | select Line | ForEach {
|
||||
$id = [regex]::match($_.Line.ToString(), '\"#([0-9]+)\"').Groups[1].Value
|
||||
if($string_ids -contains $id)
|
||||
{
|
||||
Write-Host "ERROR: String ID Already Exists : " $id
|
||||
}
|
||||
else
|
||||
{
|
||||
$string_ids += $id
|
||||
Get-ChildItem *.py,settings.xml,resources\language\resource.language.en_gb\strings.po -recurse | Select-String -pattern $id | group Pattern | where {$_.Count -eq 1} | select Name, Count
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
|
||||
del /F /Q /S %HOMEPATH%\AppData\Roaming\Kodi\addons\plugin.video.jellycon
|
||||
rmdir /Q /S %HOMEPATH%\AppData\Roaming\Kodi\addons\plugin.video.jellycon
|
||||
|
||||
xcopy /Y addon.xml %HOMEPATH%\AppData\Roaming\Kodi\addons\plugin.video.jellycon\
|
||||
xcopy /Y default.py %HOMEPATH%\AppData\Roaming\Kodi\addons\plugin.video.jellycon\
|
||||
xcopy /Y fanart.jpg %HOMEPATH%\AppData\Roaming\Kodi\addons\plugin.video.jellycon\
|
||||
xcopy /Y icon.png %HOMEPATH%\AppData\Roaming\Kodi\addons\plugin.video.jellycon\
|
||||
xcopy /Y kodi.png %HOMEPATH%\AppData\Roaming\Kodi\addons\plugin.video.jellycon\
|
||||
xcopy /Y service.py %HOMEPATH%\AppData\Roaming\Kodi\addons\plugin.video.jellycon\
|
||||
|
||||
xcopy /E /Y resources %HOMEPATH%\AppData\Roaming\Kodi\addons\plugin.video.jellycon\resources\
|
||||
|
||||
cd "%programfiles%\Kodi"
|
||||
kodi.exe
|
||||
@@ -1,45 +0,0 @@
|
||||
import xml.etree.ElementTree as ET
|
||||
import subprocess
|
||||
from shutil import copy2, copytree, rmtree
|
||||
import os
|
||||
import sys
|
||||
|
||||
package_path = "package"
|
||||
|
||||
def ignore_files(path, item_list):
|
||||
return [".idea", ".git", ".gitignore", "scripts", package_path]
|
||||
|
||||
zip_path = "c:\\Program Files\\7-Zip\\7z.exe"
|
||||
addon_path = sys.argv[1]
|
||||
|
||||
tree = ET.parse(addon_path + "\\addon.xml")
|
||||
root = tree.getroot()
|
||||
|
||||
|
||||
id = root.attrib["id"]
|
||||
version = root.attrib["version"]
|
||||
|
||||
print (package_path + " - " + version)
|
||||
|
||||
try:
|
||||
rmtree(package_path + "\\" + id)
|
||||
except FileNotFoundError as err:
|
||||
pass
|
||||
|
||||
copytree(addon_path, package_path + "\\" + id, ignore=ignore_files)
|
||||
|
||||
zip_name = id + "-" + version + ".zip"
|
||||
|
||||
os.chdir(package_path)
|
||||
cmd_7zip = [zip_path, "a", zip_name, id]
|
||||
sp = subprocess.Popen(cmd_7zip, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
|
||||
sp.wait()
|
||||
os.chdir("..")
|
||||
|
||||
copy2(package_path + "\\" + id + "\\addon.xml", package_path + "\\addon.xml")
|
||||
|
||||
try:
|
||||
rmtree(package_path + "\\" + id)
|
||||
except FileNotFoundError as err:
|
||||
pass
|
||||
|
||||
43
service.py
43
service.py
@@ -8,16 +8,14 @@ import xbmc
|
||||
import xbmcaddon
|
||||
import xbmcgui
|
||||
|
||||
from resources.lib.downloadutils import DownloadUtils, save_user_details
|
||||
from resources.lib.loghandler import LazyLogger
|
||||
from resources.lib.lazylogger import LazyLogger
|
||||
from resources.lib.play_utils import Service, PlaybackService, send_progress
|
||||
from resources.lib.kodi_utils import HomeWindow
|
||||
from resources.lib.widgets import set_background_image, set_random_movies
|
||||
from resources.lib.websocket_client import WebSocketClient
|
||||
from resources.lib.menu_functions import set_library_window_values
|
||||
from resources.lib.context_monitor import ContextMonitor
|
||||
from resources.lib.server_detect import check_server, check_safe_delete_available, check_connection_speed
|
||||
from resources.lib.library_change_monitor import LibraryChangeMonitor
|
||||
from resources.lib.server_detect import check_server, check_connection_speed
|
||||
from resources.lib.monitors import LibraryChangeMonitor, ContextMonitor
|
||||
from resources.lib.datamanager import clear_old_cache_data
|
||||
from resources.lib.tracking import set_timing_enabled
|
||||
from resources.lib.image_server import HttpImageServerThread
|
||||
@@ -31,7 +29,7 @@ if log_timing_data:
|
||||
|
||||
# clear user and token when logging in
|
||||
home_window = HomeWindow()
|
||||
home_window.clear_property("userid")
|
||||
home_window.clear_property("user_name")
|
||||
home_window.clear_property("AccessToken")
|
||||
home_window.clear_property("Params")
|
||||
|
||||
@@ -53,16 +51,6 @@ while not monitor.abortRequested():
|
||||
|
||||
check_server()
|
||||
|
||||
download_utils = DownloadUtils()
|
||||
|
||||
# auth the service
|
||||
try:
|
||||
download_utils.authenticate()
|
||||
download_utils.get_user_id()
|
||||
except Exception as error:
|
||||
log.error("Error with initial service auth: {0}".format(error))
|
||||
|
||||
|
||||
image_server = HttpImageServerThread()
|
||||
image_server.start()
|
||||
|
||||
@@ -75,7 +63,6 @@ last_progress_update = time.time()
|
||||
last_content_check = time.time()
|
||||
last_background_update = 0
|
||||
last_random_movie_update = 0
|
||||
safe_delete_check = False
|
||||
|
||||
# start the library update monitor
|
||||
library_change_monitor = LibraryChangeMonitor()
|
||||
@@ -112,7 +99,7 @@ if enable_logging:
|
||||
time=8000,
|
||||
icon=xbmcgui.NOTIFICATION_WARNING)
|
||||
|
||||
prev_user_id = home_window.get_property("userid")
|
||||
prev_user = home_window.get_property("user_name")
|
||||
first_run = True
|
||||
home_window.set_property('exit', 'False')
|
||||
|
||||
@@ -131,15 +118,15 @@ while home_window.get_property('exit') == 'False':
|
||||
|
||||
if not screen_saver_active:
|
||||
user_changed = False
|
||||
if prev_user_id != home_window.get_property("userid"):
|
||||
if prev_user != home_window.get_property("user_name"):
|
||||
log.debug("user_change_detected")
|
||||
prev_user_id = home_window.get_property("userid")
|
||||
prev_user = home_window.get_property("user_name")
|
||||
user_changed = True
|
||||
|
||||
if user_changed or first_run:
|
||||
settings = xbmcaddon.Addon()
|
||||
settings = xbmcaddon.Addon()
|
||||
server_speed_check_data = settings.getSetting("server_speed_check_data")
|
||||
server_host = download_utils.get_server()
|
||||
server_host = settings.getSetting('server_address')
|
||||
if server_host is not None and server_host != "" and server_host != "<none>" and server_host not in server_speed_check_data:
|
||||
message = "This is the first time you have connected to this server.\nDo you want to run a connection speed test?"
|
||||
response = xbmcgui.Dialog().yesno("First Connection", message)
|
||||
@@ -168,10 +155,6 @@ while home_window.get_property('exit') == 'False':
|
||||
websocket_client = WebSocketClient(library_change_monitor)
|
||||
websocket_client.start()
|
||||
|
||||
if user_changed or not safe_delete_check:
|
||||
check_safe_delete_available()
|
||||
safe_delete_check = True
|
||||
|
||||
elif screen_saver_active:
|
||||
last_random_movie_update = time.time() - (random_movie_list_interval - 15)
|
||||
if background_interval != 0 and ((time.time() - last_background_update) > background_interval):
|
||||
@@ -193,16 +176,16 @@ websocket_client.stop_client()
|
||||
# call stop on the library update monitor
|
||||
library_change_monitor.stop()
|
||||
|
||||
# stop the play next episdoe service
|
||||
# stop the play next episode service
|
||||
if play_next_service:
|
||||
play_next_service.stop_servcie()
|
||||
play_next_service.stop_service()
|
||||
|
||||
# call stop on the context menu monitor
|
||||
if context_monitor:
|
||||
context_monitor.stop_monitor()
|
||||
|
||||
# clear user and token when loggin off
|
||||
home_window.clear_property("userid")
|
||||
# clear user and token when logging off
|
||||
home_window.clear_property("user_name")
|
||||
home_window.clear_property("AccessToken")
|
||||
home_window.clear_property("userimage")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user