mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-12-21 00:05:26 +03:00
Compare commits
1208 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
696a36b4a5 | ||
|
|
5fb4922c6f | ||
|
|
3738f95871 | ||
|
|
6797bdec04 | ||
|
|
764c6d5461 | ||
|
|
6973182ade | ||
|
|
f62af07381 | ||
|
|
46c37c0ae8 | ||
|
|
4ad71766fc | ||
|
|
9d60cc8c66 | ||
|
|
4a6243096a | ||
|
|
10cbdc8e8e | ||
|
|
4886fc467c | ||
|
|
8e2827cc39 | ||
|
|
395d2e4917 | ||
|
|
d31f5229da | ||
|
|
d6622818dc | ||
|
|
ba684d6d3a | ||
|
|
90c04a4640 | ||
|
|
06a1e1f166 | ||
|
|
31ad366aa9 | ||
|
|
10f33b0273 | ||
|
|
eaa1ac8013 | ||
|
|
ca3bb308b3 | ||
|
|
e790f024c2 | ||
|
|
250e0c75df | ||
|
|
cde7375049 | ||
|
|
c7fedfbca3 | ||
|
|
f520831025 | ||
|
|
2f0719a883 | ||
|
|
34ab99caf1 | ||
|
|
b2f94c0e40 | ||
|
|
65bff1181a | ||
|
|
efb14f0b58 | ||
|
|
75a4f04cce | ||
|
|
007fe34363 | ||
|
|
a7e31ef31f | ||
|
|
eae0c28e6d | ||
|
|
21950382b9 | ||
|
|
1af9c047fb | ||
|
|
2d19bfa7fb | ||
|
|
f5f7de64de | ||
|
|
754e76a61b | ||
|
|
09505e0988 | ||
|
|
67e206fa0f | ||
|
|
608fd873de | ||
|
|
05a4161fd3 | ||
|
|
05040351dc | ||
|
|
d75324afc9 | ||
|
|
38fcd31917 | ||
|
|
816d8a0216 | ||
|
|
e37ccd6ec0 | ||
|
|
f27477da26 | ||
|
|
c032a015a4 | ||
|
|
11e81b035a | ||
|
|
891a03c038 | ||
|
|
31aa6c486c | ||
|
|
1d9133a5e8 | ||
|
|
3375ca5a8c | ||
|
|
1596e93cc1 | ||
|
|
1a540f1cf7 | ||
|
|
05f5cd1bde | ||
|
|
f0fbd0232c | ||
|
|
72dd609109 | ||
|
|
13e94a8b1b | ||
|
|
d9e7883fb5 | ||
|
|
2d396cb589 | ||
|
|
b56031b9f3 | ||
|
|
fd86b141e2 | ||
|
|
427a3e9b08 | ||
|
|
3001f21f8d | ||
|
|
48b50a22a4 | ||
|
|
5e8496bc59 | ||
|
|
2dbc1153e8 | ||
|
|
b07c146fd9 | ||
|
|
cc2edc4d66 | ||
|
|
524357bfa8 | ||
|
|
7343e07fe5 | ||
|
|
6be8624373 | ||
|
|
740c95d557 | ||
|
|
31607fbb37 | ||
|
|
122cba2aa7 | ||
|
|
b44a70ff36 | ||
|
|
1b03f078b9 | ||
|
|
4c8f8cf64c | ||
|
|
d623f616fa | ||
|
|
fc8de8aead | ||
|
|
6480cfcc87 | ||
|
|
e36d424b5f | ||
|
|
f7e7d72688 | ||
|
|
3474568ce2 | ||
|
|
89f2dfd78a | ||
|
|
2c4c56d6d6 | ||
|
|
087d4153ae | ||
|
|
86772bd7bd | ||
|
|
4e2841f0d7 | ||
|
|
26fe4040bf | ||
|
|
fb7f29de18 | ||
|
|
d18252542d | ||
|
|
030fcaac15 | ||
|
|
7ebb043249 | ||
|
|
598b1c9966 | ||
|
|
cf36aaef2b | ||
|
|
f30af9cd5f | ||
|
|
5024c52c60 | ||
|
|
e971b62dab | ||
|
|
4ffec8ad26 | ||
|
|
69cc5814d8 | ||
|
|
414a318a0d | ||
|
|
758e35baba | ||
|
|
09921a00aa | ||
|
|
16a3bb2df4 | ||
|
|
2c684c0231 | ||
|
|
949a1cce21 | ||
|
|
0e787f4e9f | ||
|
|
bd31091648 | ||
|
|
4cd8903abc | ||
|
|
7b01de8db1 | ||
|
|
f73d8a44df | ||
|
|
752d65d020 | ||
|
|
c2667f99f4 | ||
|
|
c7e7aa0a61 | ||
|
|
fc79659549 | ||
|
|
e81a6adb95 | ||
|
|
80aedcd7e2 | ||
|
|
fc28c9237c | ||
|
|
b04200ca68 | ||
|
|
67fbbcfd12 | ||
|
|
e3dbed1c1a | ||
|
|
480a6607e2 | ||
|
|
4a30fee40d | ||
|
|
7f0fa74467 | ||
|
|
3d1d27230d | ||
|
|
9df1506794 | ||
|
|
2d0844b5db | ||
|
|
1ee016c997 | ||
|
|
221389089c | ||
|
|
59031ee3b8 | ||
|
|
d2e408539e | ||
|
|
a8140cc74b | ||
|
|
d5f080fefb | ||
|
|
35ff8ec713 | ||
|
|
764c901cd7 | ||
|
|
f85d45d17f | ||
|
|
022bd1b8b4 | ||
|
|
31305af7ff | ||
|
|
dd929d796f | ||
|
|
11fde02035 | ||
|
|
3d85014edc | ||
|
|
d125fbc43d | ||
|
|
427688a0a0 | ||
|
|
21cc38fcf4 | ||
|
|
ee7bf86e0f | ||
|
|
f8bb7a7ff4 | ||
|
|
6d3e6d800f | ||
|
|
208585d3f6 | ||
|
|
bf00dedc7f | ||
|
|
bf43dc00bb | ||
|
|
e64aaebbac | ||
|
|
1d443d2ff5 | ||
|
|
6507a9b2ee | ||
|
|
4cc4d57a78 | ||
|
|
605bf0e8c3 | ||
|
|
89e2af6b57 | ||
|
|
b864e9da2a | ||
|
|
f10382a696 | ||
|
|
297f25cfc2 | ||
|
|
afdef163ea | ||
|
|
6751560228 | ||
|
|
2012eb5e11 | ||
|
|
58068e249a | ||
|
|
3ddbda9aca | ||
|
|
1fef8bf266 | ||
|
|
3c4043199a | ||
|
|
0220309ea7 | ||
|
|
497b4f834f | ||
|
|
715ddbb3b0 | ||
|
|
0ff038f0a2 | ||
|
|
7322485a6d | ||
|
|
f77af5f6e4 | ||
|
|
2324c408ba | ||
|
|
037cf9e1ee | ||
|
|
5268553e7f | ||
|
|
5f7524aca2 | ||
|
|
86f5221f96 | ||
|
|
ecf85a73ec | ||
|
|
132ce3ece1 | ||
|
|
25deca9579 | ||
|
|
93d15cd969 | ||
|
|
4b91c9bf66 | ||
|
|
16adaa64c9 | ||
|
|
93fe7957fb | ||
|
|
fb96763f65 | ||
|
|
63342f89d4 | ||
|
|
47095e6cf8 | ||
|
|
f2062ba19b | ||
|
|
58061a7295 | ||
|
|
c6c398179a | ||
|
|
e498e47109 | ||
|
|
40089e2fd9 | ||
|
|
045a0419f6 | ||
|
|
80fb3dc2cb | ||
|
|
fcee64df09 | ||
|
|
757e0194b9 | ||
|
|
4625592a83 | ||
|
|
e3b844b5aa | ||
|
|
decaffed86 | ||
|
|
669c48cc8b | ||
|
|
d1fe24ac92 | ||
|
|
3fa43a1e08 | ||
|
|
028a98d2c1 | ||
|
|
0f70a81db3 | ||
|
|
d014a1dc1d | ||
|
|
e04a152ed0 | ||
|
|
8a680ae324 | ||
|
|
75996476a7 | ||
|
|
620d7b560d | ||
|
|
ab9859ecef | ||
|
|
37ea50a572 | ||
|
|
5cb3f04389 | ||
|
|
cedf50eeec | ||
|
|
c5fce647de | ||
|
|
10a0d6bdba | ||
|
|
0abe57e930 | ||
|
|
65c0b486aa | ||
|
|
ae0ecc1b10 | ||
|
|
dfff68b2f4 | ||
|
|
e4c5d51860 | ||
|
|
8c609bc9ce | ||
|
|
f486f5966f | ||
|
|
e91dd14b31 | ||
|
|
8a53b60912 | ||
|
|
a4b52b7264 | ||
|
|
5ae0ef0527 | ||
|
|
dfb1d704ed | ||
|
|
ffd6dac03a | ||
|
|
8f4895e8a5 | ||
|
|
a9302b8b53 | ||
|
|
c31b0b311b | ||
|
|
bba049c987 | ||
|
|
21c2acc520 | ||
|
|
394d23a73a | ||
|
|
276428878e | ||
|
|
04db0369d4 | ||
|
|
4ef7eda593 | ||
|
|
2242c8d793 | ||
|
|
bef665be36 | ||
|
|
bf9f342c13 | ||
|
|
a994edda04 | ||
|
|
9f6bca3658 | ||
|
|
2617a49b78 | ||
|
|
656bffbbb2 | ||
|
|
8104e739d5 | ||
|
|
632968dc81 | ||
|
|
ed69e690b8 | ||
|
|
20775116f7 | ||
|
|
446f9bf81f | ||
|
|
913e80fd55 | ||
|
|
9a4a01fb0e | ||
|
|
df92df7bd6 | ||
|
|
78742b8e4c | ||
|
|
942c400c19 | ||
|
|
5587dd8bfb | ||
|
|
8d1fc3f984 | ||
|
|
318e0d4a24 | ||
|
|
bc00617df7 | ||
|
|
2c26517172 | ||
|
|
51648a2a21 | ||
|
|
12df381495 | ||
|
|
17ca23d73b | ||
|
|
41df94115f | ||
|
|
0250204f14 | ||
|
|
0419deeec4 | ||
|
|
9020f68ce1 | ||
|
|
557c4d065d | ||
|
|
6cc1bd544a | ||
|
|
aba22b92bc | ||
|
|
040871459b | ||
|
|
6263b73d9c | ||
|
|
1cc433eabc | ||
|
|
5982cdad90 | ||
|
|
d450169964 | ||
|
|
e823c11b46 | ||
|
|
c328417d29 | ||
|
|
c4192f9f8b | ||
|
|
5368112d90 | ||
|
|
ed07ed44ae | ||
|
|
9993dafe54 | ||
|
|
6bdb5debd2 | ||
|
|
65403747df | ||
|
|
594b271383 | ||
|
|
27f9981142 | ||
|
|
3d3d879b99 | ||
|
|
53ed6e5e6e | ||
|
|
d0e4e0f600 | ||
|
|
311caf3fc3 | ||
|
|
7c13021def | ||
|
|
c8788d83fb | ||
|
|
331260cf80 | ||
|
|
58e5931a32 | ||
|
|
02041fa6f4 | ||
|
|
fcd299965d | ||
|
|
79d5a53aea | ||
|
|
f1086a72bf | ||
|
|
95d001a053 | ||
|
|
b7fd68d366 | ||
|
|
c84729a4f4 | ||
|
|
4951ec9814 | ||
|
|
edba82db37 | ||
|
|
1d1e6dede9 | ||
|
|
f384822aa5 | ||
|
|
1ac282b12e | ||
|
|
588a13377c | ||
|
|
fb1de5a921 | ||
|
|
71ed840944 | ||
|
|
dab8e15052 | ||
|
|
e47d121985 | ||
|
|
c0b95dbc79 | ||
|
|
647adc51c8 | ||
|
|
7668ecf9c9 | ||
|
|
3769453541 | ||
|
|
8c2af50170 | ||
|
|
1e97e4d462 | ||
|
|
27e7e792b3 | ||
|
|
7429c07c05 | ||
|
|
91afaaf8fe | ||
|
|
333bd2107a | ||
|
|
25d3d0b731 | ||
|
|
77addb2283 | ||
|
|
9651a78b0c | ||
|
|
9eba31185a | ||
|
|
aea7edf0fa | ||
|
|
42d4834f63 | ||
|
|
ba78f6a0ff | ||
|
|
feb5b62ad4 | ||
|
|
5ccba7cf8a | ||
|
|
848cfc32cc | ||
|
|
5510e8ebee | ||
|
|
9c02e99e35 | ||
|
|
148db8b81a | ||
|
|
e342b7bc71 | ||
|
|
f1c93ae618 | ||
|
|
4e229ad86b | ||
|
|
e88f079da6 | ||
|
|
4e8de67aca | ||
|
|
a85488cd20 | ||
|
|
5a7cca9d1b | ||
|
|
d6c6f3c10c | ||
|
|
38f52a139e | ||
|
|
194da8416b | ||
|
|
f3e7bc0573 | ||
|
|
c3fa299acc | ||
|
|
852460b991 | ||
|
|
33b67a357f | ||
|
|
4db31acff9 | ||
|
|
968e282c90 | ||
|
|
1731bf7372 | ||
|
|
0804bed66d | ||
|
|
a0606b5730 | ||
|
|
9ba6227db4 | ||
|
|
9bab93262e | ||
|
|
0f9006c81f | ||
|
|
b3438559cc | ||
|
|
8e5cccb22c | ||
|
|
500c0b9cba | ||
|
|
5054a77dcf | ||
|
|
dac2c98d8a | ||
|
|
4df3333b71 | ||
|
|
5262e50fee | ||
|
|
547d0ecf58 | ||
|
|
6e07eab247 | ||
|
|
96b3d37caf | ||
|
|
aafed63c3f | ||
|
|
2e9a3d45c2 | ||
|
|
e281c79d6f | ||
|
|
38ec68c488 | ||
|
|
da61998ad6 | ||
|
|
f28dd79fb1 | ||
|
|
c2e57aba27 | ||
|
|
4a3e42e779 | ||
|
|
67f399dccf | ||
|
|
eb95b025d4 | ||
|
|
de45cfdd8c | ||
|
|
47966793c0 | ||
|
|
0c49079c16 | ||
|
|
d82d6b6aef | ||
|
|
7ae526da8b | ||
|
|
e79d44d9f1 | ||
|
|
fb7de2f966 | ||
|
|
db54fe4c70 | ||
|
|
1eb26bdf08 | ||
|
|
cbd0e71c07 | ||
|
|
2db1826ed8 | ||
|
|
cf4e64f430 | ||
|
|
9b39404b9a | ||
|
|
00fe66a38c | ||
|
|
406af5f086 | ||
|
|
e7e7d96f51 | ||
|
|
785fa76ac6 | ||
|
|
6c967c5982 | ||
|
|
f03e279382 | ||
|
|
1bc2b12ee3 | ||
|
|
469a17b3ca | ||
|
|
affb8c8673 | ||
|
|
74aa38acd7 | ||
|
|
d4ded281aa | ||
|
|
c597f0de35 | ||
|
|
3965f90236 | ||
|
|
8af4417f8f | ||
|
|
83948420a4 | ||
|
|
8c53407a9d | ||
|
|
4a5c526ccc | ||
|
|
69a81c0bc2 | ||
|
|
320707d44c | ||
|
|
2690ac299b | ||
|
|
268b099ca8 | ||
|
|
33171a58b5 | ||
|
|
73c1cdb32a | ||
|
|
13bfe5093e | ||
|
|
99bed9a9c3 | ||
|
|
8ef41020d9 | ||
|
|
fca226bdfd | ||
|
|
bca7a26ffd | ||
|
|
60df855b26 | ||
|
|
44ed037e73 | ||
|
|
50ce7572b4 | ||
|
|
74695428fe | ||
|
|
139807719c | ||
|
|
1e2050f106 | ||
|
|
a23f04623e | ||
|
|
1f30a50f4a | ||
|
|
098de6b050 | ||
|
|
a0d31a49a0 | ||
|
|
6bbb968b57 | ||
|
|
6c6e9ca9f2 | ||
|
|
89d4ce309d | ||
|
|
b43317c5e1 | ||
|
|
5917e91447 | ||
|
|
9753a76905 | ||
|
|
d978ae1996 | ||
|
|
6016a27736 | ||
|
|
24b76dbed8 | ||
|
|
dab25a0eeb | ||
|
|
566646ad8b | ||
|
|
6c1ca6f737 | ||
|
|
aa0c20afd5 | ||
|
|
46acff4113 | ||
|
|
de5c0bab70 | ||
|
|
5181427234 | ||
|
|
c79324154f | ||
|
|
53beebc774 | ||
|
|
ba003e06ef | ||
|
|
1d631540ac | ||
|
|
3ed9d32f68 | ||
|
|
3ecfd1fdd1 | ||
|
|
24574d4964 | ||
|
|
512ab8c6aa | ||
|
|
029bafdf9c | ||
|
|
0849c4a447 | ||
|
|
5238ba5d8f | ||
|
|
6b1a64652f | ||
|
|
9961c8c459 | ||
|
|
18418b6892 | ||
|
|
d4bc7b5a5a | ||
|
|
e2d0f67077 | ||
|
|
5ef63e738d | ||
|
|
7bbcb455c0 | ||
|
|
2ad54cd09d | ||
|
|
7c9803e135 | ||
|
|
480999e8e6 | ||
|
|
ef17ec700b | ||
|
|
4b34b0cfea | ||
|
|
60fc53306d | ||
|
|
77d4fec6eb | ||
|
|
c6188e26af | ||
|
|
18717d103a | ||
|
|
6834b64922 | ||
|
|
29ff80d69c | ||
|
|
4a700778e3 | ||
|
|
56e3063342 | ||
|
|
781cca0c82 | ||
|
|
eab35890dc | ||
|
|
967d5deeb7 | ||
|
|
51ba28bd65 | ||
|
|
a94aeb5c87 | ||
|
|
13f2783a8e | ||
|
|
7554f63551 | ||
|
|
25253cf961 | ||
|
|
77a5617774 | ||
|
|
f274d024ce | ||
|
|
395072239d | ||
|
|
e2f6ecaef6 | ||
|
|
48e7274d37 | ||
|
|
9f3aa2cead | ||
|
|
bb50363812 | ||
|
|
9a38e4dc8a | ||
|
|
c607c95e64 | ||
|
|
18ae107ce4 | ||
|
|
3f80b16ffa | ||
|
|
72aa364aa5 | ||
|
|
0d5fbcb031 | ||
|
|
a35ea49c99 | ||
|
|
c45b6aa53e | ||
|
|
4b4399fba6 | ||
|
|
c06598635f | ||
|
|
a15098dc00 | ||
|
|
4811e76860 | ||
|
|
64a4f259a2 | ||
|
|
bdfd042d70 | ||
|
|
a993420676 | ||
|
|
fb6a901374 | ||
|
|
86a4d15a32 | ||
|
|
25c2267a89 | ||
|
|
b86f049e66 | ||
|
|
12fea24590 | ||
|
|
26e2ffdd31 | ||
|
|
d9ab654abe | ||
|
|
c44f96b727 | ||
|
|
c5ac36c886 | ||
|
|
ff9a0c7e55 | ||
|
|
056e19f350 | ||
|
|
f8ba55e202 | ||
|
|
4ea76f9cdc | ||
|
|
88f56cd0c4 | ||
|
|
69ea15f73a | ||
|
|
b7ae044e65 | ||
|
|
d8d237f6f2 | ||
|
|
18e1d03a89 | ||
|
|
3947f2315d | ||
|
|
cb9e50b2ea | ||
|
|
e620bb9512 | ||
|
|
8b04fe7633 | ||
|
|
2cb747651b | ||
|
|
46897aab4f | ||
|
|
892787cb1a | ||
|
|
be77e14db9 | ||
|
|
34af7501fa | ||
|
|
183ef34422 | ||
|
|
637936cb9f | ||
|
|
fc59b0ab77 | ||
|
|
d8b312674d | ||
|
|
ebae7229c1 | ||
|
|
3df8cda110 | ||
|
|
43cf11aa35 | ||
|
|
6d74184cfb | ||
|
|
21f0a7e020 | ||
|
|
cb6d2cbd2d | ||
|
|
ce51025e7c | ||
|
|
5a054e5150 | ||
|
|
98f003f71a | ||
|
|
b9efcace79 | ||
|
|
1aaa8de1f9 | ||
|
|
5e2e190f3e | ||
|
|
828434058f | ||
|
|
dfbf5fc9fa | ||
|
|
8029cd3ebb | ||
|
|
e970d7a6aa | ||
|
|
350e795640 | ||
|
|
f5bda652c4 | ||
|
|
e8189cd0f6 | ||
|
|
18231fedef | ||
|
|
935c7231eb | ||
|
|
da2c7db0df | ||
|
|
83d98ac92d | ||
|
|
b997b12d27 | ||
|
|
6887e790c8 | ||
|
|
373a1f72bf | ||
|
|
0d43b06042 | ||
|
|
ced9868357 | ||
|
|
23c867f946 | ||
|
|
42c233c74e | ||
|
|
1f8e74f3a8 | ||
|
|
d6835f8dd6 | ||
|
|
86940e96d5 | ||
|
|
75d90c8e4c | ||
|
|
ecbc0538f6 | ||
|
|
2a26760911 | ||
|
|
19b6808602 | ||
|
|
c2202be0f8 | ||
|
|
9729ae52a3 | ||
|
|
7cc69f30c4 | ||
|
|
e33706ab25 | ||
|
|
4018b7e2d5 | ||
|
|
8425d76198 | ||
|
|
9bf009c4f8 | ||
|
|
2845e7e101 | ||
|
|
c78298789d | ||
|
|
a6bde0943e | ||
|
|
7bb8985f11 | ||
|
|
db1ebe2559 | ||
|
|
dbebc4774f | ||
|
|
0fbc4545d1 | ||
|
|
8414285b58 | ||
|
|
5d4bef5478 | ||
|
|
cac3a3e945 | ||
|
|
7ec42b89a0 | ||
|
|
bca569da42 | ||
|
|
a82303ccd1 | ||
|
|
c720504e39 | ||
|
|
a2dd2ddd55 | ||
|
|
5835c4b21d | ||
|
|
d8e6808d77 | ||
|
|
9e58e31de0 | ||
|
|
77602aff88 | ||
|
|
1ffd443d5a | ||
|
|
1dc5a624a7 | ||
|
|
af8f86b3de | ||
|
|
bfc3954995 | ||
|
|
4ed90d4658 | ||
|
|
3a6a5baa8e | ||
|
|
18f0d996c0 | ||
|
|
da2554bd53 | ||
|
|
f2811323c2 | ||
|
|
3f878d63a5 | ||
|
|
a5882ae162 | ||
|
|
c74028d08d | ||
|
|
3f13851be5 | ||
|
|
ea446fd4a3 | ||
|
|
585b5201f1 | ||
|
|
8d98885cda | ||
|
|
da9418c1b2 | ||
|
|
9dba930a85 | ||
|
|
7722cb3ffa | ||
|
|
3e6819c718 | ||
|
|
41fb1e5106 | ||
|
|
64d5ec12e2 | ||
|
|
d409623086 | ||
|
|
9af28607c9 | ||
|
|
81a8ebde22 | ||
|
|
221a95c93c | ||
|
|
982ac32471 | ||
|
|
d48275a785 | ||
|
|
a4e98a0390 | ||
|
|
0fbdb79df7 | ||
|
|
87dc60d4aa | ||
|
|
d6b56dde62 | ||
|
|
0302144b22 | ||
|
|
269b94254b | ||
|
|
2f377e0a0f | ||
|
|
3b96c78515 | ||
|
|
e150174ece | ||
|
|
33e069e461 | ||
|
|
8055b70ab1 | ||
|
|
593b7327cf | ||
|
|
9d795adc3e | ||
|
|
0ff38b6012 | ||
|
|
fe43e279c8 | ||
|
|
d18823ced1 | ||
|
|
05bbf71b6d | ||
|
|
8bf88f4cb2 | ||
|
|
db4a72df10 | ||
|
|
406fb045c2 | ||
|
|
32992b6143 | ||
|
|
da169dddb5 | ||
|
|
250f03d2d9 | ||
|
|
d8cb34dbbc | ||
|
|
edf5ee0cc4 | ||
|
|
8fd9f5b6a4 | ||
|
|
2f4a00d322 | ||
|
|
86089ec03a | ||
|
|
9849c183ac | ||
|
|
29d6783471 | ||
|
|
236e21efcb | ||
|
|
30ec203eff | ||
|
|
bcb32ec6ad | ||
|
|
eb4b705167 | ||
|
|
d6c669a7c8 | ||
|
|
1b84446831 | ||
|
|
fb256b7aa0 | ||
|
|
382b8bb509 | ||
|
|
00234a5ece | ||
|
|
57cefb432a | ||
|
|
7be4a8500c | ||
|
|
74d2698c5f | ||
|
|
4727f69fc9 | ||
|
|
1e6c41e333 | ||
|
|
bee8f58265 | ||
|
|
a71040ba1b | ||
|
|
a6a4cd5667 | ||
|
|
3a5bbcf2a8 | ||
|
|
449074e73f | ||
|
|
2fc97212a7 | ||
|
|
f1ef0b0b4c | ||
|
|
387b4dea25 | ||
|
|
3014866f65 | ||
|
|
37985c2e26 | ||
|
|
139e3c19ee | ||
|
|
da860e6e54 | ||
|
|
ce03662fa7 | ||
|
|
49923e50db | ||
|
|
c3c52b6682 | ||
|
|
80281e599d | ||
|
|
3a88a3c795 | ||
|
|
d6e98f9a50 | ||
|
|
2bcbffee0c | ||
|
|
22ffc5aee4 | ||
|
|
ee3a4531a0 | ||
|
|
aff740c596 | ||
|
|
38d9eeffbe | ||
|
|
d6d9fce898 | ||
|
|
f60ad53393 | ||
|
|
e8461d3317 | ||
|
|
9dd512df80 | ||
|
|
5b0bd88892 | ||
|
|
70c85925af | ||
|
|
e449182641 | ||
|
|
fcfe02ee73 | ||
|
|
b8b650540d | ||
|
|
e1d523ee45 | ||
|
|
ceb8b9f740 | ||
|
|
8413c56392 | ||
|
|
88038d9644 | ||
|
|
c846da4f9e | ||
|
|
546f4cd46f | ||
|
|
e216702bcf | ||
|
|
be89a5e719 | ||
|
|
84d56976ba | ||
|
|
0ef2b46106 | ||
|
|
52294881b1 | ||
|
|
5e8a2db029 | ||
|
|
262eefd8db | ||
|
|
73e8758d84 | ||
|
|
181de97ce5 | ||
|
|
ae5514afd6 | ||
|
|
83af2db679 | ||
|
|
0b3e6548db | ||
|
|
72beadc74d | ||
|
|
f0e74c2c6b | ||
|
|
d351fa0c1e | ||
|
|
20033f2275 | ||
|
|
c4c0894b29 | ||
|
|
c4f51e16a5 | ||
|
|
56dcc45dc0 | ||
|
|
be89d53a9e | ||
|
|
3ac7531385 | ||
|
|
cb1ff69585 | ||
|
|
a50fb922c5 | ||
|
|
593c6c071c | ||
|
|
d573f2d671 | ||
|
|
1ce5939362 | ||
|
|
4d335d8f13 | ||
|
|
c118f111b6 | ||
|
|
52e91243e5 | ||
|
|
9faa68b26f | ||
|
|
aadf7676d1 | ||
|
|
08ca1337a9 | ||
|
|
07072d9f7b | ||
|
|
7e3c45c917 | ||
|
|
548270772c | ||
|
|
cb7bffc233 | ||
|
|
da2caa2902 | ||
|
|
ab0e851db9 | ||
|
|
32f393d57f | ||
|
|
78e4e2ed92 | ||
|
|
42d5a48491 | ||
|
|
20dac6d6b8 | ||
|
|
1cdcace061 | ||
|
|
95ee3c72e3 | ||
|
|
66eabcdd39 | ||
|
|
1d94607a30 | ||
|
|
1385d89df6 | ||
|
|
8b073e2ba5 | ||
|
|
34da7de47d | ||
|
|
021a1887fb | ||
|
|
6772ac5603 | ||
|
|
b630e9de82 | ||
|
|
7774977cdd | ||
|
|
5ac6d0ae59 | ||
|
|
fa3a8108e5 | ||
|
|
660f6174b3 | ||
|
|
8af1e93cd4 | ||
|
|
cabb824f2a | ||
|
|
b4c5ff89fd | ||
|
|
78324ff797 | ||
|
|
885a000da7 | ||
|
|
aad34e62ca | ||
|
|
45d8ace9bb | ||
|
|
5e4697802f | ||
|
|
f6227e99cc | ||
|
|
ae24d644db | ||
|
|
b982d7c239 | ||
|
|
c713824bf9 | ||
|
|
ea851317e7 | ||
|
|
8985fb8d58 | ||
|
|
b5e8cce4cf | ||
|
|
211ae30188 | ||
|
|
e18b89ca27 | ||
|
|
ebd2a30087 | ||
|
|
fd361421b1 | ||
|
|
f7a46c7a56 | ||
|
|
2a1f6361a5 | ||
|
|
4519ce26e2 | ||
|
|
49d9649b8e | ||
|
|
1ea219bf3f | ||
|
|
d0f2b3a747 | ||
|
|
ffcf6bdd3a | ||
|
|
795f2c8774 | ||
|
|
f8aff0c51d | ||
|
|
055e43eda7 | ||
|
|
c8cb908004 | ||
|
|
8ab08dd041 | ||
|
|
8487319374 | ||
|
|
91e99effc9 | ||
|
|
0e2e731103 | ||
|
|
6822975fd3 | ||
|
|
12e4c1c7ae | ||
|
|
6786dfcabd | ||
|
|
f06b9a14f3 | ||
|
|
838541b825 | ||
|
|
1d1d7e8a37 | ||
|
|
d3afa53191 | ||
|
|
450f246f95 | ||
|
|
b9a111432a | ||
|
|
581a7fe078 | ||
|
|
a430568082 | ||
|
|
d7c6d16250 | ||
|
|
3a831994f6 | ||
|
|
dc68d61491 | ||
|
|
a05d803d4c | ||
|
|
b4893b9ac9 | ||
|
|
b0608d26b4 | ||
|
|
67b1f9f716 | ||
|
|
39195aae09 | ||
|
|
cc598a86f1 | ||
|
|
ffe79c8982 | ||
|
|
05ad2e9b3f | ||
|
|
42abb5a993 | ||
|
|
a4055779f6 | ||
|
|
1a3543e5a5 | ||
|
|
42e0b32c7d | ||
|
|
85a58fd655 | ||
|
|
a709cbdc64 | ||
|
|
08b63a7c11 | ||
|
|
51edd5d067 | ||
|
|
ee89236fe8 | ||
|
|
fee42e883c | ||
|
|
cc3422b96b | ||
|
|
50279be686 | ||
|
|
0e617933f6 | ||
|
|
f74bfcb343 | ||
|
|
64b6cfa3dc | ||
|
|
bb056f4b59 | ||
|
|
ce11869a1a | ||
|
|
e3b19c22a7 | ||
|
|
05fd76c0fa | ||
|
|
7165868509 | ||
|
|
4190410c7e | ||
|
|
b673054c8d | ||
|
|
e051ca6ff6 | ||
|
|
d8d6c6f254 | ||
|
|
2ffab720fb | ||
|
|
07f163a4c3 | ||
|
|
883575893b | ||
|
|
d1a0497f55 | ||
|
|
ded9dee22c | ||
|
|
e8f6a61131 | ||
|
|
fd7f420af2 | ||
|
|
eaa6cb0ddc | ||
|
|
8af256f9c2 | ||
|
|
9f83ee7b3e | ||
|
|
e0315b5695 | ||
|
|
fd36bbede8 | ||
|
|
b4fdfb562d | ||
|
|
48ad18d12b | ||
|
|
fe197415ca | ||
|
|
0231bd88a7 | ||
|
|
15806de2aa | ||
|
|
68a7ed6b7c | ||
|
|
48e1a55d9e | ||
|
|
2c9e056d52 | ||
|
|
8191efb90c | ||
|
|
1d7d4c5738 | ||
|
|
3701ce4037 | ||
|
|
b2ffad9ce9 | ||
|
|
f4015f82e0 | ||
|
|
cab7fa2671 | ||
|
|
6a3ed5d519 | ||
|
|
f2d0d1f646 | ||
|
|
d6a729c119 | ||
|
|
4e7675e78f | ||
|
|
b6f5c33191 | ||
|
|
1cbcddfbd2 | ||
|
|
80d011bb4f | ||
|
|
59ff083f5d | ||
|
|
cc3b1e5cc8 | ||
|
|
58591da0b8 | ||
|
|
905a253ff5 | ||
|
|
3cd31cadf8 | ||
|
|
48da8f429e | ||
|
|
8d9428ebdc | ||
|
|
f6f0a8a481 | ||
|
|
a30687a15a | ||
|
|
404bd04cbc | ||
|
|
bd550ef996 | ||
|
|
e05e002b8b | ||
|
|
ede0439b12 | ||
|
|
becbad981c | ||
|
|
3d01aa1ae4 | ||
|
|
0fec7994a8 | ||
|
|
090fea21ea | ||
|
|
52dd570142 | ||
|
|
28483bdb54 | ||
|
|
722120af74 | ||
|
|
df5e87409a | ||
|
|
94789860b1 | ||
|
|
fd6d35e1d0 | ||
|
|
cce90d2b56 | ||
|
|
8106c8393b | ||
|
|
0b80902cc8 | ||
|
|
189b99df16 | ||
|
|
490e22c790 | ||
|
|
a356c1417a | ||
|
|
07cba6cbcf | ||
|
|
411139cd78 | ||
|
|
29f3330091 | ||
|
|
8108e295dc | ||
|
|
aa25dd1a0b | ||
|
|
23c52c3fb9 | ||
|
|
a5aa482b6c | ||
|
|
8d298e0e36 | ||
|
|
13f1ea2c19 | ||
|
|
9ad182502f | ||
|
|
b2767eceff | ||
|
|
bc8a0eeead | ||
|
|
73df5bdbe9 | ||
|
|
e6b95db132 | ||
|
|
e30cf63aef | ||
|
|
571afa4fe2 | ||
|
|
42f2799d66 | ||
|
|
384f867228 | ||
|
|
cf85e2327e | ||
|
|
2f8f9e6853 | ||
|
|
06d9423f00 | ||
|
|
37be6c87eb | ||
|
|
c9b88ab741 | ||
|
|
0dab69b551 | ||
|
|
ff4cbfc6df | ||
|
|
c72144111e | ||
|
|
3518400b22 | ||
|
|
adf037c44c | ||
|
|
73038ee3f7 | ||
|
|
920c39454c | ||
|
|
edcfd8b565 | ||
|
|
7327bb91a3 | ||
|
|
6a5488c651 | ||
|
|
1cf1e9bfa1 | ||
|
|
7469ed4e6e | ||
|
|
c7f648f86a | ||
|
|
3069c749b4 | ||
|
|
d02642bf7b | ||
|
|
803bf563d7 | ||
|
|
d16f38dbe1 | ||
|
|
e8813ced3c | ||
|
|
a1fcf4ea0d | ||
|
|
c8dd72886b | ||
|
|
c64cc733d2 | ||
|
|
190bc46c1b | ||
|
|
ae73f7b3e3 | ||
|
|
060eb98cc5 | ||
|
|
da16de48aa | ||
|
|
e62198650e | ||
|
|
88f13492c7 | ||
|
|
65cd3ed597 | ||
|
|
c27aff1c63 | ||
|
|
0586598d33 | ||
|
|
e8cf72e925 | ||
|
|
fc7c211025 | ||
|
|
3d441d4a73 | ||
|
|
35d97dc949 | ||
|
|
18189644e3 | ||
|
|
56365e9237 | ||
|
|
9da5d3acc2 | ||
|
|
3320d4feeb | ||
|
|
90b9a95619 | ||
|
|
3a6624f701 | ||
|
|
2b47006662 | ||
|
|
acb9afd908 | ||
|
|
7e4cc9f513 | ||
|
|
ca910325f3 | ||
|
|
8fc8fc0622 | ||
|
|
2dc14aa85d | ||
|
|
26e20d1cd5 | ||
|
|
217d35ee74 | ||
|
|
790266d314 | ||
|
|
eba1f05c03 | ||
|
|
b35dcbb9f0 | ||
|
|
3a5e3ade01 | ||
|
|
fbc82c88be | ||
|
|
9eada88545 | ||
|
|
6561021926 | ||
|
|
d72d0fb865 | ||
|
|
875392c77f | ||
|
|
449dd1a6a2 | ||
|
|
9a7a5ef50e | ||
|
|
bc18d5341c | ||
|
|
99dfb8549f | ||
|
|
4f14b479bb | ||
|
|
f229c641a1 | ||
|
|
235125df57 | ||
|
|
d7da475aad | ||
|
|
8de4eb7d19 | ||
|
|
8a5198e6a3 | ||
|
|
85966b54fb | ||
|
|
469590c9c5 | ||
|
|
e066a02403 | ||
|
|
924ec0c191 | ||
|
|
daaa007fea | ||
|
|
0addc9ef46 | ||
|
|
9f8b716f40 | ||
|
|
edfd950aad | ||
|
|
bb8df8dfa0 | ||
|
|
f952988fb3 | ||
|
|
97639e5c85 | ||
|
|
d42ef36bf9 | ||
|
|
1bd477e2e5 | ||
|
|
949393043d | ||
|
|
55538764fa | ||
|
|
3b52035ee0 | ||
|
|
c5430f86b0 | ||
|
|
1e94023927 | ||
|
|
a00c0defa8 | ||
|
|
e63b18f17d | ||
|
|
72ab479d1f | ||
|
|
bf7d8fdf4a | ||
|
|
582226c133 | ||
|
|
529d804414 | ||
|
|
d116efe1f7 | ||
|
|
c1f76eb8ab | ||
|
|
d00e43735f | ||
|
|
04d03c5cf9 | ||
|
|
e9e152d2fc | ||
|
|
cfd5d1a4f2 | ||
|
|
440350a3f6 | ||
|
|
fe4c3fddb4 | ||
|
|
38f96af079 | ||
|
|
321c440739 | ||
|
|
e241589969 | ||
|
|
47f08fbb12 | ||
|
|
a0195420df | ||
|
|
7aa975325a | ||
|
|
d0980f0da5 | ||
|
|
900dc851e6 | ||
|
|
933ef43889 | ||
|
|
2b1e3aa45f | ||
|
|
67465c6e10 | ||
|
|
5b1f36ef27 | ||
|
|
b30d702782 | ||
|
|
bddfca6215 | ||
|
|
a358631040 | ||
|
|
49b61f238e | ||
|
|
99acf83dfa | ||
|
|
e5ffa45dbe | ||
|
|
22a64f37f5 | ||
|
|
0e422a33d6 | ||
|
|
256e6dc195 | ||
|
|
e0e5a487c3 | ||
|
|
801726ce38 | ||
|
|
19319e8eb6 | ||
|
|
d707e969fa | ||
|
|
4a03ac4022 | ||
|
|
eca3c099d9 | ||
|
|
8ea0c72070 | ||
|
|
351bac44c5 | ||
|
|
9c4239af01 | ||
|
|
9b224d7080 | ||
|
|
ca320ba7ac | ||
|
|
ae0732136f | ||
|
|
d7b7be395b | ||
|
|
9d0a08571e | ||
|
|
f8dd182e42 | ||
|
|
23f5c1d90b | ||
|
|
e867446437 | ||
|
|
f50a997e40 | ||
|
|
006e81588a | ||
|
|
65bd052f3e | ||
|
|
17c60f46db | ||
|
|
a36658f6f0 | ||
|
|
f11a4368bb | ||
|
|
9fa60ec934 | ||
|
|
089ad8e7c2 | ||
|
|
b062577d81 | ||
|
|
8f41ba4d3a | ||
|
|
ba610b5094 | ||
|
|
e566d9a231 | ||
|
|
742bef5b5f | ||
|
|
aacafee1de | ||
|
|
382e8699a2 | ||
|
|
3ed6f37030 | ||
|
|
51ed47f4c4 | ||
|
|
5b3d8a6d76 | ||
|
|
cc719fd77c | ||
|
|
8fd0bc63b9 | ||
|
|
9014e16037 | ||
|
|
9741817af4 | ||
|
|
f4ae36b2a8 | ||
|
|
587bb85b41 | ||
|
|
1a4b271314 | ||
|
|
f2e50f50bd | ||
|
|
22879a603e | ||
|
|
26ca4b607b | ||
|
|
106d1d18ed | ||
|
|
b67c1b933e | ||
|
|
f0acc0446c | ||
|
|
80691e53b0 | ||
|
|
d655283ef0 | ||
|
|
25f0315e91 | ||
|
|
0efc699e3d | ||
|
|
39ef1106d7 | ||
|
|
58b582bdcb | ||
|
|
c5c7a3c4ee | ||
|
|
a5288115a8 | ||
|
|
dd15c808cb | ||
|
|
decc475f7c | ||
|
|
5665933849 | ||
|
|
25a428373c | ||
|
|
009c95d972 | ||
|
|
9d37fd96f1 | ||
|
|
8bfb54a41b | ||
|
|
17703c8bd2 | ||
|
|
1077570ca8 | ||
|
|
e8d93b3485 | ||
|
|
56de8c893a | ||
|
|
9dcaafe700 | ||
|
|
17d8de4962 | ||
|
|
b936c43932 | ||
|
|
c8e3c1737a | ||
|
|
f2dae8ee51 | ||
|
|
3a2a0fbfe8 | ||
|
|
81475e361b | ||
|
|
50c127fd9a | ||
|
|
bf4de012da | ||
|
|
debb8e56fd | ||
|
|
ddc18a1ca7 | ||
|
|
0abdfbb526 | ||
|
|
e9519de07d | ||
|
|
783e74d9c9 | ||
|
|
78a5d999f4 | ||
|
|
846456b41e | ||
|
|
41343b9220 | ||
|
|
016bad1ea3 | ||
|
|
e04f652eff | ||
|
|
03ec62e478 | ||
|
|
dadd6e11b1 | ||
|
|
c28283aa7c | ||
|
|
2e53f4c2e9 | ||
|
|
f1d6f04572 | ||
|
|
f818053a43 | ||
|
|
874a6bf38b | ||
|
|
deb9d97d37 | ||
|
|
672013c23d | ||
|
|
b73d081bd2 | ||
|
|
ba671569b4 | ||
|
|
2c65fe53f2 | ||
|
|
2c62f8dbd5 | ||
|
|
4b00b0cc87 | ||
|
|
74507099ad | ||
|
|
0bb08b3f8d | ||
|
|
21098eb861 | ||
|
|
94933722c4 | ||
|
|
3f9b005885 | ||
|
|
559ecb2afc | ||
|
|
862fe1a290 | ||
|
|
5ffea816a1 | ||
|
|
7bda212958 | ||
|
|
101f47b6d4 | ||
|
|
b6c0e5d472 | ||
|
|
40e509588e | ||
|
|
fa01c4f02e | ||
|
|
cb328e4b6f | ||
|
|
8eb2fe1b58 | ||
|
|
c888879599 | ||
|
|
e2751d42e8 | ||
|
|
e5c2dbdf23 | ||
|
|
15c89d281e | ||
|
|
9659decef0 | ||
|
|
fddd72a3bd | ||
|
|
8489febcc7 | ||
|
|
ec1f5dc317 | ||
|
|
47e36b6791 | ||
|
|
399a079dd4 | ||
|
|
5900ab8c68 | ||
|
|
0abe5b6ec3 | ||
|
|
3d867c2c46 | ||
|
|
7a832045d6 | ||
|
|
7603b8d0fe | ||
|
|
04ab1daa02 | ||
|
|
41da58206f | ||
|
|
909409bb6d | ||
|
|
f454b753f2 | ||
|
|
9de66e9e87 | ||
|
|
4e7f475491 | ||
|
|
ad36f9ec89 | ||
|
|
7f4a073b05 | ||
|
|
f520ddc966 | ||
|
|
bd169e4fd4 | ||
|
|
ba1794f64b | ||
|
|
0e455b0f62 | ||
|
|
cbff18edb5 | ||
|
|
07a8e49c4b | ||
|
|
8ff89fdc0c | ||
|
|
79229fe3ae | ||
|
|
90ab6a40fc | ||
|
|
b3de385d5b | ||
|
|
0eafc3fd11 | ||
|
|
a968913e9f | ||
|
|
a2c1ec0de3 | ||
|
|
4eaeee7be2 | ||
|
|
443218e3f1 |
192
.ci/azure-pipelines.yml
Normal file
192
.ci/azure-pipelines.yml
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
name: $(Date:yyyyMMdd)$(Rev:.r)
|
||||||
|
|
||||||
|
variables:
|
||||||
|
- name: TestProjects
|
||||||
|
value: 'Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj'
|
||||||
|
- name: RestoreBuildProjects
|
||||||
|
value: 'Jellyfin.Server/Jellyfin.Server.csproj'
|
||||||
|
|
||||||
|
pr:
|
||||||
|
autoCancel: true
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
batch: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
- job: main_build
|
||||||
|
displayName: Main Build
|
||||||
|
pool:
|
||||||
|
vmImage: ubuntu-16.04
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
release:
|
||||||
|
BuildConfiguration: Release
|
||||||
|
debug:
|
||||||
|
BuildConfiguration: Debug
|
||||||
|
maxParallel: 2
|
||||||
|
steps:
|
||||||
|
- checkout: self
|
||||||
|
clean: true
|
||||||
|
submodules: true
|
||||||
|
persistCredentials: false
|
||||||
|
|
||||||
|
- task: DotNetCoreCLI@2
|
||||||
|
displayName: Restore
|
||||||
|
inputs:
|
||||||
|
command: restore
|
||||||
|
projects: '$(RestoreBuildProjects)'
|
||||||
|
|
||||||
|
- task: DotNetCoreCLI@2
|
||||||
|
displayName: Build
|
||||||
|
inputs:
|
||||||
|
projects: '$(RestoreBuildProjects)'
|
||||||
|
arguments: '--configuration $(BuildConfiguration)'
|
||||||
|
|
||||||
|
- task: DotNetCoreCLI@2
|
||||||
|
displayName: Test
|
||||||
|
inputs:
|
||||||
|
command: test
|
||||||
|
projects: '$(RestoreBuildProjects)'
|
||||||
|
arguments: '--configuration $(BuildConfiguration)'
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
- task: DotNetCoreCLI@2
|
||||||
|
displayName: Publish
|
||||||
|
inputs:
|
||||||
|
command: publish
|
||||||
|
publishWebProjects: false
|
||||||
|
projects: '$(RestoreBuildProjects)'
|
||||||
|
arguments: '--configuration $(BuildConfiguration) --output $(build.artifactstagingdirectory)'
|
||||||
|
zipAfterPublish: false
|
||||||
|
|
||||||
|
# - task: PublishBuildArtifacts@1
|
||||||
|
# displayName: 'Publish Artifact'
|
||||||
|
# inputs:
|
||||||
|
# PathtoPublish: '$(build.artifactstagingdirectory)'
|
||||||
|
# artifactName: 'jellyfin-build-$(BuildConfiguration)'
|
||||||
|
# zipAfterPublish: true
|
||||||
|
|
||||||
|
- task: PublishBuildArtifacts@1
|
||||||
|
displayName: 'Publish Artifact Naming'
|
||||||
|
condition: and(eq(variables['BuildConfiguration'], 'Release'), succeeded())
|
||||||
|
inputs:
|
||||||
|
PathtoPublish: '$(build.artifactstagingdirectory)/Jellyfin.Server/Emby.Naming.dll'
|
||||||
|
artifactName: 'Jellyfin.Naming'
|
||||||
|
|
||||||
|
- task: PublishBuildArtifacts@1
|
||||||
|
displayName: 'Publish Artifact Controller'
|
||||||
|
condition: and(eq(variables['BuildConfiguration'], 'Release'), succeeded())
|
||||||
|
inputs:
|
||||||
|
PathtoPublish: '$(build.artifactstagingdirectory)/Jellyfin.Server/MediaBrowser.Controller.dll'
|
||||||
|
artifactName: 'Jellyfin.Controller'
|
||||||
|
|
||||||
|
- task: PublishBuildArtifacts@1
|
||||||
|
displayName: 'Publish Artifact Model'
|
||||||
|
condition: and(eq(variables['BuildConfiguration'], 'Release'), succeeded())
|
||||||
|
inputs:
|
||||||
|
PathtoPublish: '$(build.artifactstagingdirectory)/Jellyfin.Server/MediaBrowser.Model.dll'
|
||||||
|
artifactName: 'Jellyfin.Model'
|
||||||
|
|
||||||
|
- task: PublishBuildArtifacts@1
|
||||||
|
displayName: 'Publish Artifact Common'
|
||||||
|
condition: and(eq(variables['BuildConfiguration'], 'Release'), succeeded())
|
||||||
|
inputs:
|
||||||
|
PathtoPublish: '$(build.artifactstagingdirectory)/Jellyfin.Server/MediaBrowser.Common.dll'
|
||||||
|
artifactName: 'Jellyfin.Common'
|
||||||
|
|
||||||
|
- job: dotnet_compat
|
||||||
|
displayName: Compatibility Check
|
||||||
|
pool:
|
||||||
|
vmImage: ubuntu-16.04
|
||||||
|
dependsOn: main_build
|
||||||
|
condition: and(succeeded(), variables['System.PullRequest.PullRequestNumber']) # Only execute if the pullrequest numer is defined. (So not for normal CI builds)
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
Naming:
|
||||||
|
NugetPackageName: Jellyfin.Naming
|
||||||
|
AssemblyFileName: Emby.Naming.dll
|
||||||
|
Controller:
|
||||||
|
NugetPackageName: Jellyfin.Controller
|
||||||
|
AssemblyFileName: MediaBrowser.Controller.dll
|
||||||
|
Model:
|
||||||
|
NugetPackageName: Jellyfin.Model
|
||||||
|
AssemblyFileName: MediaBrowser.Model.dll
|
||||||
|
Common:
|
||||||
|
NugetPackageName: Jellyfin.Common
|
||||||
|
AssemblyFileName: MediaBrowser.Common.dll
|
||||||
|
maxParallel: 2
|
||||||
|
steps:
|
||||||
|
- checkout: none
|
||||||
|
|
||||||
|
- task: DownloadBuildArtifacts@0
|
||||||
|
displayName: Download the Reference Assembly Build Artifact
|
||||||
|
inputs:
|
||||||
|
buildType: 'specific' # Options: current, specific
|
||||||
|
project: $(System.TeamProjectId) # Required when buildType == Specific
|
||||||
|
pipeline: $(System.DefinitionId) # Required when buildType == Specific, not sure if this will take a name too
|
||||||
|
#specificBuildWithTriggering: false # Optional
|
||||||
|
buildVersionToDownload: 'latestFromBranch' # Required when buildType == Specific# Options: latest, latestFromBranch, specific
|
||||||
|
allowPartiallySucceededBuilds: false # Optional
|
||||||
|
branchName: '$(System.PullRequest.TargetBranch)' # Required when buildType == Specific && BuildVersionToDownload == LatestFromBranch
|
||||||
|
#buildId: # Required when buildType == Specific && BuildVersionToDownload == Specific
|
||||||
|
#tags: # Optional
|
||||||
|
downloadType: 'single' # Options: single, specific
|
||||||
|
artifactName: '$(NugetPackageName)'# Required when downloadType == Single
|
||||||
|
#itemPattern: '**' # Optional
|
||||||
|
downloadPath: '$(System.ArtifactsDirectory)/current-artifacts'
|
||||||
|
#parallelizationLimit: '8' # Optional
|
||||||
|
|
||||||
|
- task: CopyFiles@2
|
||||||
|
displayName: Copy Nuget Assembly to current-release folder
|
||||||
|
inputs:
|
||||||
|
sourceFolder: $(System.ArtifactsDirectory)/current-artifacts # Optional
|
||||||
|
contents: '**/*.dll'
|
||||||
|
targetFolder: $(System.ArtifactsDirectory)/current-release
|
||||||
|
cleanTargetFolder: true # Optional
|
||||||
|
overWrite: true # Optional
|
||||||
|
flattenFolders: true # Optional
|
||||||
|
|
||||||
|
- task: DownloadBuildArtifacts@0
|
||||||
|
displayName: Download the New Assembly Build Artifact
|
||||||
|
inputs:
|
||||||
|
buildType: 'current' # Options: current, specific
|
||||||
|
allowPartiallySucceededBuilds: false # Optional
|
||||||
|
downloadType: 'single' # Options: single, specific
|
||||||
|
artifactName: '$(NugetPackageName)' # Required when downloadType == Single
|
||||||
|
downloadPath: '$(System.ArtifactsDirectory)/new-artifacts'
|
||||||
|
|
||||||
|
- task: CopyFiles@2
|
||||||
|
displayName: Copy Artifact Assembly to new-release folder
|
||||||
|
inputs:
|
||||||
|
sourceFolder: $(System.ArtifactsDirectory)/new-artifacts # Optional
|
||||||
|
contents: '**/*.dll'
|
||||||
|
targetFolder: $(System.ArtifactsDirectory)/new-release
|
||||||
|
cleanTargetFolder: true # Optional
|
||||||
|
overWrite: true # Optional
|
||||||
|
flattenFolders: true # Optional
|
||||||
|
|
||||||
|
- task: DownloadGitHubRelease@0
|
||||||
|
displayName: Download ABI compatibility check tool from GitHub
|
||||||
|
inputs:
|
||||||
|
connection: Jellyfin GitHub
|
||||||
|
userRepository: EraYaN/dotnet-compatibility
|
||||||
|
defaultVersionType: 'latest' # Options: latest, specificVersion, specificTag
|
||||||
|
#version: # Required when defaultVersionType != Latest
|
||||||
|
itemPattern: '**-ci.zip' # Optional
|
||||||
|
downloadPath: '$(System.ArtifactsDirectory)'
|
||||||
|
|
||||||
|
- task: ExtractFiles@1
|
||||||
|
displayName: Extract ABI compatibility check tool
|
||||||
|
inputs:
|
||||||
|
archiveFilePatterns: '$(System.ArtifactsDirectory)/*-ci.zip'
|
||||||
|
destinationFolder: $(System.ArtifactsDirectory)/tools
|
||||||
|
cleanDestinationFolder: true
|
||||||
|
|
||||||
|
- task: CmdLine@2
|
||||||
|
displayName: Execute ABI compatibility check tool
|
||||||
|
inputs:
|
||||||
|
script: 'dotnet tools/CompatibilityCheckerCoreCLI.dll current-release/$(AssemblyFileName) new-release/$(AssemblyFileName)'
|
||||||
|
workingDirectory: $(System.ArtifactsDirectory) # Optional
|
||||||
|
#failOnStderr: false # Optional
|
||||||
|
|
||||||
|
|
||||||
8
.copr/Makefile
Normal file
8
.copr/Makefile
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
srpm:
|
||||||
|
dnf -y install git
|
||||||
|
git submodule update --init --recursive
|
||||||
|
cd deployment/fedora-package-x64; \
|
||||||
|
./create_tarball.sh; \
|
||||||
|
rpmbuild -bs pkg-src/jellyfin.spec \
|
||||||
|
--define "_sourcedir $$PWD/pkg-src/" \
|
||||||
|
--define "_srcrpmdir $(outdir)"
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
.git
|
.git
|
||||||
.dockerignore
|
.dockerignore
|
||||||
Dockerfile
|
Dockerfile
|
||||||
|
Dockerfile.arm
|
||||||
|
Dockerfile.arm64
|
||||||
CONTRIBUTORS.md
|
CONTRIBUTORS.md
|
||||||
README.md
|
README.md
|
||||||
|
deployment/*/dist
|
||||||
|
deployment/*/pkg-dist
|
||||||
|
deployment/collect-dist/
|
||||||
|
ci/
|
||||||
|
|||||||
22
.drone.yml
22
.drone.yml
@@ -1,12 +1,30 @@
|
|||||||
|
---
|
||||||
kind: pipeline
|
kind: pipeline
|
||||||
name: build
|
name: build-debug
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: submodules
|
- name: submodules
|
||||||
image: docker:git
|
image: docker:git
|
||||||
commands:
|
commands:
|
||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
|
|
||||||
- name: build
|
- name: build
|
||||||
image: microsoft/dotnet:2-sdk
|
image: microsoft/dotnet:2-sdk
|
||||||
commands:
|
commands:
|
||||||
- dotnet publish --configuration release --output /release
|
- dotnet publish "Jellyfin.Server" --configuration Debug --output "../ci/ci-debug"
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: build-release
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: submodules
|
||||||
|
image: docker:git
|
||||||
|
commands:
|
||||||
|
- git submodule update --init --recursive
|
||||||
|
|
||||||
|
- name: build
|
||||||
|
image: microsoft/dotnet:2-sdk
|
||||||
|
commands:
|
||||||
|
- dotnet publish "Jellyfin.Server" --configuration Release --output "../ci/ci-release"
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
###############################
|
###############################
|
||||||
# Core EditorConfig Options #
|
# Core EditorConfig Options #
|
||||||
###############################
|
###############################
|
||||||
|
root = true
|
||||||
# All files
|
# All files
|
||||||
[*]
|
[*]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
root = true
|
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
@@ -15,11 +15,13 @@ insert_final_newline = true
|
|||||||
end_of_line = lf
|
end_of_line = lf
|
||||||
max_line_length = null
|
max_line_length = null
|
||||||
|
|
||||||
# Code files
|
# YAML indentation
|
||||||
[*.{cs,csx,vb,vbx}]
|
[*.{yml,yaml}]
|
||||||
indent_size = 4
|
indent_size = 2
|
||||||
insert_final_newline = true
|
|
||||||
charset = utf-8
|
# XML indentation
|
||||||
|
[*.{csproj,xml}]
|
||||||
|
indent_size = 2
|
||||||
###############################
|
###############################
|
||||||
# .NET Coding Conventions #
|
# .NET Coding Conventions #
|
||||||
###############################
|
###############################
|
||||||
@@ -57,15 +59,77 @@ dotnet_style_prefer_conditional_expression_over_return = true:silent
|
|||||||
###############################
|
###############################
|
||||||
# Naming Conventions #
|
# Naming Conventions #
|
||||||
###############################
|
###############################
|
||||||
# Style Definitions
|
# Style Definitions (From Roslyn)
|
||||||
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
|
|
||||||
# Use PascalCase for constant fields
|
# Non-private static fields are PascalCase
|
||||||
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
|
dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.severity = suggestion
|
||||||
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
|
dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.symbols = non_private_static_fields
|
||||||
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
|
dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style
|
||||||
dotnet_naming_symbols.constant_fields.applicable_kinds = field
|
|
||||||
dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
|
dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field
|
||||||
dotnet_naming_symbols.constant_fields.required_modifiers = const
|
dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected internal, private protected
|
||||||
|
dotnet_naming_symbols.non_private_static_fields.required_modifiers = static
|
||||||
|
|
||||||
|
dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case
|
||||||
|
|
||||||
|
# Constants are PascalCase
|
||||||
|
dotnet_naming_rule.constants_should_be_pascal_case.severity = suggestion
|
||||||
|
dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants
|
||||||
|
dotnet_naming_rule.constants_should_be_pascal_case.style = constant_style
|
||||||
|
|
||||||
|
dotnet_naming_symbols.constants.applicable_kinds = field, local
|
||||||
|
dotnet_naming_symbols.constants.required_modifiers = const
|
||||||
|
|
||||||
|
dotnet_naming_style.constant_style.capitalization = pascal_case
|
||||||
|
|
||||||
|
# Static fields are camelCase and start with s_
|
||||||
|
dotnet_naming_rule.static_fields_should_be_camel_case.severity = suggestion
|
||||||
|
dotnet_naming_rule.static_fields_should_be_camel_case.symbols = static_fields
|
||||||
|
dotnet_naming_rule.static_fields_should_be_camel_case.style = static_field_style
|
||||||
|
|
||||||
|
dotnet_naming_symbols.static_fields.applicable_kinds = field
|
||||||
|
dotnet_naming_symbols.static_fields.required_modifiers = static
|
||||||
|
|
||||||
|
dotnet_naming_style.static_field_style.capitalization = camel_case
|
||||||
|
dotnet_naming_style.static_field_style.required_prefix = _
|
||||||
|
|
||||||
|
# Instance fields are camelCase and start with _
|
||||||
|
dotnet_naming_rule.instance_fields_should_be_camel_case.severity = suggestion
|
||||||
|
dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields
|
||||||
|
dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style
|
||||||
|
|
||||||
|
dotnet_naming_symbols.instance_fields.applicable_kinds = field
|
||||||
|
|
||||||
|
dotnet_naming_style.instance_field_style.capitalization = camel_case
|
||||||
|
dotnet_naming_style.instance_field_style.required_prefix = _
|
||||||
|
|
||||||
|
# Locals and parameters are camelCase
|
||||||
|
dotnet_naming_rule.locals_should_be_camel_case.severity = suggestion
|
||||||
|
dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters
|
||||||
|
dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style
|
||||||
|
|
||||||
|
dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local
|
||||||
|
|
||||||
|
dotnet_naming_style.camel_case_style.capitalization = camel_case
|
||||||
|
|
||||||
|
# Local functions are PascalCase
|
||||||
|
dotnet_naming_rule.local_functions_should_be_pascal_case.severity = suggestion
|
||||||
|
dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions
|
||||||
|
dotnet_naming_rule.local_functions_should_be_pascal_case.style = local_function_style
|
||||||
|
|
||||||
|
dotnet_naming_symbols.local_functions.applicable_kinds = local_function
|
||||||
|
|
||||||
|
dotnet_naming_style.local_function_style.capitalization = pascal_case
|
||||||
|
|
||||||
|
# By default, name items with PascalCase
|
||||||
|
dotnet_naming_rule.members_should_be_pascal_case.severity = suggestion
|
||||||
|
dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members
|
||||||
|
dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case_style
|
||||||
|
|
||||||
|
dotnet_naming_symbols.all_members.applicable_kinds = *
|
||||||
|
|
||||||
|
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
|
||||||
|
|
||||||
###############################
|
###############################
|
||||||
# C# Coding Conventions #
|
# C# Coding Conventions #
|
||||||
###############################
|
###############################
|
||||||
|
|||||||
13
.github/ISSUE_TEMPLATE/bug_report.md
vendored
13
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -8,28 +8,29 @@ assignees: ''
|
|||||||
---
|
---
|
||||||
|
|
||||||
**Describe the bug**
|
**Describe the bug**
|
||||||
A clear and concise description of what the bug is.
|
<!-- A clear and concise description of what the bug is. -->
|
||||||
|
|
||||||
**To Reproduce**
|
**To Reproduce**
|
||||||
Steps to reproduce the behavior:
|
<!-- Steps to reproduce the behavior: -->
|
||||||
1. Go to '...'
|
1. Go to '...'
|
||||||
2. Click on '....'
|
2. Click on '....'
|
||||||
3. Scroll down to '....'
|
3. Scroll down to '....'
|
||||||
4. See error
|
4. See error
|
||||||
|
|
||||||
**Expected behavior**
|
**Expected behavior**
|
||||||
A clear and concise description of what you expected to happen.
|
<!-- A clear and concise description of what you expected to happen. -->
|
||||||
|
|
||||||
**Logs**
|
**Logs**
|
||||||
Please paste any log errors.
|
<!-- Please paste any log errors. -->
|
||||||
|
|
||||||
**Screenshots**
|
**Screenshots**
|
||||||
If applicable, add screenshots to help explain your problem.
|
<!-- If applicable, add screenshots to help explain your problem. -->
|
||||||
|
|
||||||
**System (please complete the following information):**
|
**System (please complete the following information):**
|
||||||
- OS: [e.g. Docker, Debian, Windows]
|
- OS: [e.g. Docker, Debian, Windows]
|
||||||
- Browser: [e.g. Firefox, Chrome, Safari]
|
- Browser: [e.g. Firefox, Chrome, Safari]
|
||||||
- Jellyfin Version: [e.g. 10.0.1]
|
- Jellyfin Version: [e.g. 10.0.1]
|
||||||
|
- Reverse proxy: [e.g. no, nginx, apache, etc.]
|
||||||
|
|
||||||
**Additional context**
|
**Additional context**
|
||||||
Add any other context about the problem here.
|
<!-- Add any other context about the problem here. -->
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ assignees: ''
|
|||||||
---
|
---
|
||||||
|
|
||||||
**Is your feature request related to a problem? Please describe.**
|
**Is your feature request related to a problem? Please describe.**
|
||||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
|
||||||
|
|
||||||
**Describe the solution you'd like**
|
**Describe the solution you'd like**
|
||||||
A clear and concise description of what you want to happen.
|
<!-- A clear and concise description of what you want to happen. -->
|
||||||
|
|
||||||
**Describe alternatives you've considered**
|
**Describe alternatives you've considered**
|
||||||
A clear and concise description of any alternative solutions or features you've considered.
|
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
|
||||||
|
|
||||||
**Additional context**
|
**Additional context**
|
||||||
Add any other context or screenshots about the feature request here.
|
<!-- Add any other context or screenshots about the feature request here. -->
|
||||||
|
|||||||
4
.github/ISSUE_TEMPLATE/feature_request.md
vendored
4
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -8,7 +8,7 @@ assignees: ''
|
|||||||
---
|
---
|
||||||
|
|
||||||
**Describe the feature you'd like**
|
**Describe the feature you'd like**
|
||||||
A clear and concise description of what you want to happen.
|
<!-- A clear and concise description of what you want to happen. -->
|
||||||
|
|
||||||
**Additional context**
|
**Additional context**
|
||||||
Add any other context or screenshots about the feature request here.
|
<!-- Add any other context or screenshots about the feature request here. -->
|
||||||
|
|||||||
8
.github/pull_request_template.md
vendored
8
.github/pull_request_template.md
vendored
@@ -1,9 +1,11 @@
|
|||||||
|
<!--
|
||||||
Ensure your title is short, descriptive, and in the imperative mood (Fix X, Change Y, instead of Fixed X, Changed Y).
|
Ensure your title is short, descriptive, and in the imperative mood (Fix X, Change Y, instead of Fixed X, Changed Y).
|
||||||
For a good inspiration of what to write in commit messages and PRs please review https://chris.beams.io/posts/git-commit/ and our https://jellyfin.readthedocs.io/en/latest/developer-docs/contributing/ page.
|
For a good inspiration of what to write in commit messages and PRs please review https://chris.beams.io/posts/git-commit/ and our https://jellyfin.readthedocs.io/en/latest/developer-docs/contributing/ page.
|
||||||
|
-->
|
||||||
|
|
||||||
**Changes**
|
**Changes**
|
||||||
Describe your changes here in 1-5 sentences.
|
<!-- Describe your changes here in 1-5 sentences. -->
|
||||||
|
|
||||||
**Issues**
|
**Issues**
|
||||||
Tag any issues that this PR solves here.
|
<!-- Tag any issues that this PR solves here.
|
||||||
Fixes #
|
ex. Fixes # -->
|
||||||
|
|||||||
42
.gitignore
vendored
42
.gitignore
vendored
@@ -1,5 +1,3 @@
|
|||||||
!*
|
|
||||||
|
|
||||||
.directory
|
.directory
|
||||||
|
|
||||||
#################
|
#################
|
||||||
@@ -49,6 +47,8 @@ ProgramData-UI*/
|
|||||||
## Ignore Visual Studio temporary files, build results, and
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
## files generated by popular Visual Studio add-ons.
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
|
||||||
|
.vs/
|
||||||
|
|
||||||
# User-specific files
|
# User-specific files
|
||||||
*.suo
|
*.suo
|
||||||
*.user
|
*.user
|
||||||
@@ -204,7 +204,6 @@ $RECYCLE.BIN/
|
|||||||
# Mac crap
|
# Mac crap
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
|
||||||
#############
|
#############
|
||||||
## Python
|
## Python
|
||||||
#############
|
#############
|
||||||
@@ -234,24 +233,39 @@ pip-log.txt
|
|||||||
|
|
||||||
#Mr Developer
|
#Mr Developer
|
||||||
.mr.developer.cfg
|
.mr.developer.cfg
|
||||||
MediaBrowser.WebDashboard/dashboard-ui/.idea/
|
|
||||||
/.vs
|
|
||||||
|
|
||||||
##########
|
##########
|
||||||
# Rider
|
# Rider
|
||||||
##########
|
##########
|
||||||
.idea/
|
.idea/
|
||||||
|
|
||||||
|
##########
|
||||||
|
# Visual Studio Code
|
||||||
|
##########
|
||||||
|
.vscode/
|
||||||
|
|
||||||
#########################
|
#########################
|
||||||
# Debian build artifacts
|
# Build artifacts
|
||||||
#########################
|
#########################
|
||||||
|
|
||||||
debian/.debhelper/
|
# Artifacts for debian-x64
|
||||||
debian/*.debhelper
|
deployment/debian-package-x64/pkg-src/.debhelper/
|
||||||
debian/debhelper-build-stamp
|
deployment/debian-package-x64/pkg-src/*.debhelper
|
||||||
debian/files
|
deployment/debian-package-x64/pkg-src/debhelper-build-stamp
|
||||||
debian/jellyfin.substvars
|
deployment/debian-package-x64/pkg-src/files
|
||||||
debian/jellyfin/
|
deployment/debian-package-x64/pkg-src/jellyfin.substvars
|
||||||
|
deployment/debian-package-x64/pkg-src/jellyfin/
|
||||||
# Don't ignore the debian/bin folder
|
# Don't ignore the debian/bin folder
|
||||||
!debian/bin/
|
!deployment/debian-package-x64/pkg-src/bin/
|
||||||
|
|
||||||
|
deployment/**/dist/
|
||||||
|
deployment/**/pkg-dist/
|
||||||
|
deployment/**/pkg-dist-tmp/
|
||||||
|
deployment/collect-dist/
|
||||||
|
|
||||||
|
jellyfin_version.ini
|
||||||
|
|
||||||
|
ci/
|
||||||
|
|
||||||
|
# Doxygen
|
||||||
|
doc/
|
||||||
7
.gitmodules
vendored
7
.gitmodules
vendored
@@ -1,3 +1,4 @@
|
|||||||
[submodule "ThirdParty/taglib-sharp"]
|
[submodule "MediaBrowser.WebDashboard/jellyfin-web"]
|
||||||
path = ThirdParty/taglib-sharp
|
path = MediaBrowser.WebDashboard/jellyfin-web
|
||||||
url = https://github.com/mono/taglib-sharp.git
|
url = https://github.com/jellyfin/jellyfin-web.git
|
||||||
|
branch = .
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="..\SharedVersion.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
||||||
|
|||||||
@@ -1,105 +1,33 @@
|
|||||||
|
|
||||||
namespace BDInfo
|
namespace BDInfo
|
||||||
{
|
{
|
||||||
class BDInfoSettings
|
class BDInfoSettings
|
||||||
{
|
{
|
||||||
public static bool GenerateStreamDiagnostics
|
public static bool GenerateStreamDiagnostics => true;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool EnableSSIF
|
public static bool EnableSSIF => true;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool AutosaveReport
|
public static bool AutosaveReport => false;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool GenerateFrameDataFile
|
public static bool GenerateFrameDataFile => false;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool FilterLoopingPlaylists
|
public static bool FilterLoopingPlaylists => true;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool FilterShortPlaylists
|
public static bool FilterShortPlaylists => false;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int FilterShortPlaylistsValue
|
public static int FilterShortPlaylistsValue => 0;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool UseImagePrefix
|
public static bool UseImagePrefix => false;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string UseImagePrefixValue
|
public static string UseImagePrefixValue => null;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Setting this to false throws an IComparer error on some discs.
|
/// Setting this to false throws an IComparer error on some discs.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool KeepStreamOrder
|
public static bool KeepStreamOrder => true;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool GenerateTextSummary
|
public static bool GenerateTextSummary => false;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string LastPath
|
public static string LastPath => string.Empty;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||||
// Copyright © 2010 Cinema Squid
|
// Copyright © 2010 Cinema Squid
|
||||||
//
|
//
|
||||||
@@ -22,7 +22,6 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.Text;
|
|
||||||
|
|
||||||
namespace BDInfo
|
namespace BDInfo
|
||||||
{
|
{
|
||||||
@@ -72,12 +71,11 @@ namespace BDInfo
|
|||||||
|
|
||||||
public event OnPlaylistFileScanError PlaylistFileScanError;
|
public event OnPlaylistFileScanError PlaylistFileScanError;
|
||||||
|
|
||||||
public BDROM(
|
public BDROM(string path, IFileSystem fileSystem)
|
||||||
string path, IFileSystem fileSystem, ITextEncoding textEncoding)
|
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(path))
|
if (string.IsNullOrEmpty(path))
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException("path");
|
throw new ArgumentNullException(nameof(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
@@ -94,7 +92,7 @@ namespace BDInfo
|
|||||||
}
|
}
|
||||||
|
|
||||||
DirectoryRoot =
|
DirectoryRoot =
|
||||||
_fileSystem.GetDirectoryInfo(_fileSystem.GetDirectoryName(DirectoryBDMV.FullName));
|
_fileSystem.GetDirectoryInfo(Path.GetDirectoryName(DirectoryBDMV.FullName));
|
||||||
DirectoryBDJO =
|
DirectoryBDJO =
|
||||||
GetDirectory("BDJO", DirectoryBDMV, 0);
|
GetDirectory("BDJO", DirectoryBDMV, 0);
|
||||||
DirectoryCLIPINF =
|
DirectoryCLIPINF =
|
||||||
@@ -152,7 +150,7 @@ namespace BDInfo
|
|||||||
Is3D = true;
|
Is3D = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_fileSystem.FileExists(Path.Combine(DirectoryRoot.FullName, "FilmIndex.xml")))
|
if (File.Exists(Path.Combine(DirectoryRoot.FullName, "FilmIndex.xml")))
|
||||||
{
|
{
|
||||||
IsDBOX = true;
|
IsDBOX = true;
|
||||||
}
|
}
|
||||||
@@ -164,17 +162,17 @@ namespace BDInfo
|
|||||||
if (DirectoryPLAYLIST != null)
|
if (DirectoryPLAYLIST != null)
|
||||||
{
|
{
|
||||||
FileSystemMetadata[] files = GetFiles(DirectoryPLAYLIST.FullName, ".mpls").ToArray();
|
FileSystemMetadata[] files = GetFiles(DirectoryPLAYLIST.FullName, ".mpls").ToArray();
|
||||||
foreach (FileSystemMetadata file in files)
|
foreach (var file in files)
|
||||||
{
|
{
|
||||||
PlaylistFiles.Add(
|
PlaylistFiles.Add(
|
||||||
file.Name.ToUpper(), new TSPlaylistFile(this, file, _fileSystem, textEncoding));
|
file.Name.ToUpper(), new TSPlaylistFile(this, file));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DirectorySTREAM != null)
|
if (DirectorySTREAM != null)
|
||||||
{
|
{
|
||||||
FileSystemMetadata[] files = GetFiles(DirectorySTREAM.FullName, ".m2ts").ToArray();
|
FileSystemMetadata[] files = GetFiles(DirectorySTREAM.FullName, ".m2ts").ToArray();
|
||||||
foreach (FileSystemMetadata file in files)
|
foreach (var file in files)
|
||||||
{
|
{
|
||||||
StreamFiles.Add(
|
StreamFiles.Add(
|
||||||
file.Name.ToUpper(), new TSStreamFile(file, _fileSystem));
|
file.Name.ToUpper(), new TSStreamFile(file, _fileSystem));
|
||||||
@@ -184,17 +182,17 @@ namespace BDInfo
|
|||||||
if (DirectoryCLIPINF != null)
|
if (DirectoryCLIPINF != null)
|
||||||
{
|
{
|
||||||
FileSystemMetadata[] files = GetFiles(DirectoryCLIPINF.FullName, ".clpi").ToArray();
|
FileSystemMetadata[] files = GetFiles(DirectoryCLIPINF.FullName, ".clpi").ToArray();
|
||||||
foreach (FileSystemMetadata file in files)
|
foreach (var file in files)
|
||||||
{
|
{
|
||||||
StreamClipFiles.Add(
|
StreamClipFiles.Add(
|
||||||
file.Name.ToUpper(), new TSStreamClipFile(file, _fileSystem, textEncoding));
|
file.Name.ToUpper(), new TSStreamClipFile(file));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DirectorySSIF != null)
|
if (DirectorySSIF != null)
|
||||||
{
|
{
|
||||||
FileSystemMetadata[] files = GetFiles(DirectorySSIF.FullName, ".ssif").ToArray();
|
FileSystemMetadata[] files = GetFiles(DirectorySSIF.FullName, ".ssif").ToArray();
|
||||||
foreach (FileSystemMetadata file in files)
|
foreach (var file in files)
|
||||||
{
|
{
|
||||||
InterleavedFiles.Add(
|
InterleavedFiles.Add(
|
||||||
file.Name.ToUpper(), new TSInterleavedFile(file));
|
file.Name.ToUpper(), new TSInterleavedFile(file));
|
||||||
@@ -214,8 +212,8 @@ namespace BDInfo
|
|||||||
|
|
||||||
public void Scan()
|
public void Scan()
|
||||||
{
|
{
|
||||||
List<TSStreamClipFile> errorStreamClipFiles = new List<TSStreamClipFile>();
|
var errorStreamClipFiles = new List<TSStreamClipFile>();
|
||||||
foreach (TSStreamClipFile streamClipFile in StreamClipFiles.Values)
|
foreach (var streamClipFile in StreamClipFiles.Values)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -235,11 +233,11 @@ namespace BDInfo
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else throw ex;
|
else throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (TSStreamFile streamFile in StreamFiles.Values)
|
foreach (var streamFile in StreamFiles.Values)
|
||||||
{
|
{
|
||||||
string ssifName = Path.GetFileNameWithoutExtension(streamFile.Name) + ".SSIF";
|
string ssifName = Path.GetFileNameWithoutExtension(streamFile.Name) + ".SSIF";
|
||||||
if (InterleavedFiles.ContainsKey(ssifName))
|
if (InterleavedFiles.ContainsKey(ssifName))
|
||||||
@@ -252,8 +250,8 @@ namespace BDInfo
|
|||||||
StreamFiles.Values.CopyTo(streamFiles, 0);
|
StreamFiles.Values.CopyTo(streamFiles, 0);
|
||||||
Array.Sort(streamFiles, CompareStreamFiles);
|
Array.Sort(streamFiles, CompareStreamFiles);
|
||||||
|
|
||||||
List<TSPlaylistFile> errorPlaylistFiles = new List<TSPlaylistFile>();
|
var errorPlaylistFiles = new List<TSPlaylistFile>();
|
||||||
foreach (TSPlaylistFile playlistFile in PlaylistFiles.Values)
|
foreach (var playlistFile in PlaylistFiles.Values)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -273,19 +271,19 @@ namespace BDInfo
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else throw ex;
|
else throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<TSStreamFile> errorStreamFiles = new List<TSStreamFile>();
|
var errorStreamFiles = new List<TSStreamFile>();
|
||||||
foreach (TSStreamFile streamFile in streamFiles)
|
foreach (var streamFile in streamFiles)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
List<TSPlaylistFile> playlists = new List<TSPlaylistFile>();
|
var playlists = new List<TSPlaylistFile>();
|
||||||
foreach (TSPlaylistFile playlist in PlaylistFiles.Values)
|
foreach (var playlist in PlaylistFiles.Values)
|
||||||
{
|
{
|
||||||
foreach (TSStreamClip streamClip in playlist.StreamClips)
|
foreach (var streamClip in playlist.StreamClips)
|
||||||
{
|
{
|
||||||
if (streamClip.Name == streamFile.Name)
|
if (streamClip.Name == streamFile.Name)
|
||||||
{
|
{
|
||||||
@@ -310,16 +308,16 @@ namespace BDInfo
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else throw ex;
|
else throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (TSPlaylistFile playlistFile in PlaylistFiles.Values)
|
foreach (var playlistFile in PlaylistFiles.Values)
|
||||||
{
|
{
|
||||||
playlistFile.Initialize();
|
playlistFile.Initialize();
|
||||||
if (!Is50Hz)
|
if (!Is50Hz)
|
||||||
{
|
{
|
||||||
foreach (TSVideoStream videoStream in playlistFile.VideoStreams)
|
foreach (var videoStream in playlistFile.VideoStreams)
|
||||||
{
|
{
|
||||||
if (videoStream.FrameRate == TSFrameRate.FRAMERATE_25 ||
|
if (videoStream.FrameRate == TSFrameRate.FRAMERATE_25 ||
|
||||||
videoStream.FrameRate == TSFrameRate.FRAMERATE_50)
|
videoStream.FrameRate == TSFrameRate.FRAMERATE_50)
|
||||||
@@ -336,7 +334,7 @@ namespace BDInfo
|
|||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(path))
|
if (string.IsNullOrEmpty(path))
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException("path");
|
throw new ArgumentNullException(nameof(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
FileSystemMetadata dir = _fileSystem.GetDirectoryInfo(path);
|
FileSystemMetadata dir = _fileSystem.GetDirectoryInfo(path);
|
||||||
@@ -347,7 +345,7 @@ namespace BDInfo
|
|||||||
{
|
{
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
var parentFolder = _fileSystem.GetDirectoryName(dir.FullName);
|
var parentFolder = Path.GetDirectoryName(dir.FullName);
|
||||||
if (string.IsNullOrEmpty(parentFolder))
|
if (string.IsNullOrEmpty(parentFolder))
|
||||||
{
|
{
|
||||||
dir = null;
|
dir = null;
|
||||||
@@ -369,7 +367,7 @@ namespace BDInfo
|
|||||||
if (dir != null)
|
if (dir != null)
|
||||||
{
|
{
|
||||||
FileSystemMetadata[] children = _fileSystem.GetDirectories(dir.FullName).ToArray();
|
FileSystemMetadata[] children = _fileSystem.GetDirectories(dir.FullName).ToArray();
|
||||||
foreach (FileSystemMetadata child in children)
|
foreach (var child in children)
|
||||||
{
|
{
|
||||||
if (string.Equals(child.Name, name, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(child.Name, name, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
@@ -378,7 +376,7 @@ namespace BDInfo
|
|||||||
}
|
}
|
||||||
if (searchDepth > 0)
|
if (searchDepth > 0)
|
||||||
{
|
{
|
||||||
foreach (FileSystemMetadata child in children)
|
foreach (var child in children)
|
||||||
{
|
{
|
||||||
GetDirectory(
|
GetDirectory(
|
||||||
name, child, searchDepth - 1);
|
name, child, searchDepth - 1);
|
||||||
@@ -395,7 +393,7 @@ namespace BDInfo
|
|||||||
//if (!ExcludeDirs.Contains(directoryInfo.Name.ToUpper())) // TODO: Keep?
|
//if (!ExcludeDirs.Contains(directoryInfo.Name.ToUpper())) // TODO: Keep?
|
||||||
{
|
{
|
||||||
FileSystemMetadata[] pathFiles = _fileSystem.GetFiles(directoryInfo.FullName).ToArray();
|
FileSystemMetadata[] pathFiles = _fileSystem.GetFiles(directoryInfo.FullName).ToArray();
|
||||||
foreach (FileSystemMetadata pathFile in pathFiles)
|
foreach (var pathFile in pathFiles)
|
||||||
{
|
{
|
||||||
if (pathFile.Extension.ToUpper() == ".SSIF")
|
if (pathFile.Extension.ToUpper() == ".SSIF")
|
||||||
{
|
{
|
||||||
@@ -405,7 +403,7 @@ namespace BDInfo
|
|||||||
}
|
}
|
||||||
|
|
||||||
FileSystemMetadata[] pathChildren = _fileSystem.GetDirectories(directoryInfo.FullName).ToArray();
|
FileSystemMetadata[] pathChildren = _fileSystem.GetDirectories(directoryInfo.FullName).ToArray();
|
||||||
foreach (FileSystemMetadata pathChild in pathChildren)
|
foreach (var pathChild in pathChildren)
|
||||||
{
|
{
|
||||||
size += GetDirectorySize(pathChild);
|
size += GetDirectorySize(pathChild);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||||
// Copyright © 2010 Cinema Squid
|
// Copyright © 2010 Cinema Squid
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System.Resources;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Resources;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
// General Information about an assembly is controlled through the following
|
||||||
@@ -9,21 +8,14 @@ using System.Runtime.InteropServices;
|
|||||||
[assembly: AssemblyTitle("BDInfo")]
|
[assembly: AssemblyTitle("BDInfo")]
|
||||||
[assembly: AssemblyDescription("")]
|
[assembly: AssemblyDescription("")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCompany("")]
|
[assembly: AssemblyCompany("Jellyfin Project")]
|
||||||
[assembly: AssemblyProduct("BDInfo")]
|
[assembly: AssemblyProduct("Jellyfin Server")]
|
||||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
[assembly: AssemblyCopyright("Copyright © 2016 CinemaSquid. Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: NeutralResourcesLanguage("en")]
|
[assembly: NeutralResourcesLanguage("en")]
|
||||||
|
|
||||||
// Version information for an assembly consists of the following four values:
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
//
|
// to COM components. If you need to access a type in this assembly from
|
||||||
// Major Version
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
// Minor Version
|
[assembly: ComVisible(false)]
|
||||||
// Build Number
|
|
||||||
// Revision
|
|
||||||
//
|
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
|
||||||
// by using the '*' as shown below:
|
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
|
||||||
[assembly: AssemblyVersion("1.0.1")]
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
The source is taken from the BDRom folder of this project:
|
The source is taken from the BDRom folder of this project:
|
||||||
|
|
||||||
http://www.cinemasquid.com/blu-ray/tools/bdinfo
|
http://www.cinemasquid.com/blu-ray/tools/bdinfo
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||||
// Copyright © 2010 Cinema Squid
|
// Copyright © 2010 Cinema Squid
|
||||||
//
|
//
|
||||||
@@ -24,7 +24,7 @@ namespace BDInfo
|
|||||||
{
|
{
|
||||||
public abstract class TSCodecAC3
|
public abstract class TSCodecAC3
|
||||||
{
|
{
|
||||||
private static byte[] eac3_blocks = new byte[] { 1, 2, 3, 6 };
|
private static byte[] eac3_blocks = new byte[] { 1, 2, 3, 6 };
|
||||||
|
|
||||||
public static void Scan(
|
public static void Scan(
|
||||||
TSAudioStream stream,
|
TSAudioStream stream,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||||
// Copyright © 2010 Cinema Squid
|
// Copyright © 2010 Cinema Squid
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||||
// Copyright © 2010 Cinema Squid
|
// Copyright © 2010 Cinema Squid
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||||
// Copyright © 2010 Cinema Squid
|
// Copyright © 2010 Cinema Squid
|
||||||
//
|
//
|
||||||
@@ -211,7 +211,7 @@ namespace BDInfo
|
|||||||
// TODO
|
// TODO
|
||||||
if (stream.CoreStream != null)
|
if (stream.CoreStream != null)
|
||||||
{
|
{
|
||||||
TSAudioStream coreStream = (TSAudioStream)stream.CoreStream;
|
var coreStream = (TSAudioStream)stream.CoreStream;
|
||||||
if (coreStream.AudioMode == TSAudioMode.Extended &&
|
if (coreStream.AudioMode == TSAudioMode.Extended &&
|
||||||
stream.ChannelCount == 5)
|
stream.ChannelCount == 5)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||||
// Copyright © 2010 Cinema Squid
|
// Copyright © 2010 Cinema Squid
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||||
// Copyright © 2010 Cinema Squid
|
// Copyright © 2010 Cinema Squid
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||||
// Copyright © 2010 Cinema Squid
|
// Copyright © 2010 Cinema Squid
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||||
// Copyright © 2010 Cinema Squid
|
// Copyright © 2010 Cinema Squid
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||||
// Copyright © 2010 Cinema Squid
|
// Copyright © 2010 Cinema Squid
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||||
// Copyright © 2010 Cinema Squid
|
// Copyright © 2010 Cinema Squid
|
||||||
//
|
//
|
||||||
@@ -17,7 +17,6 @@
|
|||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
using System.IO;
|
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
|
||||||
// TODO: Do more interesting things here...
|
// TODO: Do more interesting things here...
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||||
// Copyright © 2010 Cinema Squid
|
// Copyright © 2010 Cinema Squid
|
||||||
//
|
//
|
||||||
@@ -23,14 +23,11 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.Text;
|
|
||||||
|
|
||||||
namespace BDInfo
|
namespace BDInfo
|
||||||
{
|
{
|
||||||
public class TSPlaylistFile
|
public class TSPlaylistFile
|
||||||
{
|
{
|
||||||
private readonly IFileSystem _fileSystem;
|
|
||||||
private readonly ITextEncoding _textEncoding;
|
|
||||||
private FileSystemMetadata FileInfo = null;
|
private FileSystemMetadata FileInfo = null;
|
||||||
public string FileType = null;
|
public string FileType = null;
|
||||||
public bool IsInitialized = false;
|
public bool IsInitialized = false;
|
||||||
@@ -65,30 +62,24 @@ namespace BDInfo
|
|||||||
public List<TSGraphicsStream> GraphicsStreams =
|
public List<TSGraphicsStream> GraphicsStreams =
|
||||||
new List<TSGraphicsStream>();
|
new List<TSGraphicsStream>();
|
||||||
|
|
||||||
public TSPlaylistFile(
|
public TSPlaylistFile(BDROM bdrom,
|
||||||
BDROM bdrom,
|
FileSystemMetadata fileInfo)
|
||||||
FileSystemMetadata fileInfo, IFileSystem fileSystem, ITextEncoding textEncoding)
|
|
||||||
{
|
{
|
||||||
BDROM = bdrom;
|
BDROM = bdrom;
|
||||||
FileInfo = fileInfo;
|
FileInfo = fileInfo;
|
||||||
_fileSystem = fileSystem;
|
|
||||||
_textEncoding = textEncoding;
|
|
||||||
Name = fileInfo.Name.ToUpper();
|
Name = fileInfo.Name.ToUpper();
|
||||||
}
|
}
|
||||||
|
|
||||||
public TSPlaylistFile(
|
public TSPlaylistFile(BDROM bdrom,
|
||||||
BDROM bdrom,
|
|
||||||
string name,
|
string name,
|
||||||
List<TSStreamClip> clips, IFileSystem fileSystem, ITextEncoding textEncoding)
|
List<TSStreamClip> clips)
|
||||||
{
|
{
|
||||||
BDROM = bdrom;
|
BDROM = bdrom;
|
||||||
Name = name;
|
Name = name;
|
||||||
_fileSystem = fileSystem;
|
|
||||||
_textEncoding = textEncoding;
|
|
||||||
IsCustom = true;
|
IsCustom = true;
|
||||||
foreach (TSStreamClip clip in clips)
|
foreach (var clip in clips)
|
||||||
{
|
{
|
||||||
TSStreamClip newClip = new TSStreamClip(
|
var newClip = new TSStreamClip(
|
||||||
clip.StreamFile, clip.StreamClipFile);
|
clip.StreamFile, clip.StreamClipFile);
|
||||||
|
|
||||||
newClip.Name = clip.Name;
|
newClip.Name = clip.Name;
|
||||||
@@ -124,7 +115,7 @@ namespace BDInfo
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
ulong size = 0;
|
ulong size = 0;
|
||||||
foreach (TSStreamClip clip in StreamClips)
|
foreach (var clip in StreamClips)
|
||||||
{
|
{
|
||||||
size += clip.InterleavedFileSize;
|
size += clip.InterleavedFileSize;
|
||||||
}
|
}
|
||||||
@@ -136,7 +127,7 @@ namespace BDInfo
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
ulong size = 0;
|
ulong size = 0;
|
||||||
foreach (TSStreamClip clip in StreamClips)
|
foreach (var clip in StreamClips)
|
||||||
{
|
{
|
||||||
size += clip.FileSize;
|
size += clip.FileSize;
|
||||||
}
|
}
|
||||||
@@ -148,7 +139,7 @@ namespace BDInfo
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
double length = 0;
|
double length = 0;
|
||||||
foreach (TSStreamClip clip in StreamClips)
|
foreach (var clip in StreamClips)
|
||||||
{
|
{
|
||||||
if (clip.AngleIndex == 0)
|
if (clip.AngleIndex == 0)
|
||||||
{
|
{
|
||||||
@@ -164,7 +155,7 @@ namespace BDInfo
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
double length = 0;
|
double length = 0;
|
||||||
foreach (TSStreamClip clip in StreamClips)
|
foreach (var clip in StreamClips)
|
||||||
{
|
{
|
||||||
length += clip.Length;
|
length += clip.Length;
|
||||||
}
|
}
|
||||||
@@ -177,7 +168,7 @@ namespace BDInfo
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
ulong size = 0;
|
ulong size = 0;
|
||||||
foreach (TSStreamClip clip in StreamClips)
|
foreach (var clip in StreamClips)
|
||||||
{
|
{
|
||||||
if (clip.AngleIndex == 0)
|
if (clip.AngleIndex == 0)
|
||||||
{
|
{
|
||||||
@@ -193,7 +184,7 @@ namespace BDInfo
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
ulong size = 0;
|
ulong size = 0;
|
||||||
foreach (TSStreamClip clip in StreamClips)
|
foreach (var clip in StreamClips)
|
||||||
{
|
{
|
||||||
size += clip.PacketSize;
|
size += clip.PacketSize;
|
||||||
}
|
}
|
||||||
@@ -237,7 +228,7 @@ namespace BDInfo
|
|||||||
Streams.Clear();
|
Streams.Clear();
|
||||||
StreamClips.Clear();
|
StreamClips.Clear();
|
||||||
|
|
||||||
fileStream = _fileSystem.OpenRead(FileInfo.FullName);
|
fileStream = File.OpenRead(FileInfo.FullName);
|
||||||
fileReader = new BinaryReader(fileStream);
|
fileReader = new BinaryReader(fileStream);
|
||||||
|
|
||||||
byte[] data = new byte[fileStream.Length];
|
byte[] data = new byte[fileStream.Length];
|
||||||
@@ -264,7 +255,7 @@ namespace BDInfo
|
|||||||
int itemCount = ReadInt16(data, ref pos);
|
int itemCount = ReadInt16(data, ref pos);
|
||||||
int subitemCount = ReadInt16(data, ref pos);
|
int subitemCount = ReadInt16(data, ref pos);
|
||||||
|
|
||||||
List<TSStreamClip> chapterClips = new List<TSStreamClip>();
|
var chapterClips = new List<TSStreamClip>();
|
||||||
for (int itemIndex = 0; itemIndex < itemCount; itemIndex++)
|
for (int itemIndex = 0; itemIndex < itemCount; itemIndex++)
|
||||||
{
|
{
|
||||||
int itemStart = pos;
|
int itemStart = pos;
|
||||||
@@ -311,7 +302,7 @@ namespace BDInfo
|
|||||||
if (outTime < 0) outTime &= 0x7FFFFFFF;
|
if (outTime < 0) outTime &= 0x7FFFFFFF;
|
||||||
double timeOut = (double)outTime / 45000;
|
double timeOut = (double)outTime / 45000;
|
||||||
|
|
||||||
TSStreamClip streamClip = new TSStreamClip(
|
var streamClip = new TSStreamClip(
|
||||||
streamFile, streamClipFile);
|
streamFile, streamClipFile);
|
||||||
|
|
||||||
streamClip.Name = streamFileName; //TODO
|
streamClip.Name = streamFileName; //TODO
|
||||||
@@ -362,7 +353,7 @@ namespace BDInfo
|
|||||||
FileInfo.Name, angleClipFileName));
|
FileInfo.Name, angleClipFileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
TSStreamClip angleClip =
|
var angleClip =
|
||||||
new TSStreamClip(angleFile, angleClipFile);
|
new TSStreamClip(angleFile, angleClipFile);
|
||||||
angleClip.AngleIndex = angle + 1;
|
angleClip.AngleIndex = angle + 1;
|
||||||
angleClip.TimeIn = streamClip.TimeIn;
|
angleClip.TimeIn = streamClip.TimeIn;
|
||||||
@@ -395,33 +386,33 @@ namespace BDInfo
|
|||||||
|
|
||||||
for (int i = 0; i < streamCountVideo; i++)
|
for (int i = 0; i < streamCountVideo; i++)
|
||||||
{
|
{
|
||||||
TSStream stream = CreatePlaylistStream(data, ref pos);
|
var stream = CreatePlaylistStream(data, ref pos);
|
||||||
if (stream != null) PlaylistStreams[stream.PID] = stream;
|
if (stream != null) PlaylistStreams[stream.PID] = stream;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < streamCountAudio; i++)
|
for (int i = 0; i < streamCountAudio; i++)
|
||||||
{
|
{
|
||||||
TSStream stream = CreatePlaylistStream(data, ref pos);
|
var stream = CreatePlaylistStream(data, ref pos);
|
||||||
if (stream != null) PlaylistStreams[stream.PID] = stream;
|
if (stream != null) PlaylistStreams[stream.PID] = stream;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < streamCountPG; i++)
|
for (int i = 0; i < streamCountPG; i++)
|
||||||
{
|
{
|
||||||
TSStream stream = CreatePlaylistStream(data, ref pos);
|
var stream = CreatePlaylistStream(data, ref pos);
|
||||||
if (stream != null) PlaylistStreams[stream.PID] = stream;
|
if (stream != null) PlaylistStreams[stream.PID] = stream;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < streamCountIG; i++)
|
for (int i = 0; i < streamCountIG; i++)
|
||||||
{
|
{
|
||||||
TSStream stream = CreatePlaylistStream(data, ref pos);
|
var stream = CreatePlaylistStream(data, ref pos);
|
||||||
if (stream != null) PlaylistStreams[stream.PID] = stream;
|
if (stream != null) PlaylistStreams[stream.PID] = stream;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < streamCountSecondaryAudio; i++)
|
for (int i = 0; i < streamCountSecondaryAudio; i++)
|
||||||
{
|
{
|
||||||
TSStream stream = CreatePlaylistStream(data, ref pos);
|
var stream = CreatePlaylistStream(data, ref pos);
|
||||||
if (stream != null) PlaylistStreams[stream.PID] = stream;
|
if (stream != null) PlaylistStreams[stream.PID] = stream;
|
||||||
pos += 2;
|
pos += 2;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < streamCountSecondaryVideo; i++)
|
for (int i = 0; i < streamCountSecondaryVideo; i++)
|
||||||
{
|
{
|
||||||
TSStream stream = CreatePlaylistStream(data, ref pos);
|
var stream = CreatePlaylistStream(data, ref pos);
|
||||||
if (stream != null) PlaylistStreams[stream.PID] = stream;
|
if (stream != null) PlaylistStreams[stream.PID] = stream;
|
||||||
pos += 6;
|
pos += 6;
|
||||||
}
|
}
|
||||||
@@ -446,7 +437,7 @@ namespace BDInfo
|
|||||||
chapterIndex < chapterCount;
|
chapterIndex < chapterCount;
|
||||||
chapterIndex++)
|
chapterIndex++)
|
||||||
{
|
{
|
||||||
int chapterType = data[pos+1];
|
int chapterType = data[pos + 1];
|
||||||
|
|
||||||
if (chapterType == 1)
|
if (chapterType == 1)
|
||||||
{
|
{
|
||||||
@@ -459,7 +450,7 @@ namespace BDInfo
|
|||||||
((long)data[pos + 6] << 8) +
|
((long)data[pos + 6] << 8) +
|
||||||
((long)data[pos + 7]);
|
((long)data[pos + 7]);
|
||||||
|
|
||||||
TSStreamClip streamClip = chapterClips[streamFileIndex];
|
var streamClip = chapterClips[streamFileIndex];
|
||||||
|
|
||||||
double chapterSeconds = (double)chapterTime / 45000;
|
double chapterSeconds = (double)chapterTime / 45000;
|
||||||
|
|
||||||
@@ -499,8 +490,8 @@ namespace BDInfo
|
|||||||
{
|
{
|
||||||
LoadStreamClips();
|
LoadStreamClips();
|
||||||
|
|
||||||
Dictionary<string, List<double>> clipTimes = new Dictionary<string, List<double>>();
|
var clipTimes = new Dictionary<string, List<double>>();
|
||||||
foreach (TSStreamClip clip in StreamClips)
|
foreach (var clip in StreamClips)
|
||||||
{
|
{
|
||||||
if (clip.AngleIndex == 0)
|
if (clip.AngleIndex == 0)
|
||||||
{
|
{
|
||||||
@@ -568,7 +559,7 @@ namespace BDInfo
|
|||||||
int streamLength = data[pos++];
|
int streamLength = data[pos++];
|
||||||
int streamPos = pos;
|
int streamPos = pos;
|
||||||
|
|
||||||
TSStreamType streamType = (TSStreamType)data[pos++];
|
var streamType = (TSStreamType)data[pos++];
|
||||||
switch (streamType)
|
switch (streamType)
|
||||||
{
|
{
|
||||||
case TSStreamType.MVC_VIDEO:
|
case TSStreamType.MVC_VIDEO:
|
||||||
@@ -580,11 +571,11 @@ namespace BDInfo
|
|||||||
case TSStreamType.MPEG2_VIDEO:
|
case TSStreamType.MPEG2_VIDEO:
|
||||||
case TSStreamType.VC1_VIDEO:
|
case TSStreamType.VC1_VIDEO:
|
||||||
|
|
||||||
TSVideoFormat videoFormat = (TSVideoFormat)
|
var videoFormat = (TSVideoFormat)
|
||||||
(data[pos] >> 4);
|
(data[pos] >> 4);
|
||||||
TSFrameRate frameRate = (TSFrameRate)
|
var frameRate = (TSFrameRate)
|
||||||
(data[pos] & 0xF);
|
(data[pos] & 0xF);
|
||||||
TSAspectRatio aspectRatio = (TSAspectRatio)
|
var aspectRatio = (TSAspectRatio)
|
||||||
(data[pos + 1] >> 4);
|
(data[pos + 1] >> 4);
|
||||||
|
|
||||||
stream = new TSVideoStream();
|
stream = new TSVideoStream();
|
||||||
@@ -618,9 +609,9 @@ namespace BDInfo
|
|||||||
|
|
||||||
int audioFormat = ReadByte(data, ref pos);
|
int audioFormat = ReadByte(data, ref pos);
|
||||||
|
|
||||||
TSChannelLayout channelLayout = (TSChannelLayout)
|
var channelLayout = (TSChannelLayout)
|
||||||
(audioFormat >> 4);
|
(audioFormat >> 4);
|
||||||
TSSampleRate sampleRate = (TSSampleRate)
|
var sampleRate = (TSSampleRate)
|
||||||
(audioFormat & 0xF);
|
(audioFormat & 0xF);
|
||||||
|
|
||||||
string audioLanguage = ReadString(data, 3, ref pos);
|
string audioLanguage = ReadString(data, 3, ref pos);
|
||||||
@@ -713,7 +704,7 @@ namespace BDInfo
|
|||||||
{
|
{
|
||||||
referenceClip = StreamClips[0];
|
referenceClip = StreamClips[0];
|
||||||
}
|
}
|
||||||
foreach (TSStreamClip clip in StreamClips)
|
foreach (var clip in StreamClips)
|
||||||
{
|
{
|
||||||
if (clip.StreamClipFile.Streams.Count > referenceClip.StreamClipFile.Streams.Count)
|
if (clip.StreamClipFile.Streams.Count > referenceClip.StreamClipFile.Streams.Count)
|
||||||
{
|
{
|
||||||
@@ -739,12 +730,12 @@ namespace BDInfo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (TSStream clipStream
|
foreach (var clipStream
|
||||||
in referenceClip.StreamClipFile.Streams.Values)
|
in referenceClip.StreamClipFile.Streams.Values)
|
||||||
{
|
{
|
||||||
if (!Streams.ContainsKey(clipStream.PID))
|
if (!Streams.ContainsKey(clipStream.PID))
|
||||||
{
|
{
|
||||||
TSStream stream = clipStream.Clone();
|
var stream = clipStream.Clone();
|
||||||
Streams[clipStream.PID] = stream;
|
Streams[clipStream.PID] = stream;
|
||||||
|
|
||||||
if (!IsCustom && !PlaylistStreams.ContainsKey(stream.PID))
|
if (!IsCustom && !PlaylistStreams.ContainsKey(stream.PID))
|
||||||
@@ -780,7 +771,7 @@ namespace BDInfo
|
|||||||
referenceClip.StreamFile.Streams.ContainsKey(4114) &&
|
referenceClip.StreamFile.Streams.ContainsKey(4114) &&
|
||||||
!Streams.ContainsKey(4114))
|
!Streams.ContainsKey(4114))
|
||||||
{
|
{
|
||||||
TSStream stream = referenceClip.StreamFile.Streams[4114].Clone();
|
var stream = referenceClip.StreamFile.Streams[4114].Clone();
|
||||||
Streams[4114] = stream;
|
Streams[4114] = stream;
|
||||||
if (stream.IsVideoStream)
|
if (stream.IsVideoStream)
|
||||||
{
|
{
|
||||||
@@ -788,12 +779,12 @@ namespace BDInfo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (TSStream clipStream
|
foreach (var clipStream
|
||||||
in referenceClip.StreamFile.Streams.Values)
|
in referenceClip.StreamFile.Streams.Values)
|
||||||
{
|
{
|
||||||
if (Streams.ContainsKey(clipStream.PID))
|
if (Streams.ContainsKey(clipStream.PID))
|
||||||
{
|
{
|
||||||
TSStream stream = Streams[clipStream.PID];
|
var stream = Streams[clipStream.PID];
|
||||||
|
|
||||||
if (stream.StreamType != clipStream.StreamType) continue;
|
if (stream.StreamType != clipStream.StreamType) continue;
|
||||||
|
|
||||||
@@ -812,8 +803,8 @@ namespace BDInfo
|
|||||||
else if (stream.IsAudioStream &&
|
else if (stream.IsAudioStream &&
|
||||||
clipStream.IsAudioStream)
|
clipStream.IsAudioStream)
|
||||||
{
|
{
|
||||||
TSAudioStream audioStream = (TSAudioStream)stream;
|
var audioStream = (TSAudioStream)stream;
|
||||||
TSAudioStream clipAudioStream = (TSAudioStream)clipStream;
|
var clipAudioStream = (TSAudioStream)clipStream;
|
||||||
|
|
||||||
if (clipAudioStream.ChannelCount > audioStream.ChannelCount)
|
if (clipAudioStream.ChannelCount > audioStream.ChannelCount)
|
||||||
{
|
{
|
||||||
@@ -864,7 +855,7 @@ namespace BDInfo
|
|||||||
SortedStreams.Add(stream);
|
SortedStreams.Add(stream);
|
||||||
for (int i = 0; i < AngleCount; i++)
|
for (int i = 0; i < AngleCount; i++)
|
||||||
{
|
{
|
||||||
TSStream angleStream = stream.Clone();
|
var angleStream = stream.Clone();
|
||||||
angleStream.AngleIndex = i + 1;
|
angleStream.AngleIndex = i + 1;
|
||||||
AngleStreams[i][angleStream.PID] = angleStream;
|
AngleStreams[i][angleStream.PID] = angleStream;
|
||||||
SortedStreams.Add(angleStream);
|
SortedStreams.Add(angleStream);
|
||||||
@@ -901,7 +892,7 @@ namespace BDInfo
|
|||||||
|
|
||||||
public void ClearBitrates()
|
public void ClearBitrates()
|
||||||
{
|
{
|
||||||
foreach (TSStreamClip clip in StreamClips)
|
foreach (var clip in StreamClips)
|
||||||
{
|
{
|
||||||
clip.PayloadBytes = 0;
|
clip.PayloadBytes = 0;
|
||||||
clip.PacketCount = 0;
|
clip.PacketCount = 0;
|
||||||
@@ -909,7 +900,7 @@ namespace BDInfo
|
|||||||
|
|
||||||
if (clip.StreamFile != null)
|
if (clip.StreamFile != null)
|
||||||
{
|
{
|
||||||
foreach (TSStream stream in clip.StreamFile.Streams.Values)
|
foreach (var stream in clip.StreamFile.Streams.Values)
|
||||||
{
|
{
|
||||||
stream.PayloadBytes = 0;
|
stream.PayloadBytes = 0;
|
||||||
stream.PacketCount = 0;
|
stream.PacketCount = 0;
|
||||||
@@ -924,7 +915,7 @@ namespace BDInfo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (TSStream stream in SortedStreams)
|
foreach (var stream in SortedStreams)
|
||||||
{
|
{
|
||||||
stream.PayloadBytes = 0;
|
stream.PayloadBytes = 0;
|
||||||
stream.PacketCount = 0;
|
stream.PacketCount = 0;
|
||||||
@@ -1246,8 +1237,7 @@ namespace BDInfo
|
|||||||
int count,
|
int count,
|
||||||
ref int pos)
|
ref int pos)
|
||||||
{
|
{
|
||||||
string val =
|
string val = Encoding.ASCII.GetString(data, pos, count);
|
||||||
_textEncoding.GetASCIIEncoding().GetString(data, pos, count);
|
|
||||||
|
|
||||||
pos += count;
|
pos += count;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||||
// Copyright © 2010 Cinema Squid
|
// Copyright © 2010 Cinema Squid
|
||||||
//
|
//
|
||||||
@@ -109,7 +109,7 @@ namespace BDInfo
|
|||||||
|
|
||||||
public TSDescriptor Clone()
|
public TSDescriptor Clone()
|
||||||
{
|
{
|
||||||
TSDescriptor descriptor =
|
var descriptor =
|
||||||
new TSDescriptor(Name, (byte)Value.Length);
|
new TSDescriptor(Name, (byte)Value.Length);
|
||||||
Value.CopyTo(descriptor.Value, 0);
|
Value.CopyTo(descriptor.Value, 0);
|
||||||
return descriptor;
|
return descriptor;
|
||||||
@@ -142,21 +142,12 @@ namespace BDInfo
|
|||||||
public double PacketSeconds = 0;
|
public double PacketSeconds = 0;
|
||||||
public int AngleIndex = 0;
|
public int AngleIndex = 0;
|
||||||
|
|
||||||
public ulong PacketSize
|
public ulong PacketSize => PacketCount * 192;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return PacketCount * 192;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string _LanguageCode;
|
private string _LanguageCode;
|
||||||
public string LanguageCode
|
public string LanguageCode
|
||||||
{
|
{
|
||||||
get
|
get => _LanguageCode;
|
||||||
{
|
|
||||||
return _LanguageCode;
|
|
||||||
}
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_LanguageCode = value;
|
_LanguageCode = value;
|
||||||
@@ -398,13 +389,7 @@ namespace BDInfo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual string Description
|
public virtual string Description => "";
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract TSStream Clone();
|
public abstract TSStream Clone();
|
||||||
|
|
||||||
@@ -419,7 +404,7 @@ namespace BDInfo
|
|||||||
if (Descriptors != null)
|
if (Descriptors != null)
|
||||||
{
|
{
|
||||||
stream.Descriptors = new List<TSDescriptor>();
|
stream.Descriptors = new List<TSDescriptor>();
|
||||||
foreach (TSDescriptor descriptor in Descriptors)
|
foreach (var descriptor in Descriptors)
|
||||||
{
|
{
|
||||||
stream.Descriptors.Add(descriptor.Clone());
|
stream.Descriptors.Add(descriptor.Clone());
|
||||||
}
|
}
|
||||||
@@ -444,10 +429,7 @@ namespace BDInfo
|
|||||||
private TSVideoFormat _VideoFormat;
|
private TSVideoFormat _VideoFormat;
|
||||||
public TSVideoFormat VideoFormat
|
public TSVideoFormat VideoFormat
|
||||||
{
|
{
|
||||||
get
|
get => _VideoFormat;
|
||||||
{
|
|
||||||
return _VideoFormat;
|
|
||||||
}
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_VideoFormat = value;
|
_VideoFormat = value;
|
||||||
@@ -488,10 +470,7 @@ namespace BDInfo
|
|||||||
private TSFrameRate _FrameRate;
|
private TSFrameRate _FrameRate;
|
||||||
public TSFrameRate FrameRate
|
public TSFrameRate FrameRate
|
||||||
{
|
{
|
||||||
get
|
get => _FrameRate;
|
||||||
{
|
|
||||||
return _FrameRate;
|
|
||||||
}
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_FrameRate = value;
|
_FrameRate = value;
|
||||||
@@ -574,7 +553,7 @@ namespace BDInfo
|
|||||||
|
|
||||||
public override TSStream Clone()
|
public override TSStream Clone()
|
||||||
{
|
{
|
||||||
TSVideoStream stream = new TSVideoStream();
|
var stream = new TSVideoStream();
|
||||||
CopyTo(stream);
|
CopyTo(stream);
|
||||||
|
|
||||||
stream.VideoFormat = _VideoFormat;
|
stream.VideoFormat = _VideoFormat;
|
||||||
@@ -748,7 +727,7 @@ namespace BDInfo
|
|||||||
|
|
||||||
public override TSStream Clone()
|
public override TSStream Clone()
|
||||||
{
|
{
|
||||||
TSAudioStream stream = new TSAudioStream();
|
var stream = new TSAudioStream();
|
||||||
CopyTo(stream);
|
CopyTo(stream);
|
||||||
|
|
||||||
stream.SampleRate = SampleRate;
|
stream.SampleRate = SampleRate;
|
||||||
@@ -777,7 +756,7 @@ namespace BDInfo
|
|||||||
|
|
||||||
public override TSStream Clone()
|
public override TSStream Clone()
|
||||||
{
|
{
|
||||||
TSGraphicsStream stream = new TSGraphicsStream();
|
var stream = new TSGraphicsStream();
|
||||||
CopyTo(stream);
|
CopyTo(stream);
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
@@ -793,7 +772,7 @@ namespace BDInfo
|
|||||||
|
|
||||||
public override TSStream Clone()
|
public override TSStream Clone()
|
||||||
{
|
{
|
||||||
TSTextStream stream = new TSTextStream();
|
var stream = new TSTextStream();
|
||||||
CopyTo(stream);
|
CopyTo(stream);
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||||
// Copyright © 2010 Cinema Squid
|
// Copyright © 2010 Cinema Squid
|
||||||
//
|
//
|
||||||
@@ -37,21 +37,9 @@ namespace BDInfo
|
|||||||
Stream = new MemoryStream(Buffer);
|
Stream = new MemoryStream(Buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long Length
|
public long Length => (long)BufferLength;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return (long)BufferLength;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public long Position
|
public long Position => Stream.Position;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Stream.Position;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(
|
public void Add(
|
||||||
byte[] buffer,
|
byte[] buffer,
|
||||||
@@ -123,7 +111,7 @@ namespace BDInfo
|
|||||||
data += (Stream.ReadByte() << shift);
|
data += (Stream.ReadByte() << shift);
|
||||||
shift -= 8;
|
shift -= 8;
|
||||||
}
|
}
|
||||||
BitVector32 vector = new BitVector32(data);
|
var vector = new BitVector32(data);
|
||||||
|
|
||||||
int value = 0;
|
int value = 0;
|
||||||
for (int i = SkipBits; i < SkipBits + bits; i++)
|
for (int i = SkipBits; i < SkipBits + bits; i++)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||||
// Copyright © 2010 Cinema Squid
|
// Copyright © 2010 Cinema Squid
|
||||||
//
|
//
|
||||||
@@ -74,13 +74,7 @@ namespace BDInfo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ulong PacketSize
|
public ulong PacketSize => PacketCount * 192;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return PacketCount * 192;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ulong PacketBitRate
|
public ulong PacketBitRate
|
||||||
{
|
{
|
||||||
@@ -96,11 +90,11 @@ namespace BDInfo
|
|||||||
|
|
||||||
public bool IsCompatible(TSStreamClip clip)
|
public bool IsCompatible(TSStreamClip clip)
|
||||||
{
|
{
|
||||||
foreach (TSStream stream1 in StreamFile.Streams.Values)
|
foreach (var stream1 in StreamFile.Streams.Values)
|
||||||
{
|
{
|
||||||
if (clip.StreamFile.Streams.ContainsKey(stream1.PID))
|
if (clip.StreamFile.Streams.ContainsKey(stream1.PID))
|
||||||
{
|
{
|
||||||
TSStream stream2 = clip.StreamFile.Streams[stream1.PID];
|
var stream2 = clip.StreamFile.Streams[stream1.PID];
|
||||||
if (stream1.StreamType != stream2.StreamType)
|
if (stream1.StreamType != stream2.StreamType)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||||
// Copyright © 2010 Cinema Squid
|
// Copyright © 2010 Cinema Squid
|
||||||
//
|
//
|
||||||
@@ -23,28 +23,22 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.Text;
|
|
||||||
|
|
||||||
namespace BDInfo
|
namespace BDInfo
|
||||||
{
|
{
|
||||||
public class TSStreamClipFile
|
public class TSStreamClipFile
|
||||||
{
|
{
|
||||||
private readonly IFileSystem _fileSystem;
|
|
||||||
private readonly ITextEncoding _textEncoding;
|
|
||||||
public FileSystemMetadata FileInfo = null;
|
public FileSystemMetadata FileInfo = null;
|
||||||
public string FileType = null;
|
public string FileType = null;
|
||||||
public bool IsValid = false;
|
public bool IsValid = false;
|
||||||
public string Name = null;
|
public string Name = null;
|
||||||
|
|
||||||
public Dictionary<ushort, TSStream> Streams =
|
public Dictionary<ushort, TSStream> Streams =
|
||||||
new Dictionary<ushort,TSStream>();
|
new Dictionary<ushort, TSStream>();
|
||||||
|
|
||||||
public TSStreamClipFile(
|
public TSStreamClipFile(FileSystemMetadata fileInfo)
|
||||||
FileSystemMetadata fileInfo, IFileSystem fileSystem, ITextEncoding textEncoding)
|
|
||||||
{
|
{
|
||||||
FileInfo = fileInfo;
|
FileInfo = fileInfo;
|
||||||
_fileSystem = fileSystem;
|
|
||||||
_textEncoding = textEncoding;
|
|
||||||
Name = fileInfo.Name.ToUpper();
|
Name = fileInfo.Name.ToUpper();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +55,7 @@ namespace BDInfo
|
|||||||
#endif
|
#endif
|
||||||
Streams.Clear();
|
Streams.Clear();
|
||||||
|
|
||||||
fileStream = _fileSystem.OpenRead(FileInfo.FullName);
|
fileStream = File.OpenRead(FileInfo.FullName);
|
||||||
fileReader = new BinaryReader(fileStream);
|
fileReader = new BinaryReader(fileStream);
|
||||||
|
|
||||||
byte[] data = new byte[fileStream.Length];
|
byte[] data = new byte[fileStream.Length];
|
||||||
@@ -70,7 +64,7 @@ namespace BDInfo
|
|||||||
byte[] fileType = new byte[8];
|
byte[] fileType = new byte[8];
|
||||||
Array.Copy(data, 0, fileType, 0, fileType.Length);
|
Array.Copy(data, 0, fileType, 0, fileType.Length);
|
||||||
|
|
||||||
FileType = _textEncoding.GetASCIIEncoding().GetString(fileType, 0, fileType.Length);
|
FileType = Encoding.ASCII.GetString(fileType, 0, fileType.Length);
|
||||||
if (FileType != "HDMV0100" &&
|
if (FileType != "HDMV0100" &&
|
||||||
FileType != "HDMV0200")
|
FileType != "HDMV0200")
|
||||||
{
|
{
|
||||||
@@ -115,7 +109,7 @@ namespace BDInfo
|
|||||||
|
|
||||||
streamOffset += 2;
|
streamOffset += 2;
|
||||||
|
|
||||||
TSStreamType streamType = (TSStreamType)
|
var streamType = (TSStreamType)
|
||||||
clipData[streamOffset + 1];
|
clipData[streamOffset + 1];
|
||||||
switch (streamType)
|
switch (streamType)
|
||||||
{
|
{
|
||||||
@@ -127,18 +121,18 @@ namespace BDInfo
|
|||||||
case TSStreamType.MPEG1_VIDEO:
|
case TSStreamType.MPEG1_VIDEO:
|
||||||
case TSStreamType.MPEG2_VIDEO:
|
case TSStreamType.MPEG2_VIDEO:
|
||||||
case TSStreamType.VC1_VIDEO:
|
case TSStreamType.VC1_VIDEO:
|
||||||
{
|
{
|
||||||
TSVideoFormat videoFormat = (TSVideoFormat)
|
var videoFormat = (TSVideoFormat)
|
||||||
(clipData[streamOffset + 2] >> 4);
|
(clipData[streamOffset + 2] >> 4);
|
||||||
TSFrameRate frameRate = (TSFrameRate)
|
var frameRate = (TSFrameRate)
|
||||||
(clipData[streamOffset + 2] & 0xF);
|
(clipData[streamOffset + 2] & 0xF);
|
||||||
TSAspectRatio aspectRatio = (TSAspectRatio)
|
var aspectRatio = (TSAspectRatio)
|
||||||
(clipData[streamOffset + 3] >> 4);
|
(clipData[streamOffset + 3] >> 4);
|
||||||
|
|
||||||
stream = new TSVideoStream();
|
stream = new TSVideoStream();
|
||||||
((TSVideoStream)stream).VideoFormat = videoFormat;
|
((TSVideoStream)stream).VideoFormat = videoFormat;
|
||||||
((TSVideoStream)stream).AspectRatio = aspectRatio;
|
((TSVideoStream)stream).AspectRatio = aspectRatio;
|
||||||
((TSVideoStream)stream).FrameRate = frameRate;
|
((TSVideoStream)stream).FrameRate = frameRate;
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Debug.WriteLine(string.Format(
|
Debug.WriteLine(string.Format(
|
||||||
"\t{0} {1} {2} {3} {4}",
|
"\t{0} {1} {2} {3} {4}",
|
||||||
@@ -148,8 +142,8 @@ namespace BDInfo
|
|||||||
frameRate,
|
frameRate,
|
||||||
aspectRatio));
|
aspectRatio));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TSStreamType.AC3_AUDIO:
|
case TSStreamType.AC3_AUDIO:
|
||||||
case TSStreamType.AC3_PLUS_AUDIO:
|
case TSStreamType.AC3_PLUS_AUDIO:
|
||||||
@@ -162,23 +156,22 @@ namespace BDInfo
|
|||||||
case TSStreamType.LPCM_AUDIO:
|
case TSStreamType.LPCM_AUDIO:
|
||||||
case TSStreamType.MPEG1_AUDIO:
|
case TSStreamType.MPEG1_AUDIO:
|
||||||
case TSStreamType.MPEG2_AUDIO:
|
case TSStreamType.MPEG2_AUDIO:
|
||||||
{
|
{
|
||||||
byte[] languageBytes = new byte[3];
|
byte[] languageBytes = new byte[3];
|
||||||
Array.Copy(clipData, streamOffset + 3,
|
Array.Copy(clipData, streamOffset + 3,
|
||||||
languageBytes, 0, languageBytes.Length);
|
languageBytes, 0, languageBytes.Length);
|
||||||
string languageCode =
|
string languageCode = Encoding.ASCII.GetString(languageBytes, 0, languageBytes.Length);
|
||||||
_textEncoding.GetASCIIEncoding().GetString(languageBytes, 0, languageBytes.Length);
|
|
||||||
|
|
||||||
TSChannelLayout channelLayout = (TSChannelLayout)
|
var channelLayout = (TSChannelLayout)
|
||||||
(clipData[streamOffset + 2] >> 4);
|
(clipData[streamOffset + 2] >> 4);
|
||||||
TSSampleRate sampleRate = (TSSampleRate)
|
var sampleRate = (TSSampleRate)
|
||||||
(clipData[streamOffset + 2] & 0xF);
|
(clipData[streamOffset + 2] & 0xF);
|
||||||
|
|
||||||
stream = new TSAudioStream();
|
stream = new TSAudioStream();
|
||||||
((TSAudioStream)stream).LanguageCode = languageCode;
|
((TSAudioStream)stream).LanguageCode = languageCode;
|
||||||
((TSAudioStream)stream).ChannelLayout = channelLayout;
|
((TSAudioStream)stream).ChannelLayout = channelLayout;
|
||||||
((TSAudioStream)stream).SampleRate = TSAudioStream.ConvertSampleRate(sampleRate);
|
((TSAudioStream)stream).SampleRate = TSAudioStream.ConvertSampleRate(sampleRate);
|
||||||
((TSAudioStream)stream).LanguageCode = languageCode;
|
((TSAudioStream)stream).LanguageCode = languageCode;
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Debug.WriteLine(string.Format(
|
Debug.WriteLine(string.Format(
|
||||||
"\t{0} {1} {2} {3} {4}",
|
"\t{0} {1} {2} {3} {4}",
|
||||||
@@ -188,20 +181,19 @@ namespace BDInfo
|
|||||||
channelLayout,
|
channelLayout,
|
||||||
sampleRate));
|
sampleRate));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TSStreamType.INTERACTIVE_GRAPHICS:
|
case TSStreamType.INTERACTIVE_GRAPHICS:
|
||||||
case TSStreamType.PRESENTATION_GRAPHICS:
|
case TSStreamType.PRESENTATION_GRAPHICS:
|
||||||
{
|
{
|
||||||
byte[] languageBytes = new byte[3];
|
byte[] languageBytes = new byte[3];
|
||||||
Array.Copy(clipData, streamOffset + 2,
|
Array.Copy(clipData, streamOffset + 2,
|
||||||
languageBytes, 0, languageBytes.Length);
|
languageBytes, 0, languageBytes.Length);
|
||||||
string languageCode =
|
string languageCode = Encoding.ASCII.GetString(languageBytes, 0, languageBytes.Length);
|
||||||
_textEncoding.GetASCIIEncoding().GetString(languageBytes, 0, languageBytes.Length);
|
|
||||||
|
|
||||||
stream = new TSGraphicsStream();
|
stream = new TSGraphicsStream();
|
||||||
stream.LanguageCode = languageCode;
|
stream.LanguageCode = languageCode;
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Debug.WriteLine(string.Format(
|
Debug.WriteLine(string.Format(
|
||||||
"\t{0} {1} {2}",
|
"\t{0} {1} {2}",
|
||||||
@@ -209,16 +201,15 @@ namespace BDInfo
|
|||||||
streamType,
|
streamType,
|
||||||
languageCode));
|
languageCode));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TSStreamType.SUBTITLE:
|
case TSStreamType.SUBTITLE:
|
||||||
{
|
{
|
||||||
byte[] languageBytes = new byte[3];
|
byte[] languageBytes = new byte[3];
|
||||||
Array.Copy(clipData, streamOffset + 3,
|
Array.Copy(clipData, streamOffset + 3,
|
||||||
languageBytes, 0, languageBytes.Length);
|
languageBytes, 0, languageBytes.Length);
|
||||||
string languageCode =
|
string languageCode = Encoding.ASCII.GetString(languageBytes, 0, languageBytes.Length);
|
||||||
_textEncoding.GetASCIIEncoding().GetString(languageBytes, 0, languageBytes.Length);
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Debug.WriteLine(string.Format(
|
Debug.WriteLine(string.Format(
|
||||||
"\t{0} {1} {2}",
|
"\t{0} {1} {2}",
|
||||||
@@ -227,9 +218,9 @@ namespace BDInfo
|
|||||||
languageCode));
|
languageCode));
|
||||||
#endif
|
#endif
|
||||||
stream = new TSTextStream();
|
stream = new TSTextStream();
|
||||||
stream.LanguageCode = languageCode;
|
stream.LanguageCode = languageCode;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream != null)
|
if (stream != null)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||||
// Copyright © 2010 Cinema Squid
|
// Copyright © 2010 Cinema Squid
|
||||||
//
|
//
|
||||||
@@ -283,7 +283,7 @@ namespace BDInfo
|
|||||||
|
|
||||||
bool isAVC = false;
|
bool isAVC = false;
|
||||||
bool isMVC = false;
|
bool isMVC = false;
|
||||||
foreach (TSStream finishedStream in Streams.Values)
|
foreach (var finishedStream in Streams.Values)
|
||||||
{
|
{
|
||||||
if (!finishedStream.IsInitialized)
|
if (!finishedStream.IsInitialized)
|
||||||
{
|
{
|
||||||
@@ -327,10 +327,10 @@ namespace BDInfo
|
|||||||
UpdateStreamBitrate(PID, PTSPID, PTS, PTSDiff);
|
UpdateStreamBitrate(PID, PTSPID, PTS, PTSDiff);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (TSPlaylistFile playlist in Playlists)
|
foreach (var playlist in Playlists)
|
||||||
{
|
{
|
||||||
double packetSeconds = 0;
|
double packetSeconds = 0;
|
||||||
foreach (TSStreamClip clip in playlist.StreamClips)
|
foreach (var clip in playlist.StreamClips)
|
||||||
{
|
{
|
||||||
if (clip.AngleIndex == 0)
|
if (clip.AngleIndex == 0)
|
||||||
{
|
{
|
||||||
@@ -339,7 +339,7 @@ namespace BDInfo
|
|||||||
}
|
}
|
||||||
if (packetSeconds > 0)
|
if (packetSeconds > 0)
|
||||||
{
|
{
|
||||||
foreach (TSStream playlistStream in playlist.SortedStreams)
|
foreach (var playlistStream in playlist.SortedStreams)
|
||||||
{
|
{
|
||||||
if (playlistStream.IsVBR)
|
if (playlistStream.IsVBR)
|
||||||
{
|
{
|
||||||
@@ -366,14 +366,14 @@ namespace BDInfo
|
|||||||
{
|
{
|
||||||
if (Playlists == null) return;
|
if (Playlists == null) return;
|
||||||
|
|
||||||
TSStreamState streamState = StreamStates[PID];
|
var streamState = StreamStates[PID];
|
||||||
double streamTime = (double)PTS / 90000;
|
double streamTime = (double)PTS / 90000;
|
||||||
double streamInterval = (double)PTSDiff / 90000;
|
double streamInterval = (double)PTSDiff / 90000;
|
||||||
double streamOffset = streamTime + streamInterval;
|
double streamOffset = streamTime + streamInterval;
|
||||||
|
|
||||||
foreach (TSPlaylistFile playlist in Playlists)
|
foreach (var playlist in Playlists)
|
||||||
{
|
{
|
||||||
foreach (TSStreamClip clip in playlist.StreamClips)
|
foreach (var clip in playlist.StreamClips)
|
||||||
{
|
{
|
||||||
if (clip.Name != this.Name) continue;
|
if (clip.Name != this.Name) continue;
|
||||||
|
|
||||||
@@ -390,7 +390,7 @@ namespace BDInfo
|
|||||||
clip.PacketSeconds = streamOffset - clip.TimeIn;
|
clip.PacketSeconds = streamOffset - clip.TimeIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary<ushort, TSStream> playlistStreams = playlist.Streams;
|
var playlistStreams = playlist.Streams;
|
||||||
if (clip.AngleIndex > 0 &&
|
if (clip.AngleIndex > 0 &&
|
||||||
clip.AngleIndex < playlist.AngleStreams.Count + 1)
|
clip.AngleIndex < playlist.AngleStreams.Count + 1)
|
||||||
{
|
{
|
||||||
@@ -398,7 +398,7 @@ namespace BDInfo
|
|||||||
}
|
}
|
||||||
if (playlistStreams.ContainsKey(PID))
|
if (playlistStreams.ContainsKey(PID))
|
||||||
{
|
{
|
||||||
TSStream stream = playlistStreams[PID];
|
var stream = playlistStreams[PID];
|
||||||
|
|
||||||
stream.PayloadBytes += streamState.WindowBytes;
|
stream.PayloadBytes += streamState.WindowBytes;
|
||||||
stream.PacketCount += streamState.WindowPackets;
|
stream.PacketCount += streamState.WindowPackets;
|
||||||
@@ -425,13 +425,13 @@ namespace BDInfo
|
|||||||
|
|
||||||
if (Streams.ContainsKey(PID))
|
if (Streams.ContainsKey(PID))
|
||||||
{
|
{
|
||||||
TSStream stream = Streams[PID];
|
var stream = Streams[PID];
|
||||||
stream.PayloadBytes += streamState.WindowBytes;
|
stream.PayloadBytes += streamState.WindowBytes;
|
||||||
stream.PacketCount += streamState.WindowPackets;
|
stream.PacketCount += streamState.WindowPackets;
|
||||||
|
|
||||||
if (stream.IsVideoStream)
|
if (stream.IsVideoStream)
|
||||||
{
|
{
|
||||||
TSStreamDiagnostics diag = new TSStreamDiagnostics();
|
var diag = new TSStreamDiagnostics();
|
||||||
diag.Marker = (double)PTS / 90000;
|
diag.Marker = (double)PTS / 90000;
|
||||||
diag.Interval = (double)PTSDiff / 90000;
|
diag.Interval = (double)PTSDiff / 90000;
|
||||||
diag.Bytes = streamState.WindowBytes;
|
diag.Bytes = streamState.WindowBytes;
|
||||||
@@ -482,7 +482,7 @@ namespace BDInfo
|
|||||||
StreamStates.Clear();
|
StreamStates.Clear();
|
||||||
StreamDiagnostics.Clear();
|
StreamDiagnostics.Clear();
|
||||||
|
|
||||||
TSPacketParser parser =
|
var parser =
|
||||||
new TSPacketParser();
|
new TSPacketParser();
|
||||||
|
|
||||||
long fileLength = (uint)fileStream.Length;
|
long fileLength = (uint)fileStream.Length;
|
||||||
@@ -536,80 +536,80 @@ namespace BDInfo
|
|||||||
switch (parser.HeaderParse)
|
switch (parser.HeaderParse)
|
||||||
{
|
{
|
||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
parser.TransportErrorIndicator =
|
parser.TransportErrorIndicator =
|
||||||
(byte)((buffer[i] >> 7) & 0x1);
|
(byte)((buffer[i] >> 7) & 0x1);
|
||||||
parser.PayloadUnitStartIndicator =
|
parser.PayloadUnitStartIndicator =
|
||||||
(byte)((buffer[i] >> 6) & 0x1);
|
(byte)((buffer[i] >> 6) & 0x1);
|
||||||
parser.TransportPriority =
|
parser.TransportPriority =
|
||||||
(byte)((buffer[i] >> 5) & 0x1);
|
(byte)((buffer[i] >> 5) & 0x1);
|
||||||
parser.PID =
|
parser.PID =
|
||||||
(ushort)((buffer[i] & 0x1f) << 8);
|
(ushort)((buffer[i] & 0x1f) << 8);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
{
|
|
||||||
parser.PID |= (ushort)buffer[i];
|
|
||||||
if (Streams.ContainsKey(parser.PID))
|
|
||||||
{
|
{
|
||||||
parser.Stream = Streams[parser.PID];
|
parser.PID |= (ushort)buffer[i];
|
||||||
|
if (Streams.ContainsKey(parser.PID))
|
||||||
|
{
|
||||||
|
parser.Stream = Streams[parser.PID];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parser.Stream = null;
|
||||||
|
}
|
||||||
|
if (!StreamStates.ContainsKey(parser.PID))
|
||||||
|
{
|
||||||
|
StreamStates[parser.PID] = new TSStreamState();
|
||||||
|
}
|
||||||
|
parser.StreamState = StreamStates[parser.PID];
|
||||||
|
parser.StreamState.TotalPackets++;
|
||||||
|
parser.StreamState.WindowPackets++;
|
||||||
|
parser.TotalPackets++;
|
||||||
}
|
}
|
||||||
else
|
break;
|
||||||
{
|
|
||||||
parser.Stream = null;
|
|
||||||
}
|
|
||||||
if (!StreamStates.ContainsKey(parser.PID))
|
|
||||||
{
|
|
||||||
StreamStates[parser.PID] = new TSStreamState();
|
|
||||||
}
|
|
||||||
parser.StreamState = StreamStates[parser.PID];
|
|
||||||
parser.StreamState.TotalPackets++;
|
|
||||||
parser.StreamState.WindowPackets++;
|
|
||||||
parser.TotalPackets++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0:
|
case 0:
|
||||||
{
|
|
||||||
parser.TransportScramblingControl =
|
|
||||||
(byte)((buffer[i] >> 6) & 0x3);
|
|
||||||
parser.AdaptionFieldControl =
|
|
||||||
(byte)((buffer[i] >> 4) & 0x3);
|
|
||||||
|
|
||||||
if ((parser.AdaptionFieldControl & 0x2) == 0x2)
|
|
||||||
{
|
{
|
||||||
parser.AdaptionFieldState = true;
|
parser.TransportScramblingControl =
|
||||||
}
|
(byte)((buffer[i] >> 6) & 0x3);
|
||||||
if (parser.PayloadUnitStartIndicator == 1)
|
parser.AdaptionFieldControl =
|
||||||
{
|
(byte)((buffer[i] >> 4) & 0x3);
|
||||||
if (parser.PID == 0)
|
|
||||||
{
|
|
||||||
parser.PATSectionStart = true;
|
|
||||||
}
|
|
||||||
else if (parser.PID == parser.PMTPID)
|
|
||||||
{
|
|
||||||
parser.PMTSectionStart = true;
|
|
||||||
}
|
|
||||||
else if (parser.StreamState != null &&
|
|
||||||
parser.StreamState.TransferState)
|
|
||||||
{
|
|
||||||
parser.StreamState.TransferState = false;
|
|
||||||
parser.StreamState.TransferCount++;
|
|
||||||
|
|
||||||
bool isFinished = ScanStream(
|
if ((parser.AdaptionFieldControl & 0x2) == 0x2)
|
||||||
parser.Stream,
|
{
|
||||||
parser.StreamState,
|
parser.AdaptionFieldState = true;
|
||||||
parser.StreamState.StreamBuffer);
|
}
|
||||||
|
if (parser.PayloadUnitStartIndicator == 1)
|
||||||
if (!isFullScan && isFinished)
|
{
|
||||||
|
if (parser.PID == 0)
|
||||||
{
|
{
|
||||||
return;
|
parser.PATSectionStart = true;
|
||||||
|
}
|
||||||
|
else if (parser.PID == parser.PMTPID)
|
||||||
|
{
|
||||||
|
parser.PMTSectionStart = true;
|
||||||
|
}
|
||||||
|
else if (parser.StreamState != null &&
|
||||||
|
parser.StreamState.TransferState)
|
||||||
|
{
|
||||||
|
parser.StreamState.TransferState = false;
|
||||||
|
parser.StreamState.TransferCount++;
|
||||||
|
|
||||||
|
bool isFinished = ScanStream(
|
||||||
|
parser.Stream,
|
||||||
|
parser.StreamState,
|
||||||
|
parser.StreamState.StreamBuffer);
|
||||||
|
|
||||||
|
if (!isFullScan && isFinished)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (parser.AdaptionFieldState)
|
else if (parser.AdaptionFieldState)
|
||||||
@@ -670,7 +670,8 @@ namespace BDInfo
|
|||||||
parser.PAT[parser.PATOffset++] = buffer[i++];
|
parser.PAT[parser.PATOffset++] = buffer[i++];
|
||||||
parser.PATSectionLength--;
|
parser.PATSectionLength--;
|
||||||
parser.PacketLength--;
|
parser.PacketLength--;
|
||||||
} --i;
|
}
|
||||||
|
--i;
|
||||||
|
|
||||||
if (parser.PATSectionLength == 0)
|
if (parser.PATSectionLength == 0)
|
||||||
{
|
{
|
||||||
@@ -801,7 +802,8 @@ namespace BDInfo
|
|||||||
PMT[parser.PMTOffset++] = buffer[i++];
|
PMT[parser.PMTOffset++] = buffer[i++];
|
||||||
--parser.PMTSectionLength;
|
--parser.PMTSectionLength;
|
||||||
--parser.PacketLength;
|
--parser.PacketLength;
|
||||||
} --i;
|
}
|
||||||
|
--i;
|
||||||
|
|
||||||
if (parser.PMTSectionLength == 0)
|
if (parser.PMTSectionLength == 0)
|
||||||
{
|
{
|
||||||
@@ -837,7 +839,7 @@ namespace BDInfo
|
|||||||
|
|
||||||
if (!Streams.ContainsKey(streamPID))
|
if (!Streams.ContainsKey(streamPID))
|
||||||
{
|
{
|
||||||
List<TSDescriptor> streamDescriptors =
|
var streamDescriptors =
|
||||||
new List<TSDescriptor>();
|
new List<TSDescriptor>();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -994,7 +996,7 @@ namespace BDInfo
|
|||||||
{
|
{
|
||||||
--parser.PMTProgramDescriptorLength;
|
--parser.PMTProgramDescriptorLength;
|
||||||
|
|
||||||
TSDescriptor descriptor = parser.PMTProgramDescriptors[
|
var descriptor = parser.PMTProgramDescriptors[
|
||||||
parser.PMTProgramDescriptors.Count - 1];
|
parser.PMTProgramDescriptors.Count - 1];
|
||||||
|
|
||||||
int valueIndex =
|
int valueIndex =
|
||||||
@@ -1024,8 +1026,8 @@ namespace BDInfo
|
|||||||
parser.StreamState != null &&
|
parser.StreamState != null &&
|
||||||
parser.TransportScramblingControl == 0)
|
parser.TransportScramblingControl == 0)
|
||||||
{
|
{
|
||||||
TSStream stream = parser.Stream;
|
var stream = parser.Stream;
|
||||||
TSStreamState streamState = parser.StreamState;
|
var streamState = parser.StreamState;
|
||||||
|
|
||||||
streamState.Parse =
|
streamState.Parse =
|
||||||
(streamState.Parse << 8) + buffer[i];
|
(streamState.Parse << 8) + buffer[i];
|
||||||
@@ -1459,7 +1461,7 @@ namespace BDInfo
|
|||||||
|
|
||||||
ulong PTSLast = 0;
|
ulong PTSLast = 0;
|
||||||
ulong PTSDiff = 0;
|
ulong PTSDiff = 0;
|
||||||
foreach (TSStream stream in Streams.Values)
|
foreach (var stream in Streams.Values)
|
||||||
{
|
{
|
||||||
if (!stream.IsVideoStream) continue;
|
if (!stream.IsVideoStream) continue;
|
||||||
|
|
||||||
@@ -1495,10 +1497,10 @@ namespace BDInfo
|
|||||||
case TSStreamType.MPEG1_VIDEO:
|
case TSStreamType.MPEG1_VIDEO:
|
||||||
case TSStreamType.MPEG2_VIDEO:
|
case TSStreamType.MPEG2_VIDEO:
|
||||||
case TSStreamType.VC1_VIDEO:
|
case TSStreamType.VC1_VIDEO:
|
||||||
{
|
{
|
||||||
stream = new TSVideoStream();
|
stream = new TSVideoStream();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TSStreamType.AC3_AUDIO:
|
case TSStreamType.AC3_AUDIO:
|
||||||
case TSStreamType.AC3_PLUS_AUDIO:
|
case TSStreamType.AC3_PLUS_AUDIO:
|
||||||
@@ -1511,23 +1513,23 @@ namespace BDInfo
|
|||||||
case TSStreamType.LPCM_AUDIO:
|
case TSStreamType.LPCM_AUDIO:
|
||||||
case TSStreamType.MPEG1_AUDIO:
|
case TSStreamType.MPEG1_AUDIO:
|
||||||
case TSStreamType.MPEG2_AUDIO:
|
case TSStreamType.MPEG2_AUDIO:
|
||||||
{
|
{
|
||||||
stream = new TSAudioStream();
|
stream = new TSAudioStream();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TSStreamType.INTERACTIVE_GRAPHICS:
|
case TSStreamType.INTERACTIVE_GRAPHICS:
|
||||||
case TSStreamType.PRESENTATION_GRAPHICS:
|
case TSStreamType.PRESENTATION_GRAPHICS:
|
||||||
{
|
{
|
||||||
stream = new TSGraphicsStream();
|
stream = new TSGraphicsStream();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TSStreamType.SUBTITLE:
|
case TSStreamType.SUBTITLE:
|
||||||
{
|
{
|
||||||
stream = new TSTextStream();
|
stream = new TSTextStream();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -11,6 +11,19 @@
|
|||||||
- [AnthonyLavado](https://github.com/anthonylavado)
|
- [AnthonyLavado](https://github.com/anthonylavado)
|
||||||
- [sparky8251](https://github.com/sparky8251)
|
- [sparky8251](https://github.com/sparky8251)
|
||||||
- [LeoVerto](https://github.com/LeoVerto)
|
- [LeoVerto](https://github.com/LeoVerto)
|
||||||
|
- [grafixeyehero](https://github.com/grafixeyehero)
|
||||||
|
- [cvium](https://github.com/cvium)
|
||||||
|
- [wtayl0r](https://github.com/wtayl0r)
|
||||||
|
- [TtheCreator](https://github.com/Tthecreator)
|
||||||
|
- [dkanada](https://github.com/dkanada)
|
||||||
|
- [LogicalPhallacy](https://github.com/LogicalPhallacy/)
|
||||||
|
- [RazeLighter777](https://github.com/RazeLighter777)
|
||||||
|
- [WillWill56](https://github.com/WillWill56)
|
||||||
|
- [Liggy](https://github.com/Liggy)
|
||||||
|
- [fruhnow](https://github.com/fruhnow)
|
||||||
|
- [Lynxy](https://github.com/Lynxy)
|
||||||
|
- [fasheng](https://github.com/fasheng)
|
||||||
|
- [ploughpuff](https://github.com/ploughpuff)
|
||||||
|
|
||||||
# Emby Contributors
|
# Emby Contributors
|
||||||
|
|
||||||
|
|||||||
50
Dockerfile
50
Dockerfile
@@ -1,28 +1,34 @@
|
|||||||
ARG DOTNET_VERSION=2
|
ARG DOTNET_VERSION=2.2
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/core/sdk:${DOTNET_VERSION} as builder
|
||||||
# Download ffmpeg first to allow quicker rebuild of other layers
|
|
||||||
FROM alpine as ffmpeg
|
|
||||||
ARG FFMPEG_URL=https://www.johnvansickle.com/ffmpeg/old-releases/ffmpeg-4.0.3-64bit-static.tar.xz
|
|
||||||
RUN wget ${FFMPEG_URL} -O - | tar Jxf - \
|
|
||||||
&& mkdir ffmpeg-bin \
|
|
||||||
&& mv ffmpeg*/ffmpeg ffmpeg-bin \
|
|
||||||
&& mv ffmpeg*/ffprobe ffmpeg-bin
|
|
||||||
|
|
||||||
|
|
||||||
FROM microsoft/dotnet:${DOTNET_VERSION}-sdk as builder
|
|
||||||
WORKDIR /repo
|
WORKDIR /repo
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN export DOTNET_CLI_TELEMETRY_OPTOUT=1 \
|
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||||
&& dotnet clean \
|
RUN bash -c "source deployment/common.build.sh && \
|
||||||
&& dotnet publish --configuration release --output /jellyfin
|
build_jellyfin Jellyfin.Server Release linux-x64 /jellyfin"
|
||||||
|
|
||||||
|
FROM jellyfin/ffmpeg as ffmpeg
|
||||||
FROM microsoft/dotnet:${DOTNET_VERSION}-runtime
|
FROM mcr.microsoft.com/dotnet/core/runtime:${DOTNET_VERSION}
|
||||||
|
# libfontconfig1 is required for Skia
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install --no-install-recommends --no-install-suggests -y \
|
||||||
|
libfontconfig1 \
|
||||||
|
&& apt-get clean autoclean \
|
||||||
|
&& apt-get autoremove \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
|
&& mkdir -p /cache /config /media \
|
||||||
|
&& chmod 777 /cache /config /media
|
||||||
|
COPY --from=ffmpeg / /
|
||||||
COPY --from=builder /jellyfin /jellyfin
|
COPY --from=builder /jellyfin /jellyfin
|
||||||
COPY --from=ffmpeg /ffmpeg-bin/* /usr/bin/
|
|
||||||
|
ARG JELLYFIN_WEB_VERSION=10.3.1
|
||||||
|
RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/v${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
|
||||||
|
&& rm -rf /jellyfin/jellyfin-web \
|
||||||
|
&& mv jellyfin-web-${JELLYFIN_WEB_VERSION} /jellyfin/jellyfin-web
|
||||||
|
|
||||||
EXPOSE 8096
|
EXPOSE 8096
|
||||||
VOLUME /config /media
|
VOLUME /cache /config /media
|
||||||
RUN apt update \
|
ENTRYPOINT dotnet /jellyfin/jellyfin.dll \
|
||||||
&& apt install -y libfontconfig1 # needed for Skia
|
--datadir /config \
|
||||||
ENTRYPOINT dotnet /jellyfin/jellyfin.dll -programdata /config
|
--cachedir /cache \
|
||||||
|
--ffmpeg /usr/local/bin/ffmpeg
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
ARG DOTNET_VERSION=3.0
|
|
||||||
|
|
||||||
FROM microsoft/dotnet:${DOTNET_VERSION}-sdk as builder
|
|
||||||
WORKDIR /repo
|
|
||||||
COPY . .
|
|
||||||
RUN export DOTNET_CLI_TELEMETRY_OPTOUT=1 \
|
|
||||||
&& find . -type f -exec sed -i 's/netcoreapp2.1/netcoreapp3.0/g' {} \; \
|
|
||||||
&& dotnet clean \
|
|
||||||
&& dotnet publish --configuration release --output /jellyfin
|
|
||||||
|
|
||||||
FROM microsoft/dotnet:${DOTNET_VERSION}-runtime
|
|
||||||
COPY --from=builder /jellyfin /jellyfin
|
|
||||||
EXPOSE 8096
|
|
||||||
RUN apt update \
|
|
||||||
&& apt install -y ffmpeg
|
|
||||||
VOLUME /config /media
|
|
||||||
ENTRYPOINT dotnet /jellyfin/jellyfin.dll -programdata /config
|
|
||||||
43
Dockerfile.arm
Normal file
43
Dockerfile.arm
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# Requires binfm_misc registration
|
||||||
|
# https://github.com/multiarch/qemu-user-static#binfmt_misc-register
|
||||||
|
ARG DOTNET_VERSION=3.0
|
||||||
|
|
||||||
|
|
||||||
|
FROM multiarch/qemu-user-static:x86_64-arm as qemu
|
||||||
|
FROM alpine as qemu_extract
|
||||||
|
COPY --from=qemu /usr/bin qemu-arm-static.tar.gz
|
||||||
|
RUN tar -xzvf qemu-arm-static.tar.gz
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/core/sdk:${DOTNET_VERSION} as builder
|
||||||
|
WORKDIR /repo
|
||||||
|
COPY . .
|
||||||
|
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||||
|
# TODO Remove or update the sed line when we update dotnet version.
|
||||||
|
RUN find . -type f -exec sed -i 's/netcoreapp2.1/netcoreapp3.0/g' {} \;
|
||||||
|
# Discard objs - may cause failures if exists
|
||||||
|
RUN find . -type d -name obj | xargs -r rm -r
|
||||||
|
# Build
|
||||||
|
RUN bash -c "source deployment/common.build.sh && \
|
||||||
|
build_jellyfin Jellyfin.Server Release linux-arm /jellyfin"
|
||||||
|
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/core/runtime:${DOTNET_VERSION}-stretch-slim-arm32v7
|
||||||
|
COPY --from=qemu_extract qemu-arm-static /usr/bin
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install --no-install-recommends --no-install-suggests -y ffmpeg \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
|
&& mkdir -p /cache /config /media \
|
||||||
|
&& chmod 777 /cache /config /media
|
||||||
|
COPY --from=builder /jellyfin /jellyfin
|
||||||
|
|
||||||
|
ARG JELLYFIN_WEB_VERSION=10.3.1
|
||||||
|
RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/v${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
|
||||||
|
&& rm -rf /jellyfin/jellyfin-web \
|
||||||
|
&& mv jellyfin-web-${JELLYFIN_WEB_VERSION} /jellyfin/jellyfin-web
|
||||||
|
|
||||||
|
EXPOSE 8096
|
||||||
|
VOLUME /cache /config /media
|
||||||
|
ENTRYPOINT dotnet /jellyfin/jellyfin.dll \
|
||||||
|
--datadir /config \
|
||||||
|
--cachedir /cache \
|
||||||
|
--ffmpeg /usr/bin/ffmpeg
|
||||||
44
Dockerfile.arm64
Normal file
44
Dockerfile.arm64
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# Requires binfm_misc registration
|
||||||
|
# https://github.com/multiarch/qemu-user-static#binfmt_misc-register
|
||||||
|
ARG DOTNET_VERSION=3.0
|
||||||
|
|
||||||
|
|
||||||
|
FROM multiarch/qemu-user-static:x86_64-aarch64 as qemu
|
||||||
|
FROM alpine as qemu_extract
|
||||||
|
COPY --from=qemu /usr/bin qemu-aarch64-static.tar.gz
|
||||||
|
RUN tar -xzvf qemu-aarch64-static.tar.gz
|
||||||
|
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/core/sdk:${DOTNET_VERSION} as builder
|
||||||
|
WORKDIR /repo
|
||||||
|
COPY . .
|
||||||
|
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||||
|
# TODO Remove or update the sed line when we update dotnet version.
|
||||||
|
RUN find . -type f -exec sed -i 's/netcoreapp2.1/netcoreapp3.0/g' {} \;
|
||||||
|
# Discard objs - may cause failures if exists
|
||||||
|
RUN find . -type d -name obj | xargs -r rm -r
|
||||||
|
# Build
|
||||||
|
RUN bash -c "source deployment/common.build.sh && \
|
||||||
|
build_jellyfin Jellyfin.Server Release linux-arm64 /jellyfin"
|
||||||
|
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/core/runtime:${DOTNET_VERSION}-stretch-slim-arm64v8
|
||||||
|
COPY --from=qemu_extract qemu-aarch64-static /usr/bin
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install --no-install-recommends --no-install-suggests -y ffmpeg \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
|
&& mkdir -p /cache /config /media \
|
||||||
|
&& chmod 777 /cache /config /media
|
||||||
|
COPY --from=builder /jellyfin /jellyfin
|
||||||
|
|
||||||
|
ARG JELLYFIN_WEB_VERSION=10.3.1
|
||||||
|
RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/v${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
|
||||||
|
&& rm -rf /jellyfin/jellyfin-web \
|
||||||
|
&& mv jellyfin-web-${JELLYFIN_WEB_VERSION} /jellyfin/jellyfin-web
|
||||||
|
|
||||||
|
EXPOSE 8096
|
||||||
|
VOLUME /cache /config /media
|
||||||
|
ENTRYPOINT dotnet /jellyfin/jellyfin.dll \
|
||||||
|
--datadir /config \
|
||||||
|
--cachedir /cache \
|
||||||
|
--ffmpeg /usr/bin/ffmpeg
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
FROM debian:9
|
|
||||||
|
|
||||||
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
|
||||||
RUN apt-get update \
|
|
||||||
&& apt-get install -y apt-transport-https debhelper gnupg wget devscripts \
|
|
||||||
&& wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.asc.gpg \
|
|
||||||
&& mv microsoft.asc.gpg /etc/apt/trusted.gpg.d/ \
|
|
||||||
&& wget -q https://packages.microsoft.com/config/debian/9/prod.list \
|
|
||||||
&& mv prod.list /etc/apt/sources.list.d/microsoft-prod.list \
|
|
||||||
&& chown root:root /etc/apt/trusted.gpg.d/microsoft.asc.gpg \
|
|
||||||
&& chown root:root /etc/apt/sources.list.d/microsoft-prod.list \
|
|
||||||
&& apt-get update
|
|
||||||
|
|
||||||
WORKDIR /repo
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
RUN yes|mk-build-deps -i \
|
|
||||||
&& dpkg-buildpackage -us -uc \
|
|
||||||
&& mkdir /dist \
|
|
||||||
&& mv /jellyfin*deb /dist
|
|
||||||
|
|
||||||
WORKDIR /dist
|
|
||||||
@@ -1,7 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace DvdLib
|
namespace DvdLib
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="..\SharedVersion.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DvdLib.Ifo
|
|
||||||
{
|
|
||||||
public enum AudioCodec
|
|
||||||
{
|
|
||||||
AC3 = 0,
|
|
||||||
MPEG1 = 2,
|
|
||||||
MPEG2ext = 3,
|
|
||||||
LPCM = 4,
|
|
||||||
DTS = 6,
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ApplicationMode
|
|
||||||
{
|
|
||||||
Unspecified = 0,
|
|
||||||
Karaoke = 1,
|
|
||||||
Surround = 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
public class AudioAttributes
|
|
||||||
{
|
|
||||||
public readonly AudioCodec Codec;
|
|
||||||
public readonly bool MultichannelExtensionPresent;
|
|
||||||
public readonly ApplicationMode Mode;
|
|
||||||
public readonly byte QuantDRC;
|
|
||||||
public readonly byte SampleRate;
|
|
||||||
public readonly byte Channels;
|
|
||||||
public readonly ushort LanguageCode;
|
|
||||||
public readonly byte LanguageExtension;
|
|
||||||
public readonly byte CodeExtension;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class MultiChannelExtension
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace DvdLib.Ifo
|
namespace DvdLib.Ifo
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace DvdLib.Ifo
|
namespace DvdLib.Ifo
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace DvdLib.Ifo
|
namespace DvdLib.Ifo
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DvdLib.Ifo
|
namespace DvdLib.Ifo
|
||||||
{
|
{
|
||||||
public class Chapter
|
public class Chapter
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Diagnostics;
|
using System.Linq;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
|
||||||
namespace DvdLib.Ifo
|
namespace DvdLib.Ifo
|
||||||
@@ -28,18 +26,17 @@ namespace DvdLib.Ifo
|
|||||||
|
|
||||||
if (vmgPath == null)
|
if (vmgPath == null)
|
||||||
{
|
{
|
||||||
var allIfos = allFiles.Where(i => string.Equals(i.Extension, ".ifo", StringComparison.OrdinalIgnoreCase));
|
foreach (var ifo in allFiles)
|
||||||
|
|
||||||
foreach (var ifo in allIfos)
|
|
||||||
{
|
{
|
||||||
var num = ifo.Name.Split('_').ElementAtOrDefault(1);
|
if (!string.Equals(ifo.Extension, ".ifo", StringComparison.OrdinalIgnoreCase))
|
||||||
ushort ifoNumber;
|
{
|
||||||
var numbersRead = new List<ushort>();
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(num) && ushort.TryParse(num, out ifoNumber) && !numbersRead.Contains(ifoNumber))
|
var nums = ifo.Name.Split(new [] { '_' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
if (nums.Length >= 2 && ushort.TryParse(nums[1], out var ifoNumber))
|
||||||
{
|
{
|
||||||
ReadVTS(ifoNumber, ifo.FullName);
|
ReadVTS(ifoNumber, ifo.FullName);
|
||||||
numbersRead.Add(ifoNumber);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,7 +44,7 @@ namespace DvdLib.Ifo
|
|||||||
{
|
{
|
||||||
using (var vmgFs = _fileSystem.GetFileStream(vmgPath.FullName, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read))
|
using (var vmgFs = _fileSystem.GetFileStream(vmgPath.FullName, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read))
|
||||||
{
|
{
|
||||||
using (BigEndianBinaryReader vmgRead = new BigEndianBinaryReader(vmgFs))
|
using (var vmgRead = new BigEndianBinaryReader(vmgFs))
|
||||||
{
|
{
|
||||||
vmgFs.Seek(0x3E, SeekOrigin.Begin);
|
vmgFs.Seek(0x3E, SeekOrigin.Begin);
|
||||||
_titleSetCount = vmgRead.ReadUInt16();
|
_titleSetCount = vmgRead.ReadUInt16();
|
||||||
@@ -73,15 +70,15 @@ namespace DvdLib.Ifo
|
|||||||
read.BaseStream.Seek(6, SeekOrigin.Current);
|
read.BaseStream.Seek(6, SeekOrigin.Current);
|
||||||
for (uint titleNum = 1; titleNum <= _titleCount; titleNum++)
|
for (uint titleNum = 1; titleNum <= _titleCount; titleNum++)
|
||||||
{
|
{
|
||||||
Title t = new Title(titleNum);
|
var t = new Title(titleNum);
|
||||||
t.ParseTT_SRPT(read);
|
t.ParseTT_SRPT(read);
|
||||||
Titles.Add(t);
|
Titles.Add(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReadVTS(ushort vtsNum, List<FileSystemMetadata> allFiles)
|
private void ReadVTS(ushort vtsNum, IEnumerable<FileSystemMetadata> allFiles)
|
||||||
{
|
{
|
||||||
var filename = String.Format("VTS_{0:00}_0.IFO", vtsNum);
|
var filename = string.Format("VTS_{0:00}_0.IFO", vtsNum);
|
||||||
|
|
||||||
var vtsPath = allFiles.FirstOrDefault(i => string.Equals(i.Name, filename, StringComparison.OrdinalIgnoreCase)) ??
|
var vtsPath = allFiles.FirstOrDefault(i => string.Equals(i.Name, filename, StringComparison.OrdinalIgnoreCase)) ??
|
||||||
allFiles.FirstOrDefault(i => string.Equals(i.Name, Path.ChangeExtension(filename, ".bup"), StringComparison.OrdinalIgnoreCase));
|
allFiles.FirstOrDefault(i => string.Equals(i.Name, Path.ChangeExtension(filename, ".bup"), StringComparison.OrdinalIgnoreCase));
|
||||||
@@ -100,7 +97,7 @@ namespace DvdLib.Ifo
|
|||||||
|
|
||||||
using (var vtsFs = _fileSystem.GetFileStream(vtsPath, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read))
|
using (var vtsFs = _fileSystem.GetFileStream(vtsPath, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read))
|
||||||
{
|
{
|
||||||
using (BigEndianBinaryReader vtsRead = new BigEndianBinaryReader(vtsFs))
|
using (var vtsRead = new BigEndianBinaryReader(vtsFs))
|
||||||
{
|
{
|
||||||
// Read VTS_PTT_SRPT
|
// Read VTS_PTT_SRPT
|
||||||
vtsFs.Seek(0xC8, SeekOrigin.Begin);
|
vtsFs.Seek(0xC8, SeekOrigin.Begin);
|
||||||
@@ -121,7 +118,7 @@ namespace DvdLib.Ifo
|
|||||||
{
|
{
|
||||||
uint chapNum = 1;
|
uint chapNum = 1;
|
||||||
vtsFs.Seek(baseAddr + offsets[titleNum], SeekOrigin.Begin);
|
vtsFs.Seek(baseAddr + offsets[titleNum], SeekOrigin.Begin);
|
||||||
Title t = Titles.FirstOrDefault(vtst => vtst.IsVTSTitle(vtsNum, titleNum + 1));
|
var t = Titles.FirstOrDefault(vtst => vtst.IsVTSTitle(vtsNum, titleNum + 1));
|
||||||
if (t == null) continue;
|
if (t == null) continue;
|
||||||
|
|
||||||
do
|
do
|
||||||
@@ -151,7 +148,7 @@ namespace DvdLib.Ifo
|
|||||||
vtsFs.Seek(3, SeekOrigin.Current);
|
vtsFs.Seek(3, SeekOrigin.Current);
|
||||||
uint vtsPgcOffset = vtsRead.ReadUInt32();
|
uint vtsPgcOffset = vtsRead.ReadUInt32();
|
||||||
|
|
||||||
Title t = Titles.FirstOrDefault(vtst => vtst.IsVTSTitle(vtsNum, titleNum));
|
var t = Titles.FirstOrDefault(vtst => vtst.IsVTSTitle(vtsNum, titleNum));
|
||||||
if (t != null) t.AddPgc(vtsRead, startByte + vtsPgcOffset, entryPgc, pgcNum);
|
if (t != null) t.AddPgc(vtsRead, startByte + vtsPgcOffset, entryPgc, pgcNum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DvdLib.Ifo
|
namespace DvdLib.Ifo
|
||||||
{
|
{
|
||||||
@@ -20,7 +17,7 @@ namespace DvdLib.Ifo
|
|||||||
else if ((data[3] & 0x40) != 0) FrameRate = 25;
|
else if ((data[3] & 0x40) != 0) FrameRate = 25;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte GetBCDValue(byte data)
|
private static byte GetBCDValue(byte data)
|
||||||
{
|
{
|
||||||
return (byte)((((data & 0xF0) >> 4) * 10) + (data & 0x0F));
|
return (byte)((((data & 0xF0) >> 4) * 10) + (data & 0x0F));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DvdLib.Ifo
|
|
||||||
{
|
|
||||||
public class ProgramChainCommandTable
|
|
||||||
{
|
|
||||||
public readonly ushort LastByteAddress;
|
|
||||||
public readonly List<VirtualMachineCommand> PreCommands;
|
|
||||||
public readonly List<VirtualMachineCommand> PostCommands;
|
|
||||||
public readonly List<VirtualMachineCommand> CellCommands;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class VirtualMachineCommand
|
|
||||||
{
|
|
||||||
public readonly byte[] Command;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,4 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DvdLib.Ifo
|
namespace DvdLib.Ifo
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace DvdLib.Ifo
|
namespace DvdLib.Ifo
|
||||||
{
|
{
|
||||||
@@ -27,13 +25,10 @@ namespace DvdLib.Ifo
|
|||||||
public byte[] SubpictureStreamControl { get; private set; } // 32*4 entries
|
public byte[] SubpictureStreamControl { get; private set; } // 32*4 entries
|
||||||
|
|
||||||
private ushort _nextProgramNumber;
|
private ushort _nextProgramNumber;
|
||||||
public readonly ProgramChain Next;
|
|
||||||
|
|
||||||
private ushort _prevProgramNumber;
|
private ushort _prevProgramNumber;
|
||||||
public readonly ProgramChain Previous;
|
|
||||||
|
|
||||||
private ushort _goupProgramNumber;
|
private ushort _goupProgramNumber;
|
||||||
public readonly ProgramChain Goup; // ?? maybe Group
|
|
||||||
|
|
||||||
public ProgramPlaybackMode PlaybackMode { get; private set; }
|
public ProgramPlaybackMode PlaybackMode { get; private set; }
|
||||||
public uint ProgramCount { get; private set; }
|
public uint ProgramCount { get; private set; }
|
||||||
@@ -42,7 +37,6 @@ namespace DvdLib.Ifo
|
|||||||
public byte[] Palette { get; private set; } // 16*4 entries
|
public byte[] Palette { get; private set; } // 16*4 entries
|
||||||
|
|
||||||
private ushort _commandTableOffset;
|
private ushort _commandTableOffset;
|
||||||
public readonly ProgramChainCommandTable CommandTable;
|
|
||||||
|
|
||||||
private ushort _programMapOffset;
|
private ushort _programMapOffset;
|
||||||
private ushort _cellPlaybackOffset;
|
private ushort _cellPlaybackOffset;
|
||||||
@@ -89,7 +83,7 @@ namespace DvdLib.Ifo
|
|||||||
br.BaseStream.Seek(startPos + _cellPositionOffset, SeekOrigin.Begin);
|
br.BaseStream.Seek(startPos + _cellPositionOffset, SeekOrigin.Begin);
|
||||||
for (int cellNum = 0; cellNum < _cellCount; cellNum++)
|
for (int cellNum = 0; cellNum < _cellCount; cellNum++)
|
||||||
{
|
{
|
||||||
Cell c = new Cell();
|
var c = new Cell();
|
||||||
c.ParsePosition(br);
|
c.ParsePosition(br);
|
||||||
Cells.Add(c);
|
Cells.Add(c);
|
||||||
}
|
}
|
||||||
@@ -101,12 +95,12 @@ namespace DvdLib.Ifo
|
|||||||
}
|
}
|
||||||
|
|
||||||
br.BaseStream.Seek(startPos + _programMapOffset, SeekOrigin.Begin);
|
br.BaseStream.Seek(startPos + _programMapOffset, SeekOrigin.Begin);
|
||||||
List<int> cellNumbers = new List<int>();
|
var cellNumbers = new List<int>();
|
||||||
for (int progNum = 0; progNum < _programCount; progNum++) cellNumbers.Add(br.ReadByte() - 1);
|
for (int progNum = 0; progNum < _programCount; progNum++) cellNumbers.Add(br.ReadByte() - 1);
|
||||||
|
|
||||||
for (int i = 0; i < cellNumbers.Count; i++)
|
for (int i = 0; i < cellNumbers.Count; i++)
|
||||||
{
|
{
|
||||||
int max = (i + 1 == cellNumbers.Count) ? _cellCount : cellNumbers[i+1];
|
int max = (i + 1 == cellNumbers.Count) ? _cellCount : cellNumbers[i + 1];
|
||||||
Programs.Add(new Program(Cells.Where((c, idx) => idx >= cellNumbers[i] && idx < max).ToList()));
|
Programs.Add(new Program(Cells.Where((c, idx) => idx >= cellNumbers[i] && idx < max).ToList()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace DvdLib.Ifo
|
namespace DvdLib.Ifo
|
||||||
@@ -53,7 +50,7 @@ namespace DvdLib.Ifo
|
|||||||
long curPos = br.BaseStream.Position;
|
long curPos = br.BaseStream.Position;
|
||||||
br.BaseStream.Seek(startByte, SeekOrigin.Begin);
|
br.BaseStream.Seek(startByte, SeekOrigin.Begin);
|
||||||
|
|
||||||
ProgramChain pgc = new ProgramChain(pgcNum);
|
var pgc = new ProgramChain(pgcNum);
|
||||||
pgc.ParseHeader(br);
|
pgc.ParseHeader(br);
|
||||||
ProgramChains.Add(pgc);
|
ProgramChains.Add(pgc);
|
||||||
if (entryPgc) EntryProgramChain = pgc;
|
if (entryPgc) EntryProgramChain = pgc;
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DvdLib.Ifo
|
namespace DvdLib.Ifo
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DvdLib.Ifo
|
|
||||||
{
|
|
||||||
public enum VideoCodec
|
|
||||||
{
|
|
||||||
MPEG1 = 0,
|
|
||||||
MPEG2 = 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum VideoFormat
|
|
||||||
{
|
|
||||||
NTSC = 0,
|
|
||||||
PAL = 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum AspectRatio
|
|
||||||
{
|
|
||||||
ar4to3 = 0,
|
|
||||||
ar16to9 = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum FilmMode
|
|
||||||
{
|
|
||||||
None = -1,
|
|
||||||
Camera = 0,
|
|
||||||
Film = 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
public class VideoAttributes
|
|
||||||
{
|
|
||||||
public readonly VideoCodec Codec;
|
|
||||||
public readonly VideoFormat Format;
|
|
||||||
public readonly AspectRatio Aspect;
|
|
||||||
public readonly bool AutomaticPanScan;
|
|
||||||
public readonly bool AutomaticLetterBox;
|
|
||||||
public readonly bool Line21CCField1;
|
|
||||||
public readonly bool Line21CCField2;
|
|
||||||
public readonly int Width;
|
|
||||||
public readonly int Height;
|
|
||||||
public readonly bool Letterboxed;
|
|
||||||
public readonly FilmMode FilmMode;
|
|
||||||
|
|
||||||
public VideoAttributes()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
using System.Resources;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Resources;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
// General Information about an assembly is controlled through the following
|
||||||
@@ -9,21 +8,14 @@ using System.Runtime.InteropServices;
|
|||||||
[assembly: AssemblyTitle("DvdLib")]
|
[assembly: AssemblyTitle("DvdLib")]
|
||||||
[assembly: AssemblyDescription("")]
|
[assembly: AssemblyDescription("")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCompany("")]
|
[assembly: AssemblyCompany("Jellyfin Project")]
|
||||||
[assembly: AssemblyProduct("DvdLib")]
|
[assembly: AssemblyProduct("Jellyfin Server")]
|
||||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: NeutralResourcesLanguage("en")]
|
[assembly: NeutralResourcesLanguage("en")]
|
||||||
|
|
||||||
// Version information for an assembly consists of the following four values:
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
//
|
// to COM components. If you need to access a type in this assembly from
|
||||||
// Major Version
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
// Minor Version
|
[assembly: ComVisible(false)]
|
||||||
// Build Number
|
|
||||||
// Revision
|
|
||||||
//
|
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
|
||||||
// by using the '*' as shown below:
|
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
|
||||||
[assembly: AssemblyVersion("1.0.1")]
|
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
using MediaBrowser.Controller.Dlna;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using MediaBrowser.Model.Services;
|
|
||||||
using MediaBrowser.Common.Extensions;
|
|
||||||
using System.Text;
|
|
||||||
using MediaBrowser.Controller.Net;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Emby.Dlna.Main;
|
using Emby.Dlna.Main;
|
||||||
|
using MediaBrowser.Common.Extensions;
|
||||||
|
using MediaBrowser.Controller.Dlna;
|
||||||
|
using MediaBrowser.Controller.Net;
|
||||||
|
using MediaBrowser.Model.Services;
|
||||||
|
|
||||||
namespace Emby.Dlna.Api
|
namespace Emby.Dlna.Api
|
||||||
{
|
{
|
||||||
@@ -115,29 +115,11 @@ namespace Emby.Dlna.Api
|
|||||||
public IRequest Request { get; set; }
|
public IRequest Request { get; set; }
|
||||||
private IHttpResultFactory _resultFactory;
|
private IHttpResultFactory _resultFactory;
|
||||||
|
|
||||||
private IContentDirectory ContentDirectory
|
private IContentDirectory ContentDirectory => DlnaEntryPoint.Current.ContentDirectory;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return DlnaEntryPoint.Current.ContentDirectory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IConnectionManager ConnectionManager
|
private IConnectionManager ConnectionManager => DlnaEntryPoint.Current.ConnectionManager;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return DlnaEntryPoint.Current.ConnectionManager;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IMediaReceiverRegistrar MediaReceiverRegistrar
|
private IMediaReceiverRegistrar MediaReceiverRegistrar => DlnaEntryPoint.Current.MediaReceiverRegistrar;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return DlnaEntryPoint.Current.MediaReceiverRegistrar;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public DlnaServerService(IDlnaManager dlnaManager, IHttpResultFactory httpResultFactory)
|
public DlnaServerService(IDlnaManager dlnaManager, IHttpResultFactory httpResultFactory)
|
||||||
{
|
{
|
||||||
@@ -154,7 +136,7 @@ namespace Emby.Dlna.Api
|
|||||||
{
|
{
|
||||||
var url = Request.AbsoluteUri;
|
var url = Request.AbsoluteUri;
|
||||||
var serverAddress = url.Substring(0, url.IndexOf("/dlna/", StringComparison.OrdinalIgnoreCase));
|
var serverAddress = url.Substring(0, url.IndexOf("/dlna/", StringComparison.OrdinalIgnoreCase));
|
||||||
var xml = _dlnaManager.GetServerDescriptionXml(Request.Headers.ToDictionary(), request.UuId, serverAddress);
|
var xml = _dlnaManager.GetServerDescriptionXml(Request.Headers, request.UuId, serverAddress);
|
||||||
|
|
||||||
var cacheLength = TimeSpan.FromDays(1);
|
var cacheLength = TimeSpan.FromDays(1);
|
||||||
var cacheKey = Request.RawUrl.GetMD5();
|
var cacheKey = Request.RawUrl.GetMD5();
|
||||||
@@ -165,21 +147,21 @@ namespace Emby.Dlna.Api
|
|||||||
|
|
||||||
public object Get(GetContentDirectory request)
|
public object Get(GetContentDirectory request)
|
||||||
{
|
{
|
||||||
var xml = ContentDirectory.GetServiceXml(Request.Headers.ToDictionary());
|
var xml = ContentDirectory.GetServiceXml();
|
||||||
|
|
||||||
return _resultFactory.GetResult(Request, xml, XMLContentType);
|
return _resultFactory.GetResult(Request, xml, XMLContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Get(GetMediaReceiverRegistrar request)
|
public object Get(GetMediaReceiverRegistrar request)
|
||||||
{
|
{
|
||||||
var xml = MediaReceiverRegistrar.GetServiceXml(Request.Headers.ToDictionary());
|
var xml = MediaReceiverRegistrar.GetServiceXml();
|
||||||
|
|
||||||
return _resultFactory.GetResult(Request, xml, XMLContentType);
|
return _resultFactory.GetResult(Request, xml, XMLContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Get(GetConnnectionManager request)
|
public object Get(GetConnnectionManager request)
|
||||||
{
|
{
|
||||||
var xml = ConnectionManager.GetServiceXml(Request.Headers.ToDictionary());
|
var xml = ConnectionManager.GetServiceXml();
|
||||||
|
|
||||||
return _resultFactory.GetResult(Request, xml, XMLContentType);
|
return _resultFactory.GetResult(Request, xml, XMLContentType);
|
||||||
}
|
}
|
||||||
@@ -211,7 +193,7 @@ namespace Emby.Dlna.Api
|
|||||||
|
|
||||||
return service.ProcessControlRequest(new ControlRequest
|
return service.ProcessControlRequest(new ControlRequest
|
||||||
{
|
{
|
||||||
Headers = Request.Headers.ToDictionary(),
|
Headers = Request.Headers,
|
||||||
InputXml = requestStream,
|
InputXml = requestStream,
|
||||||
TargetServerUuId = id,
|
TargetServerUuId = id,
|
||||||
RequestedUrl = Request.AbsoluteUri
|
RequestedUrl = Request.AbsoluteUri
|
||||||
@@ -227,7 +209,7 @@ namespace Emby.Dlna.Api
|
|||||||
// TODO: Work out what this is doing.
|
// TODO: Work out what this is doing.
|
||||||
if (string.Equals(first, "mediabrowser", StringComparison.OrdinalIgnoreCase) ||
|
if (string.Equals(first, "mediabrowser", StringComparison.OrdinalIgnoreCase) ||
|
||||||
string.Equals(first, "emby", StringComparison.OrdinalIgnoreCase) ||
|
string.Equals(first, "emby", StringComparison.OrdinalIgnoreCase) ||
|
||||||
string.Equals(first, "jellyfin", StringComparison.OrdinalIgnoreCase ))
|
string.Equals(first, "jellyfin", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
@@ -254,12 +236,14 @@ namespace Emby.Dlna.Api
|
|||||||
|
|
||||||
public object Get(GetIcon request)
|
public object Get(GetIcon request)
|
||||||
{
|
{
|
||||||
var contentType = "image/" + Path.GetExtension(request.Filename).TrimStart('.').ToLower();
|
var contentType = "image/" + Path.GetExtension(request.Filename)
|
||||||
|
.TrimStart('.')
|
||||||
|
.ToLowerInvariant();
|
||||||
|
|
||||||
var cacheLength = TimeSpan.FromDays(365);
|
var cacheLength = TimeSpan.FromDays(365);
|
||||||
var cacheKey = Request.RawUrl.GetMD5();
|
var cacheKey = Request.RawUrl.GetMD5();
|
||||||
|
|
||||||
return _resultFactory.GetStaticResult(Request, cacheKey, null, cacheLength, contentType, () => Task.FromResult<Stream>(_dlnaManager.GetIcon(request.Filename).Stream));
|
return _resultFactory.GetStaticResult(Request, cacheKey, null, cacheLength, contentType, () => Task.FromResult(_dlnaManager.GetIcon(request.Filename).Stream));
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Subscribe(ProcessContentDirectoryEventRequest request)
|
public object Subscribe(ProcessContentDirectoryEventRequest request)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Net;
|
using MediaBrowser.Controller.Net;
|
||||||
using MediaBrowser.Model.Dlna;
|
using MediaBrowser.Model.Dlna;
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
|
|
||||||
namespace Emby.Dlna.Common
|
namespace Emby.Dlna.Common
|
||||||
{
|
{
|
||||||
public class Argument
|
public class Argument
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
public string Direction { get; set; }
|
public string Direction { get; set; }
|
||||||
|
|
||||||
public string RelatedStateVariable { get; set; }
|
public string RelatedStateVariable { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
|
|
||||||
namespace Emby.Dlna.Common
|
namespace Emby.Dlna.Common
|
||||||
{
|
{
|
||||||
public class DeviceIcon
|
public class DeviceIcon
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
|
|
||||||
namespace Emby.Dlna.Common
|
namespace Emby.Dlna.Common
|
||||||
{
|
{
|
||||||
public class DeviceService
|
public class DeviceService
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Emby.Dlna.Common
|
namespace Emby.Dlna.Common
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Emby.Dlna.Common
|
namespace Emby.Dlna.Common
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
|
|
||||||
namespace Emby.Dlna.Configuration
|
namespace Emby.Dlna.Configuration
|
||||||
{
|
{
|
||||||
public class DlnaOptions
|
public class DlnaOptions
|
||||||
@@ -7,6 +7,7 @@ namespace Emby.Dlna.Configuration
|
|||||||
public bool EnableServer { get; set; }
|
public bool EnableServer { get; set; }
|
||||||
public bool EnableDebugLog { get; set; }
|
public bool EnableDebugLog { get; set; }
|
||||||
public bool BlastAliveMessages { get; set; }
|
public bool BlastAliveMessages { get; set; }
|
||||||
|
public bool SendOnlyMatchedHost { get; set; }
|
||||||
public int ClientDiscoveryIntervalSeconds { get; set; }
|
public int ClientDiscoveryIntervalSeconds { get; set; }
|
||||||
public int BlastAliveMessageIntervalSeconds { get; set; }
|
public int BlastAliveMessageIntervalSeconds { get; set; }
|
||||||
public string DefaultUserId { get; set; }
|
public string DefaultUserId { get; set; }
|
||||||
@@ -16,6 +17,7 @@ namespace Emby.Dlna.Configuration
|
|||||||
EnablePlayTo = true;
|
EnablePlayTo = true;
|
||||||
EnableServer = true;
|
EnableServer = true;
|
||||||
BlastAliveMessages = true;
|
BlastAliveMessages = true;
|
||||||
|
SendOnlyMatchedHost = true;
|
||||||
ClientDiscoveryIntervalSeconds = 60;
|
ClientDiscoveryIntervalSeconds = 60;
|
||||||
BlastAliveMessageIntervalSeconds = 1800;
|
BlastAliveMessageIntervalSeconds = 1800;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using MediaBrowser.Common.Configuration;
|
|
||||||
using Emby.Dlna.Configuration;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Emby.Dlna.Configuration;
|
||||||
|
using MediaBrowser.Common.Configuration;
|
||||||
|
|
||||||
namespace Emby.Dlna
|
namespace Emby.Dlna
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
using MediaBrowser.Common.Net;
|
using Emby.Dlna.Service;
|
||||||
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using Emby.Dlna.Service;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using MediaBrowser.Model.Xml;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Emby.Dlna.ConnectionManager
|
namespace Emby.Dlna.ConnectionManager
|
||||||
@@ -13,18 +11,16 @@ namespace Emby.Dlna.ConnectionManager
|
|||||||
private readonly IDlnaManager _dlna;
|
private readonly IDlnaManager _dlna;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
protected readonly IXmlReaderSettingsFactory XmlReaderSettingsFactory;
|
|
||||||
|
|
||||||
public ConnectionManager(IDlnaManager dlna, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient, IXmlReaderSettingsFactory xmlReaderSettingsFactory)
|
public ConnectionManager(IDlnaManager dlna, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient)
|
||||||
: base(logger, httpClient)
|
: base(logger, httpClient)
|
||||||
{
|
{
|
||||||
_dlna = dlna;
|
_dlna = dlna;
|
||||||
_config = config;
|
_config = config;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
XmlReaderSettingsFactory = xmlReaderSettingsFactory;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetServiceXml(IDictionary<string, string> headers)
|
public string GetServiceXml()
|
||||||
{
|
{
|
||||||
return new ConnectionManagerXmlBuilder().GetXml();
|
return new ConnectionManagerXmlBuilder().GetXml();
|
||||||
}
|
}
|
||||||
@@ -34,7 +30,7 @@ namespace Emby.Dlna.ConnectionManager
|
|||||||
var profile = _dlna.GetProfile(request.Headers) ??
|
var profile = _dlna.GetProfile(request.Headers) ??
|
||||||
_dlna.GetDefaultProfile();
|
_dlna.GetDefaultProfile();
|
||||||
|
|
||||||
return new ControlHandler(_config, _logger, XmlReaderSettingsFactory, profile).ProcessControlRequest(request);
|
return new ControlHandler(_config, _logger, profile).ProcessControlRequest(request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using Emby.Dlna.Common;
|
|
||||||
using Emby.Dlna.Service;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Emby.Dlna.Common;
|
||||||
|
using Emby.Dlna.Service;
|
||||||
|
|
||||||
namespace Emby.Dlna.ConnectionManager
|
namespace Emby.Dlna.ConnectionManager
|
||||||
{
|
{
|
||||||
@@ -11,7 +11,7 @@ namespace Emby.Dlna.ConnectionManager
|
|||||||
return new ServiceXmlBuilder().GetXml(new ServiceActionListBuilder().GetActions(), GetStateVariables());
|
return new ServiceXmlBuilder().GetXml(new ServiceActionListBuilder().GetActions(), GetStateVariables());
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<StateVariable> GetStateVariables()
|
private static IEnumerable<StateVariable> GetStateVariables()
|
||||||
{
|
{
|
||||||
var list = new List<StateVariable>();
|
var list = new List<StateVariable>();
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
using MediaBrowser.Common.Extensions;
|
|
||||||
using MediaBrowser.Controller.Configuration;
|
|
||||||
using Emby.Dlna.Server;
|
|
||||||
using Emby.Dlna.Service;
|
|
||||||
using MediaBrowser.Model.Dlna;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using MediaBrowser.Model.Xml;
|
using Emby.Dlna.Service;
|
||||||
|
using MediaBrowser.Common.Extensions;
|
||||||
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
using MediaBrowser.Model.Dlna;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Emby.Dlna.ConnectionManager
|
namespace Emby.Dlna.ConnectionManager
|
||||||
{
|
{
|
||||||
@@ -33,7 +31,8 @@ namespace Emby.Dlna.ConnectionManager
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public ControlHandler(IServerConfigurationManager config, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory, DeviceProfile profile) : base(config, logger, xmlReaderSettingsFactory)
|
public ControlHandler(IServerConfigurationManager config, ILogger logger, DeviceProfile profile)
|
||||||
|
: base(config, logger)
|
||||||
{
|
{
|
||||||
_profile = profile;
|
_profile = profile;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using Emby.Dlna.Common;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Emby.Dlna.Common;
|
||||||
|
|
||||||
namespace Emby.Dlna.ConnectionManager
|
namespace Emby.Dlna.ConnectionManager
|
||||||
{
|
{
|
||||||
@@ -19,7 +19,7 @@ namespace Emby.Dlna.ConnectionManager
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServiceAction PrepareForConnection()
|
private static ServiceAction PrepareForConnection()
|
||||||
{
|
{
|
||||||
var action = new ServiceAction
|
var action = new ServiceAction
|
||||||
{
|
{
|
||||||
@@ -78,7 +78,7 @@ namespace Emby.Dlna.ConnectionManager
|
|||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServiceAction GetCurrentConnectionInfo()
|
private static ServiceAction GetCurrentConnectionInfo()
|
||||||
{
|
{
|
||||||
var action = new ServiceAction
|
var action = new ServiceAction
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
using MediaBrowser.Common.Net;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Emby.Dlna.Service;
|
||||||
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using Emby.Dlna.Service;
|
|
||||||
using MediaBrowser.Model.Dlna;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Controller.TV;
|
using MediaBrowser.Controller.TV;
|
||||||
|
using MediaBrowser.Model.Dlna;
|
||||||
using MediaBrowser.Model.Globalization;
|
using MediaBrowser.Model.Globalization;
|
||||||
using MediaBrowser.Model.Xml;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Emby.Dlna.ContentDirectory
|
namespace Emby.Dlna.ContentDirectory
|
||||||
{
|
{
|
||||||
@@ -28,7 +27,6 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
private readonly IMediaSourceManager _mediaSourceManager;
|
private readonly IMediaSourceManager _mediaSourceManager;
|
||||||
private readonly IUserViewManager _userViewManager;
|
private readonly IUserViewManager _userViewManager;
|
||||||
private readonly IMediaEncoder _mediaEncoder;
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
protected readonly IXmlReaderSettingsFactory XmlReaderSettingsFactory;
|
|
||||||
private readonly ITVSeriesManager _tvSeriesManager;
|
private readonly ITVSeriesManager _tvSeriesManager;
|
||||||
|
|
||||||
public ContentDirectory(IDlnaManager dlna,
|
public ContentDirectory(IDlnaManager dlna,
|
||||||
@@ -38,7 +36,12 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
IServerConfigurationManager config,
|
IServerConfigurationManager config,
|
||||||
IUserManager userManager,
|
IUserManager userManager,
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
IHttpClient httpClient, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, IMediaEncoder mediaEncoder, IXmlReaderSettingsFactory xmlReaderSettingsFactory, ITVSeriesManager tvSeriesManager)
|
IHttpClient httpClient,
|
||||||
|
ILocalizationManager localization,
|
||||||
|
IMediaSourceManager mediaSourceManager,
|
||||||
|
IUserViewManager userViewManager,
|
||||||
|
IMediaEncoder mediaEncoder,
|
||||||
|
ITVSeriesManager tvSeriesManager)
|
||||||
: base(logger, httpClient)
|
: base(logger, httpClient)
|
||||||
{
|
{
|
||||||
_dlna = dlna;
|
_dlna = dlna;
|
||||||
@@ -51,7 +54,6 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
_mediaSourceManager = mediaSourceManager;
|
_mediaSourceManager = mediaSourceManager;
|
||||||
_userViewManager = userViewManager;
|
_userViewManager = userViewManager;
|
||||||
_mediaEncoder = mediaEncoder;
|
_mediaEncoder = mediaEncoder;
|
||||||
XmlReaderSettingsFactory = xmlReaderSettingsFactory;
|
|
||||||
_tvSeriesManager = tvSeriesManager;
|
_tvSeriesManager = tvSeriesManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +67,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetServiceXml(IDictionary<string, string> headers)
|
public string GetServiceXml()
|
||||||
{
|
{
|
||||||
return new ContentDirectoryXmlBuilder().GetXml();
|
return new ContentDirectoryXmlBuilder().GetXml();
|
||||||
}
|
}
|
||||||
@@ -76,7 +78,6 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
_dlna.GetDefaultProfile();
|
_dlna.GetDefaultProfile();
|
||||||
|
|
||||||
var serverAddress = request.RequestedUrl.Substring(0, request.RequestedUrl.IndexOf("/dlna", StringComparison.OrdinalIgnoreCase));
|
var serverAddress = request.RequestedUrl.Substring(0, request.RequestedUrl.IndexOf("/dlna", StringComparison.OrdinalIgnoreCase));
|
||||||
string accessToken = null;
|
|
||||||
|
|
||||||
var user = GetUser(profile);
|
var user = GetUser(profile);
|
||||||
|
|
||||||
@@ -85,7 +86,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
_libraryManager,
|
_libraryManager,
|
||||||
profile,
|
profile,
|
||||||
serverAddress,
|
serverAddress,
|
||||||
accessToken,
|
null,
|
||||||
_imageProcessor,
|
_imageProcessor,
|
||||||
_userDataManager,
|
_userDataManager,
|
||||||
user,
|
user,
|
||||||
@@ -95,7 +96,6 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
_mediaSourceManager,
|
_mediaSourceManager,
|
||||||
_userViewManager,
|
_userViewManager,
|
||||||
_mediaEncoder,
|
_mediaEncoder,
|
||||||
XmlReaderSettingsFactory,
|
|
||||||
_tvSeriesManager)
|
_tvSeriesManager)
|
||||||
.ProcessControlRequest(request);
|
.ProcessControlRequest(request);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using Emby.Dlna.Common;
|
|
||||||
using Emby.Dlna.Service;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Emby.Dlna.Common;
|
||||||
|
using Emby.Dlna.Service;
|
||||||
|
|
||||||
namespace Emby.Dlna.ContentDirectory
|
namespace Emby.Dlna.ContentDirectory
|
||||||
{
|
{
|
||||||
@@ -12,7 +12,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
GetStateVariables());
|
GetStateVariables());
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<StateVariable> GetStateVariables()
|
private static IEnumerable<StateVariable> GetStateVariables()
|
||||||
{
|
{
|
||||||
var list = new List<StateVariable>();
|
var list = new List<StateVariable>();
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,3 @@
|
|||||||
using MediaBrowser.Common.Extensions;
|
|
||||||
using MediaBrowser.Controller.Channels;
|
|
||||||
using MediaBrowser.Controller.Configuration;
|
|
||||||
using MediaBrowser.Controller.Drawing;
|
|
||||||
using MediaBrowser.Controller.Entities;
|
|
||||||
using MediaBrowser.Controller.Entities.Movies;
|
|
||||||
using MediaBrowser.Controller.Entities.TV;
|
|
||||||
using MediaBrowser.Controller.Library;
|
|
||||||
using Emby.Dlna.Didl;
|
|
||||||
using Emby.Dlna.Server;
|
|
||||||
using Emby.Dlna.Service;
|
|
||||||
using MediaBrowser.Model.Configuration;
|
|
||||||
using MediaBrowser.Model.Dlna;
|
|
||||||
using MediaBrowser.Model.Entities;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using MediaBrowser.Model.Querying;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
@@ -21,17 +5,27 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
using Emby.Dlna.Didl;
|
||||||
|
using Emby.Dlna.Service;
|
||||||
|
using MediaBrowser.Common.Extensions;
|
||||||
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
|
using MediaBrowser.Controller.Entities.Movies;
|
||||||
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Controller.LiveTv;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Controller.Playlists;
|
using MediaBrowser.Controller.Playlists;
|
||||||
using MediaBrowser.Controller.TV;
|
using MediaBrowser.Controller.TV;
|
||||||
|
using MediaBrowser.Model.Dlna;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Globalization;
|
using MediaBrowser.Model.Globalization;
|
||||||
using MediaBrowser.Model.Xml;
|
using MediaBrowser.Model.Querying;
|
||||||
using MediaBrowser.Model.Extensions;
|
using Microsoft.Extensions.Logging;
|
||||||
using MediaBrowser.Controller.LiveTv;
|
|
||||||
|
|
||||||
namespace Emby.Dlna.ContentDirectory
|
namespace Emby.Dlna.ContentDirectory
|
||||||
{
|
{
|
||||||
@@ -56,8 +50,22 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
|
|
||||||
private readonly DeviceProfile _profile;
|
private readonly DeviceProfile _profile;
|
||||||
|
|
||||||
public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, IMediaEncoder mediaEncoder, IXmlReaderSettingsFactory xmlReaderSettingsFactory, ITVSeriesManager tvSeriesManager)
|
public ControlHandler(
|
||||||
: base(config, logger, xmlReaderSettingsFactory)
|
ILogger logger,
|
||||||
|
ILibraryManager libraryManager,
|
||||||
|
DeviceProfile profile,
|
||||||
|
string serverAddress,
|
||||||
|
string accessToken,
|
||||||
|
IImageProcessor imageProcessor,
|
||||||
|
IUserDataManager userDataManager,
|
||||||
|
User user, int systemUpdateId,
|
||||||
|
IServerConfigurationManager config,
|
||||||
|
ILocalizationManager localization,
|
||||||
|
IMediaSourceManager mediaSourceManager,
|
||||||
|
IUserViewManager userViewManager,
|
||||||
|
IMediaEncoder mediaEncoder,
|
||||||
|
ITVSeriesManager tvSeriesManager)
|
||||||
|
: base(config, logger)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_userDataManager = userDataManager;
|
_userDataManager = userDataManager;
|
||||||
@@ -68,7 +76,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
_profile = profile;
|
_profile = profile;
|
||||||
_config = config;
|
_config = config;
|
||||||
|
|
||||||
_didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, _logger, libraryManager, mediaEncoder);
|
_didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, _logger, mediaEncoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams)
|
protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams)
|
||||||
@@ -197,9 +205,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
|
|
||||||
public string GetValueOrDefault(IDictionary<string, string> sparams, string key, string defaultValue)
|
public string GetValueOrDefault(IDictionary<string, string> sparams, string key, string defaultValue)
|
||||||
{
|
{
|
||||||
string val;
|
if (sparams.TryGetValue(key, out string val))
|
||||||
|
|
||||||
if (sparams.TryGetValue(key, out val))
|
|
||||||
{
|
{
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
@@ -221,14 +227,12 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
int? requestedCount = null;
|
int? requestedCount = null;
|
||||||
int? start = 0;
|
int? start = 0;
|
||||||
|
|
||||||
int requestedVal;
|
if (sparams.ContainsKey("RequestedCount") && int.TryParse(sparams["RequestedCount"], out var requestedVal) && requestedVal > 0)
|
||||||
if (sparams.ContainsKey("RequestedCount") && int.TryParse(sparams["RequestedCount"], out requestedVal) && requestedVal > 0)
|
|
||||||
{
|
{
|
||||||
requestedCount = requestedVal;
|
requestedCount = requestedVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
int startVal;
|
if (sparams.ContainsKey("StartingIndex") && int.TryParse(sparams["StartingIndex"], out var startVal) && startVal > 0)
|
||||||
if (sparams.ContainsKey("StartingIndex") && int.TryParse(sparams["StartingIndex"], out startVal) && startVal > 0)
|
|
||||||
{
|
{
|
||||||
start = startVal;
|
start = startVal;
|
||||||
}
|
}
|
||||||
@@ -247,7 +251,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
|
|
||||||
var dlnaOptions = _config.GetDlnaConfiguration();
|
var dlnaOptions = _config.GetDlnaConfiguration();
|
||||||
|
|
||||||
using (XmlWriter writer = XmlWriter.Create(builder, settings))
|
using (var writer = XmlWriter.Create(builder, settings))
|
||||||
{
|
{
|
||||||
//writer.WriteStartDocument();
|
//writer.WriteStartDocument();
|
||||||
|
|
||||||
@@ -269,7 +273,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
|
|
||||||
if (item.IsDisplayedAsFolder || serverItem.StubType.HasValue)
|
if (item.IsDisplayedAsFolder || serverItem.StubType.HasValue)
|
||||||
{
|
{
|
||||||
var childrenResult = (GetUserItems(item, serverItem.StubType, user, sortCriteria, start, requestedCount));
|
var childrenResult = GetUserItems(item, serverItem.StubType, user, sortCriteria, start, requestedCount);
|
||||||
|
|
||||||
_didlBuilder.WriteFolderElement(writer, item, serverItem.StubType, null, childrenResult.TotalRecordCount, filter, id);
|
_didlBuilder.WriteFolderElement(writer, item, serverItem.StubType, null, childrenResult.TotalRecordCount, filter, id);
|
||||||
}
|
}
|
||||||
@@ -282,7 +286,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var childrenResult = (GetUserItems(item, serverItem.StubType, user, sortCriteria, start, requestedCount));
|
var childrenResult = GetUserItems(item, serverItem.StubType, user, sortCriteria, start, requestedCount);
|
||||||
totalCount = childrenResult.TotalRecordCount;
|
totalCount = childrenResult.TotalRecordCount;
|
||||||
|
|
||||||
provided = childrenResult.Items.Length;
|
provided = childrenResult.Items.Length;
|
||||||
@@ -311,7 +315,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
|
|
||||||
var resXML = builder.ToString();
|
var resXML = builder.ToString();
|
||||||
|
|
||||||
return new []
|
return new[]
|
||||||
{
|
{
|
||||||
new KeyValuePair<string,string>("Result", resXML),
|
new KeyValuePair<string,string>("Result", resXML),
|
||||||
new KeyValuePair<string,string>("NumberReturned", provided.ToString(_usCulture)),
|
new KeyValuePair<string,string>("NumberReturned", provided.ToString(_usCulture)),
|
||||||
@@ -339,14 +343,12 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
int? requestedCount = null;
|
int? requestedCount = null;
|
||||||
int? start = 0;
|
int? start = 0;
|
||||||
|
|
||||||
int requestedVal;
|
if (sparams.ContainsKey("RequestedCount") && int.TryParse(sparams["RequestedCount"], out var requestedVal) && requestedVal > 0)
|
||||||
if (sparams.ContainsKey("RequestedCount") && int.TryParse(sparams["RequestedCount"], out requestedVal) && requestedVal > 0)
|
|
||||||
{
|
{
|
||||||
requestedCount = requestedVal;
|
requestedCount = requestedVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
int startVal;
|
if (sparams.ContainsKey("StartingIndex") && int.TryParse(sparams["StartingIndex"], out var startVal) && startVal > 0)
|
||||||
if (sparams.ContainsKey("StartingIndex") && int.TryParse(sparams["StartingIndex"], out startVal) && startVal > 0)
|
|
||||||
{
|
{
|
||||||
start = startVal;
|
start = startVal;
|
||||||
}
|
}
|
||||||
@@ -363,7 +365,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
int totalCount = 0;
|
int totalCount = 0;
|
||||||
int provided = 0;
|
int provided = 0;
|
||||||
|
|
||||||
using (XmlWriter writer = XmlWriter.Create(builder, settings))
|
using (var writer = XmlWriter.Create(builder, settings))
|
||||||
{
|
{
|
||||||
//writer.WriteStartDocument();
|
//writer.WriteStartDocument();
|
||||||
|
|
||||||
@@ -465,7 +467,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
User = user,
|
User = user,
|
||||||
Recursive = true,
|
Recursive = true,
|
||||||
IsMissing = false,
|
IsMissing = false,
|
||||||
ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name },
|
ExcludeItemTypes = new[] { typeof(Book).Name },
|
||||||
IsFolder = isFolder,
|
IsFolder = isFolder,
|
||||||
MediaTypes = mediaTypes.ToArray(),
|
MediaTypes = mediaTypes.ToArray(),
|
||||||
DtoOptions = GetDtoOptions()
|
DtoOptions = GetDtoOptions()
|
||||||
@@ -494,27 +496,26 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
return GetGenreItems(item, Guid.Empty, user, sort, startIndex, limit);
|
return GetGenreItems(item, Guid.Empty, user, sort, startIndex, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stubType.HasValue || stubType.Value != StubType.Folder)
|
if ((!stubType.HasValue || stubType.Value != StubType.Folder)
|
||||||
|
&& item is IHasCollectionType collectionFolder)
|
||||||
{
|
{
|
||||||
var collectionFolder = item as IHasCollectionType;
|
if (string.Equals(CollectionType.Music, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
|
||||||
if (collectionFolder != null && string.Equals(CollectionType.Music, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
return GetMusicFolders(item, user, stubType, sort, startIndex, limit);
|
return GetMusicFolders(item, user, stubType, sort, startIndex, limit);
|
||||||
}
|
}
|
||||||
if (collectionFolder != null && string.Equals(CollectionType.Movies, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
|
else if (string.Equals(CollectionType.Movies, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return GetMovieFolders(item, user, stubType, sort, startIndex, limit);
|
return GetMovieFolders(item, user, stubType, sort, startIndex, limit);
|
||||||
}
|
}
|
||||||
if (collectionFolder != null && string.Equals(CollectionType.TvShows, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
|
else if (string.Equals(CollectionType.TvShows, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return GetTvFolders(item, user, stubType, sort, startIndex, limit);
|
return GetTvFolders(item, user, stubType, sort, startIndex, limit);
|
||||||
}
|
}
|
||||||
|
else if (string.Equals(CollectionType.Folders, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
|
||||||
if (collectionFolder != null && string.Equals(CollectionType.Folders, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
return GetFolders(item, user, stubType, sort, startIndex, limit);
|
return GetFolders(item, user, stubType, sort, startIndex, limit);
|
||||||
}
|
}
|
||||||
if (collectionFolder != null && string.Equals(CollectionType.LiveTv, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
|
else if (string.Equals(CollectionType.LiveTv, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return GetLiveTvChannels(item, user, stubType, sort, startIndex, limit);
|
return GetLiveTvChannels(item, user, stubType, sort, startIndex, limit);
|
||||||
}
|
}
|
||||||
@@ -535,7 +536,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
Limit = limit,
|
Limit = limit,
|
||||||
StartIndex = startIndex,
|
StartIndex = startIndex,
|
||||||
IsVirtualItem = false,
|
IsVirtualItem = false,
|
||||||
ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name },
|
ExcludeItemTypes = new[] { typeof(Book).Name },
|
||||||
IsPlaceHolder = false,
|
IsPlaceHolder = false,
|
||||||
DtoOptions = GetDtoOptions()
|
DtoOptions = GetDtoOptions()
|
||||||
};
|
};
|
||||||
@@ -1144,7 +1145,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
StartIndex = query.StartIndex,
|
StartIndex = query.StartIndex,
|
||||||
UserId = query.User.Id
|
UserId = query.User.Id
|
||||||
|
|
||||||
}, new [] { parent }, query.DtoOptions);
|
}, new[] { parent }, query.DtoOptions);
|
||||||
|
|
||||||
return ToResult(result);
|
return ToResult(result);
|
||||||
}
|
}
|
||||||
@@ -1298,7 +1299,6 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
|
|
||||||
private ServerItem ParseItemId(string id, User user)
|
private ServerItem ParseItemId(string id, User user)
|
||||||
{
|
{
|
||||||
Guid itemId;
|
|
||||||
StubType? stubType = null;
|
StubType? stubType = null;
|
||||||
|
|
||||||
// After using PlayTo, MediaMonkey sends a request to the server trying to get item info
|
// After using PlayTo, MediaMonkey sends a request to the server trying to get item info
|
||||||
@@ -1324,7 +1324,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Guid.TryParse(id, out itemId))
|
if (Guid.TryParse(id, out var itemId))
|
||||||
{
|
{
|
||||||
var item = _libraryManager.GetItemById(itemId);
|
var item = _libraryManager.GetItemById(itemId);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using Emby.Dlna.Common;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Emby.Dlna.Common;
|
||||||
|
|
||||||
namespace Emby.Dlna.ContentDirectory
|
namespace Emby.Dlna.ContentDirectory
|
||||||
{
|
{
|
||||||
@@ -7,7 +7,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
{
|
{
|
||||||
public IEnumerable<ServiceAction> GetActions()
|
public IEnumerable<ServiceAction> GetActions()
|
||||||
{
|
{
|
||||||
return new []
|
return new[]
|
||||||
{
|
{
|
||||||
GetSearchCapabilitiesAction(),
|
GetSearchCapabilitiesAction(),
|
||||||
GetSortCapabilitiesAction(),
|
GetSortCapabilitiesAction(),
|
||||||
@@ -20,7 +20,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServiceAction GetGetSystemUpdateIDAction()
|
private static ServiceAction GetGetSystemUpdateIDAction()
|
||||||
{
|
{
|
||||||
var action = new ServiceAction
|
var action = new ServiceAction
|
||||||
{
|
{
|
||||||
@@ -37,7 +37,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServiceAction GetSearchCapabilitiesAction()
|
private static ServiceAction GetSearchCapabilitiesAction()
|
||||||
{
|
{
|
||||||
var action = new ServiceAction
|
var action = new ServiceAction
|
||||||
{
|
{
|
||||||
@@ -54,7 +54,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServiceAction GetSortCapabilitiesAction()
|
private static ServiceAction GetSortCapabilitiesAction()
|
||||||
{
|
{
|
||||||
var action = new ServiceAction
|
var action = new ServiceAction
|
||||||
{
|
{
|
||||||
@@ -71,7 +71,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServiceAction GetX_GetFeatureListAction()
|
private static ServiceAction GetX_GetFeatureListAction()
|
||||||
{
|
{
|
||||||
var action = new ServiceAction
|
var action = new ServiceAction
|
||||||
{
|
{
|
||||||
@@ -88,7 +88,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServiceAction GetSearchAction()
|
private static ServiceAction GetSearchAction()
|
||||||
{
|
{
|
||||||
var action = new ServiceAction
|
var action = new ServiceAction
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Emby.Dlna
|
namespace Emby.Dlna
|
||||||
{
|
{
|
||||||
public class ControlRequest
|
public class ControlRequest
|
||||||
{
|
{
|
||||||
public IDictionary<string, string> Headers { get; set; }
|
public IHeaderDictionary Headers { get; set; }
|
||||||
|
|
||||||
public Stream InputXml { get; set; }
|
public Stream InputXml { get; set; }
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ namespace Emby.Dlna
|
|||||||
|
|
||||||
public ControlRequest()
|
public ControlRequest()
|
||||||
{
|
{
|
||||||
Headers = new Dictionary<string, string>();
|
Headers = new HeaderDictionary();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Emby.Dlna
|
namespace Emby.Dlna
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
using MediaBrowser.Model.Extensions;
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Xml;
|
||||||
|
using Emby.Dlna.Configuration;
|
||||||
|
using Emby.Dlna.ContentDirectory;
|
||||||
using MediaBrowser.Controller.Channels;
|
using MediaBrowser.Controller.Channels;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
@@ -6,23 +13,15 @@ using MediaBrowser.Controller.Entities.Audio;
|
|||||||
using MediaBrowser.Controller.Entities.Movies;
|
using MediaBrowser.Controller.Entities.Movies;
|
||||||
using MediaBrowser.Controller.Entities.TV;
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Controller.Playlists;
|
using MediaBrowser.Controller.Playlists;
|
||||||
using Emby.Dlna.ContentDirectory;
|
|
||||||
using MediaBrowser.Model.Dlna;
|
using MediaBrowser.Model.Dlna;
|
||||||
using MediaBrowser.Model.Drawing;
|
using MediaBrowser.Model.Drawing;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using Microsoft.Extensions.Logging;
|
using MediaBrowser.Model.Extensions;
|
||||||
using MediaBrowser.Model.Net;
|
|
||||||
using System;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Xml;
|
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
|
||||||
using Emby.Dlna.Configuration;
|
|
||||||
using MediaBrowser.Model.Globalization;
|
using MediaBrowser.Model.Globalization;
|
||||||
|
using MediaBrowser.Model.Net;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Emby.Dlna.Didl
|
namespace Emby.Dlna.Didl
|
||||||
{
|
{
|
||||||
@@ -44,22 +43,30 @@ namespace Emby.Dlna.Didl
|
|||||||
private readonly ILocalizationManager _localization;
|
private readonly ILocalizationManager _localization;
|
||||||
private readonly IMediaSourceManager _mediaSourceManager;
|
private readonly IMediaSourceManager _mediaSourceManager;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly ILibraryManager _libraryManager;
|
|
||||||
private readonly IMediaEncoder _mediaEncoder;
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
|
|
||||||
public DidlBuilder(DeviceProfile profile, User user, IImageProcessor imageProcessor, string serverAddress, string accessToken, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, ILogger logger, ILibraryManager libraryManager, IMediaEncoder mediaEncoder)
|
public DidlBuilder(
|
||||||
|
DeviceProfile profile,
|
||||||
|
User user,
|
||||||
|
IImageProcessor imageProcessor,
|
||||||
|
string serverAddress,
|
||||||
|
string accessToken,
|
||||||
|
IUserDataManager userDataManager,
|
||||||
|
ILocalizationManager localization,
|
||||||
|
IMediaSourceManager mediaSourceManager,
|
||||||
|
ILogger logger,
|
||||||
|
IMediaEncoder mediaEncoder)
|
||||||
{
|
{
|
||||||
_profile = profile;
|
_profile = profile;
|
||||||
|
_user = user;
|
||||||
_imageProcessor = imageProcessor;
|
_imageProcessor = imageProcessor;
|
||||||
_serverAddress = serverAddress;
|
_serverAddress = serverAddress;
|
||||||
|
_accessToken = accessToken;
|
||||||
_userDataManager = userDataManager;
|
_userDataManager = userDataManager;
|
||||||
_localization = localization;
|
_localization = localization;
|
||||||
_mediaSourceManager = mediaSourceManager;
|
_mediaSourceManager = mediaSourceManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_libraryManager = libraryManager;
|
|
||||||
_mediaEncoder = mediaEncoder;
|
_mediaEncoder = mediaEncoder;
|
||||||
_accessToken = accessToken;
|
|
||||||
_user = user;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string NormalizeDlnaMediaUrl(string url)
|
public static string NormalizeDlnaMediaUrl(string url)
|
||||||
@@ -79,7 +86,7 @@ namespace Emby.Dlna.Didl
|
|||||||
|
|
||||||
using (StringWriter builder = new StringWriterWithEncoding(Encoding.UTF8))
|
using (StringWriter builder = new StringWriterWithEncoding(Encoding.UTF8))
|
||||||
{
|
{
|
||||||
using (XmlWriter writer = XmlWriter.Create(builder, settings))
|
using (var writer = XmlWriter.Create(builder, settings))
|
||||||
{
|
{
|
||||||
//writer.WriteStartDocument();
|
//writer.WriteStartDocument();
|
||||||
|
|
||||||
@@ -118,7 +125,8 @@ namespace Emby.Dlna.Didl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WriteItemElement(DlnaOptions options,
|
public void WriteItemElement(
|
||||||
|
DlnaOptions options,
|
||||||
XmlWriter writer,
|
XmlWriter writer,
|
||||||
BaseItem item,
|
BaseItem item,
|
||||||
User user,
|
User user,
|
||||||
@@ -233,12 +241,15 @@ namespace Emby.Dlna.Didl
|
|||||||
AddVideoResource(writer, video, deviceId, filter, contentFeature, streamInfo);
|
AddVideoResource(writer, video, deviceId, filter, contentFeature, streamInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
var subtitleProfiles = streamInfo.GetSubtitleProfiles(_mediaEncoder, false, _serverAddress, _accessToken)
|
var subtitleProfiles = streamInfo.GetSubtitleProfiles(_mediaEncoder, false, _serverAddress, _accessToken);
|
||||||
.Where(subtitle => subtitle.DeliveryMethod == SubtitleDeliveryMethod.External)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
foreach (var subtitle in subtitleProfiles)
|
foreach (var subtitle in subtitleProfiles)
|
||||||
{
|
{
|
||||||
|
if (subtitle.DeliveryMethod != SubtitleDeliveryMethod.External)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
var subtitleAdded = AddSubtitleElement(writer, subtitle);
|
var subtitleAdded = AddSubtitleElement(writer, subtitle);
|
||||||
|
|
||||||
if (subtitleAdded && _profile.EnableSingleSubtitleLimit)
|
if (subtitleAdded && _profile.EnableSingleSubtitleLimit)
|
||||||
@@ -251,7 +262,8 @@ namespace Emby.Dlna.Didl
|
|||||||
private bool AddSubtitleElement(XmlWriter writer, SubtitleStreamInfo info)
|
private bool AddSubtitleElement(XmlWriter writer, SubtitleStreamInfo info)
|
||||||
{
|
{
|
||||||
var subtitleProfile = _profile.SubtitleProfiles
|
var subtitleProfile = _profile.SubtitleProfiles
|
||||||
.FirstOrDefault(i => string.Equals(info.Format, i.Format, StringComparison.OrdinalIgnoreCase) && i.Method == SubtitleDeliveryMethod.External);
|
.FirstOrDefault(i => string.Equals(info.Format, i.Format, StringComparison.OrdinalIgnoreCase)
|
||||||
|
&& i.Method == SubtitleDeliveryMethod.External);
|
||||||
|
|
||||||
if (subtitleProfile == null)
|
if (subtitleProfile == null)
|
||||||
{
|
{
|
||||||
@@ -266,7 +278,7 @@ namespace Emby.Dlna.Didl
|
|||||||
// <sec:CaptionInfo sec:type="srt">http://192.168.1.3:9999/video.srt</sec:CaptionInfo>
|
// <sec:CaptionInfo sec:type="srt">http://192.168.1.3:9999/video.srt</sec:CaptionInfo>
|
||||||
|
|
||||||
writer.WriteStartElement("sec", "CaptionInfoEx", null);
|
writer.WriteStartElement("sec", "CaptionInfoEx", null);
|
||||||
writer.WriteAttributeString("sec", "type", null, info.Format.ToLower());
|
writer.WriteAttributeString("sec", "type", null, info.Format.ToLowerInvariant());
|
||||||
|
|
||||||
writer.WriteString(info.Url);
|
writer.WriteString(info.Url);
|
||||||
writer.WriteFullEndElement();
|
writer.WriteFullEndElement();
|
||||||
@@ -283,7 +295,7 @@ namespace Emby.Dlna.Didl
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
writer.WriteStartElement(string.Empty, "res", NS_DIDL);
|
writer.WriteStartElement(string.Empty, "res", NS_DIDL);
|
||||||
var protocolInfo = string.Format("http-get:*:text/{0}:*", info.Format.ToLower());
|
var protocolInfo = string.Format("http-get:*:text/{0}:*", info.Format.ToLowerInvariant());
|
||||||
writer.WriteAttributeString("protocolInfo", protocolInfo);
|
writer.WriteAttributeString("protocolInfo", protocolInfo);
|
||||||
|
|
||||||
writer.WriteString(info.Url);
|
writer.WriteString(info.Url);
|
||||||
@@ -375,7 +387,7 @@ namespace Emby.Dlna.Didl
|
|||||||
? GetMimeType(filename)
|
? GetMimeType(filename)
|
||||||
: mediaProfile.MimeType;
|
: mediaProfile.MimeType;
|
||||||
|
|
||||||
writer.WriteAttributeString("protocolInfo", String.Format(
|
writer.WriteAttributeString("protocolInfo", string.Format(
|
||||||
"http-get:*:{0}:{1}",
|
"http-get:*:{0}:{1}",
|
||||||
mimeType,
|
mimeType,
|
||||||
contentFeatures
|
contentFeatures
|
||||||
@@ -388,91 +400,39 @@ namespace Emby.Dlna.Didl
|
|||||||
|
|
||||||
private string GetDisplayName(BaseItem item, StubType? itemStubType, BaseItem context)
|
private string GetDisplayName(BaseItem item, StubType? itemStubType, BaseItem context)
|
||||||
{
|
{
|
||||||
if (itemStubType.HasValue && itemStubType.Value == StubType.Latest)
|
if (itemStubType.HasValue)
|
||||||
{
|
{
|
||||||
return _localization.GetLocalizedString("Latest");
|
switch (itemStubType.Value)
|
||||||
}
|
{
|
||||||
if (itemStubType.HasValue && itemStubType.Value == StubType.Playlists)
|
case StubType.Latest: return _localization.GetLocalizedString("Latest");
|
||||||
{
|
case StubType.Playlists: return _localization.GetLocalizedString("Playlists");
|
||||||
return _localization.GetLocalizedString("Playlists");
|
case StubType.AlbumArtists: return _localization.GetLocalizedString("HeaderAlbumArtists");
|
||||||
}
|
case StubType.Albums: return _localization.GetLocalizedString("Albums");
|
||||||
if (itemStubType.HasValue && itemStubType.Value == StubType.AlbumArtists)
|
case StubType.Artists: return _localization.GetLocalizedString("Artists");
|
||||||
{
|
case StubType.Songs: return _localization.GetLocalizedString("Songs");
|
||||||
return _localization.GetLocalizedString("HeaderAlbumArtists");
|
case StubType.Genres: return _localization.GetLocalizedString("Genres");
|
||||||
}
|
case StubType.FavoriteAlbums: return _localization.GetLocalizedString("HeaderFavoriteAlbums");
|
||||||
if (itemStubType.HasValue && itemStubType.Value == StubType.Albums)
|
case StubType.FavoriteArtists: return _localization.GetLocalizedString("HeaderFavoriteArtists");
|
||||||
{
|
case StubType.FavoriteSongs: return _localization.GetLocalizedString("HeaderFavoriteSongs");
|
||||||
return _localization.GetLocalizedString("Albums");
|
case StubType.ContinueWatching: return _localization.GetLocalizedString("HeaderContinueWatching");
|
||||||
}
|
case StubType.Movies: return _localization.GetLocalizedString("Movies");
|
||||||
if (itemStubType.HasValue && itemStubType.Value == StubType.Artists)
|
case StubType.Collections: return _localization.GetLocalizedString("Collections");
|
||||||
{
|
case StubType.Favorites: return _localization.GetLocalizedString("Favorites");
|
||||||
return _localization.GetLocalizedString("Artists");
|
case StubType.NextUp: return _localization.GetLocalizedString("HeaderNextUp");
|
||||||
}
|
case StubType.FavoriteSeries: return _localization.GetLocalizedString("HeaderFavoriteShows");
|
||||||
if (itemStubType.HasValue && itemStubType.Value == StubType.Songs)
|
case StubType.FavoriteEpisodes: return _localization.GetLocalizedString("HeaderFavoriteEpisodes");
|
||||||
{
|
case StubType.Series: return _localization.GetLocalizedString("Shows");
|
||||||
return _localization.GetLocalizedString("Songs");
|
default: break;
|
||||||
}
|
}
|
||||||
if (itemStubType.HasValue && itemStubType.Value == StubType.Genres)
|
|
||||||
{
|
|
||||||
return _localization.GetLocalizedString("Genres");
|
|
||||||
}
|
|
||||||
if (itemStubType.HasValue && itemStubType.Value == StubType.FavoriteAlbums)
|
|
||||||
{
|
|
||||||
return _localization.GetLocalizedString("HeaderFavoriteAlbums");
|
|
||||||
}
|
|
||||||
if (itemStubType.HasValue && itemStubType.Value == StubType.FavoriteArtists)
|
|
||||||
{
|
|
||||||
return _localization.GetLocalizedString("HeaderFavoriteArtists");
|
|
||||||
}
|
|
||||||
if (itemStubType.HasValue && itemStubType.Value == StubType.FavoriteSongs)
|
|
||||||
{
|
|
||||||
return _localization.GetLocalizedString("HeaderFavoriteSongs");
|
|
||||||
}
|
|
||||||
if (itemStubType.HasValue && itemStubType.Value == StubType.ContinueWatching)
|
|
||||||
{
|
|
||||||
return _localization.GetLocalizedString("HeaderContinueWatching");
|
|
||||||
}
|
|
||||||
if (itemStubType.HasValue && itemStubType.Value == StubType.Movies)
|
|
||||||
{
|
|
||||||
return _localization.GetLocalizedString("Movies");
|
|
||||||
}
|
|
||||||
if (itemStubType.HasValue && itemStubType.Value == StubType.Collections)
|
|
||||||
{
|
|
||||||
return _localization.GetLocalizedString("Collections");
|
|
||||||
}
|
|
||||||
if (itemStubType.HasValue && itemStubType.Value == StubType.Favorites)
|
|
||||||
{
|
|
||||||
return _localization.GetLocalizedString("Favorites");
|
|
||||||
}
|
|
||||||
if (itemStubType.HasValue && itemStubType.Value == StubType.NextUp)
|
|
||||||
{
|
|
||||||
return _localization.GetLocalizedString("HeaderNextUp");
|
|
||||||
}
|
|
||||||
if (itemStubType.HasValue && itemStubType.Value == StubType.FavoriteSeries)
|
|
||||||
{
|
|
||||||
return _localization.GetLocalizedString("HeaderFavoriteShows");
|
|
||||||
}
|
|
||||||
if (itemStubType.HasValue && itemStubType.Value == StubType.FavoriteEpisodes)
|
|
||||||
{
|
|
||||||
return _localization.GetLocalizedString("HeaderFavoriteEpisodes");
|
|
||||||
}
|
|
||||||
if (itemStubType.HasValue && itemStubType.Value == StubType.Series)
|
|
||||||
{
|
|
||||||
return _localization.GetLocalizedString("Shows");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var episode = item as Episode;
|
if (item is Episode episode && context is Season season)
|
||||||
var season = context as Season;
|
|
||||||
|
|
||||||
if (episode != null && season != null)
|
|
||||||
{
|
{
|
||||||
// This is a special embedded within a season
|
// This is a special embedded within a season
|
||||||
if (item.ParentIndexNumber.HasValue && item.ParentIndexNumber.Value == 0)
|
if (item.ParentIndexNumber.HasValue && item.ParentIndexNumber.Value == 0
|
||||||
|
&& season.IndexNumber.HasValue && season.IndexNumber.Value != 0)
|
||||||
{
|
{
|
||||||
if (season.IndexNumber.HasValue && season.IndexNumber.Value != 0)
|
return string.Format(_localization.GetLocalizedString("ValueSpecialEpisodeName"), item.Name);
|
||||||
{
|
|
||||||
return string.Format(_localization.GetLocalizedString("ValueSpecialEpisodeName"), item.Name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.IndexNumber.HasValue)
|
if (item.IndexNumber.HasValue)
|
||||||
@@ -573,7 +533,7 @@ namespace Emby.Dlna.Didl
|
|||||||
streamInfo.RunTimeTicks ?? 0,
|
streamInfo.RunTimeTicks ?? 0,
|
||||||
streamInfo.TranscodeSeekInfo);
|
streamInfo.TranscodeSeekInfo);
|
||||||
|
|
||||||
writer.WriteAttributeString("protocolInfo", String.Format(
|
writer.WriteAttributeString("protocolInfo", string.Format(
|
||||||
"http-get:*:{0}:{1}",
|
"http-get:*:{0}:{1}",
|
||||||
mimeType,
|
mimeType,
|
||||||
contentFeatures
|
contentFeatures
|
||||||
@@ -586,10 +546,8 @@ namespace Emby.Dlna.Didl
|
|||||||
|
|
||||||
public static bool IsIdRoot(string id)
|
public static bool IsIdRoot(string id)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(id) ||
|
if (string.IsNullOrWhiteSpace(id)
|
||||||
|
|| string.Equals(id, "0", StringComparison.OrdinalIgnoreCase)
|
||||||
string.Equals(id, "0", StringComparison.OrdinalIgnoreCase)
|
|
||||||
|
|
||||||
// Samsung sometimes uses 1 as root
|
// Samsung sometimes uses 1 as root
|
||||||
|| string.Equals(id, "1", StringComparison.OrdinalIgnoreCase))
|
|| string.Equals(id, "1", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
@@ -809,7 +767,7 @@ namespace Emby.Dlna.Didl
|
|||||||
{
|
{
|
||||||
writer.WriteString(_profile.RequiresPlainFolders ? "object.container.storageFolder" : "object.container.genre.musicGenre");
|
writer.WriteString(_profile.RequiresPlainFolders ? "object.container.storageFolder" : "object.container.genre.musicGenre");
|
||||||
}
|
}
|
||||||
else if (item is Genre || item is GameGenre)
|
else if (item is Genre)
|
||||||
{
|
{
|
||||||
writer.WriteString(_profile.RequiresPlainFolders ? "object.container.storageFolder" : "object.container.genre");
|
writer.WriteString(_profile.RequiresPlainFolders ? "object.container.storageFolder" : "object.container.genre");
|
||||||
}
|
}
|
||||||
@@ -845,7 +803,7 @@ namespace Emby.Dlna.Didl
|
|||||||
// var type = types.FirstOrDefault(i => string.Equals(i, actor.Type, StringComparison.OrdinalIgnoreCase) || string.Equals(i, actor.Role, StringComparison.OrdinalIgnoreCase))
|
// var type = types.FirstOrDefault(i => string.Equals(i, actor.Type, StringComparison.OrdinalIgnoreCase) || string.Equals(i, actor.Role, StringComparison.OrdinalIgnoreCase))
|
||||||
// ?? PersonType.Actor;
|
// ?? PersonType.Actor;
|
||||||
|
|
||||||
// AddValue(writer, "upnp", type.ToLower(), actor.Name, NS_UPNP);
|
// AddValue(writer, "upnp", type.ToLowerInvariant(), actor.Name, NS_UPNP);
|
||||||
|
|
||||||
// index++;
|
// index++;
|
||||||
|
|
||||||
@@ -860,10 +818,9 @@ namespace Emby.Dlna.Didl
|
|||||||
{
|
{
|
||||||
AddCommonFields(item, itemStubType, context, writer, filter);
|
AddCommonFields(item, itemStubType, context, writer, filter);
|
||||||
|
|
||||||
var hasArtists = item as IHasArtist;
|
|
||||||
var hasAlbumArtists = item as IHasAlbumArtist;
|
var hasAlbumArtists = item as IHasAlbumArtist;
|
||||||
|
|
||||||
if (hasArtists != null)
|
if (item is IHasArtist hasArtists)
|
||||||
{
|
{
|
||||||
foreach (var artist in hasArtists.Artists)
|
foreach (var artist in hasArtists.Artists)
|
||||||
{
|
{
|
||||||
@@ -933,13 +890,7 @@ namespace Emby.Dlna.Didl
|
|||||||
|
|
||||||
private void AddCover(BaseItem item, BaseItem context, StubType? stubType, XmlWriter writer)
|
private void AddCover(BaseItem item, BaseItem context, StubType? stubType, XmlWriter writer)
|
||||||
{
|
{
|
||||||
ImageDownloadInfo imageInfo = null;
|
ImageDownloadInfo imageInfo = GetImageInfo(item);
|
||||||
|
|
||||||
// Finally, just use the image from the item
|
|
||||||
if (imageInfo == null)
|
|
||||||
{
|
|
||||||
imageInfo = GetImageInfo(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (imageInfo == null)
|
if (imageInfo == null)
|
||||||
{
|
{
|
||||||
@@ -1017,7 +968,7 @@ namespace Emby.Dlna.Didl
|
|||||||
var contentFeatures = new ContentFeatureBuilder(_profile)
|
var contentFeatures = new ContentFeatureBuilder(_profile)
|
||||||
.BuildImageHeader(format, width, height, imageInfo.IsDirectStream, org_Pn);
|
.BuildImageHeader(format, width, height, imageInfo.IsDirectStream, org_Pn);
|
||||||
|
|
||||||
writer.WriteAttributeString("protocolInfo", String.Format(
|
writer.WriteAttributeString("protocolInfo", string.Format(
|
||||||
"http-get:*:{0}:{1}",
|
"http-get:*:{0}:{1}",
|
||||||
GetMimeType("file." + format),
|
GetMimeType("file." + format),
|
||||||
contentFeatures
|
contentFeatures
|
||||||
@@ -1095,8 +1046,8 @@ namespace Emby.Dlna.Didl
|
|||||||
//{
|
//{
|
||||||
// var size = _imageProcessor.GetImageSize(imageInfo);
|
// var size = _imageProcessor.GetImageSize(imageInfo);
|
||||||
|
|
||||||
// width = Convert.ToInt32(size.Width);
|
// width = size.Width;
|
||||||
// height = Convert.ToInt32(size.Height);
|
// height = size.Height;
|
||||||
//}
|
//}
|
||||||
//catch
|
//catch
|
||||||
//{
|
//{
|
||||||
@@ -1119,7 +1070,7 @@ namespace Emby.Dlna.Didl
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class ImageDownloadInfo
|
private class ImageDownloadInfo
|
||||||
{
|
{
|
||||||
internal Guid ItemId;
|
internal Guid ItemId;
|
||||||
internal string ImageTag;
|
internal string ImageTag;
|
||||||
@@ -1135,7 +1086,7 @@ namespace Emby.Dlna.Didl
|
|||||||
internal ItemImageInfo ItemImageInfo;
|
internal ItemImageInfo ItemImageInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ImageUrlInfo
|
private class ImageUrlInfo
|
||||||
{
|
{
|
||||||
internal string Url;
|
internal string Url;
|
||||||
|
|
||||||
@@ -1154,7 +1105,7 @@ namespace Emby.Dlna.Didl
|
|||||||
|
|
||||||
if (stubType.HasValue)
|
if (stubType.HasValue)
|
||||||
{
|
{
|
||||||
id = stubType.Value.ToString().ToLower() + "_" + id;
|
id = stubType.Value.ToString().ToLowerInvariant() + "_" + id;
|
||||||
}
|
}
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
@@ -1169,8 +1120,7 @@ namespace Emby.Dlna.Didl
|
|||||||
info.ImageTag,
|
info.ImageTag,
|
||||||
format,
|
format,
|
||||||
maxWidth.ToString(CultureInfo.InvariantCulture),
|
maxWidth.ToString(CultureInfo.InvariantCulture),
|
||||||
maxHeight.ToString(CultureInfo.InvariantCulture)
|
maxHeight.ToString(CultureInfo.InvariantCulture));
|
||||||
);
|
|
||||||
|
|
||||||
var width = info.Width;
|
var width = info.Width;
|
||||||
var height = info.Height;
|
var height = info.Height;
|
||||||
@@ -1179,15 +1129,11 @@ namespace Emby.Dlna.Didl
|
|||||||
|
|
||||||
if (width.HasValue && height.HasValue)
|
if (width.HasValue && height.HasValue)
|
||||||
{
|
{
|
||||||
var newSize = DrawingUtils.Resize(new ImageSize
|
var newSize = DrawingUtils.Resize(
|
||||||
{
|
new ImageDimensions(width.Value, height.Value), 0, 0, maxWidth, maxHeight);
|
||||||
Height = height.Value,
|
|
||||||
Width = width.Value
|
|
||||||
|
|
||||||
}, 0, 0, maxWidth, maxHeight);
|
width = newSize.Width;
|
||||||
|
height = newSize.Height;
|
||||||
width = Convert.ToInt32(newSize.Width);
|
|
||||||
height = Convert.ToInt32(newSize.Height);
|
|
||||||
|
|
||||||
var normalizedFormat = format
|
var normalizedFormat = format
|
||||||
.Replace("jpeg", "jpg", StringComparison.OrdinalIgnoreCase);
|
.Replace("jpeg", "jpg", StringComparison.OrdinalIgnoreCase);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using MediaBrowser.Model.Extensions;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using MediaBrowser.Model.Extensions;
|
||||||
|
|
||||||
namespace Emby.Dlna.Didl
|
namespace Emby.Dlna.Didl
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Emby.Dlna.Didl
|
namespace Emby.Dlna.Didl
|
||||||
{
|
{
|
||||||
@@ -53,9 +51,6 @@ namespace Emby.Dlna.Didl
|
|||||||
_encoding = encoding;
|
_encoding = encoding;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Encoding Encoding
|
public override Encoding Encoding => (null == _encoding) ? base.Encoding : _encoding;
|
||||||
{
|
|
||||||
get { return (null == _encoding) ? base.Encoding : _encoding; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,25 @@
|
|||||||
using MediaBrowser.Common.Configuration;
|
|
||||||
using MediaBrowser.Common.Extensions;
|
|
||||||
using MediaBrowser.Controller;
|
|
||||||
using MediaBrowser.Controller.Dlna;
|
|
||||||
using MediaBrowser.Controller.Drawing;
|
|
||||||
using MediaBrowser.Controller.Plugins;
|
|
||||||
using Emby.Dlna.Profiles;
|
|
||||||
using Emby.Dlna.Server;
|
|
||||||
using MediaBrowser.Model.Dlna;
|
|
||||||
using MediaBrowser.Model.Drawing;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using MediaBrowser.Model.Serialization;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Emby.Dlna.Profiles;
|
||||||
|
using Emby.Dlna.Server;
|
||||||
|
using MediaBrowser.Common.Configuration;
|
||||||
|
using MediaBrowser.Common.Extensions;
|
||||||
|
using MediaBrowser.Controller;
|
||||||
|
using MediaBrowser.Controller.Dlna;
|
||||||
|
using MediaBrowser.Controller.Drawing;
|
||||||
|
using MediaBrowser.Model.Dlna;
|
||||||
|
using MediaBrowser.Model.Drawing;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.Reflection;
|
using MediaBrowser.Model.Serialization;
|
||||||
using MediaBrowser.Model.Extensions;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
|
|
||||||
namespace Emby.Dlna
|
namespace Emby.Dlna
|
||||||
{
|
{
|
||||||
@@ -30,30 +31,31 @@ namespace Emby.Dlna
|
|||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IJsonSerializer _jsonSerializer;
|
private readonly IJsonSerializer _jsonSerializer;
|
||||||
private readonly IServerApplicationHost _appHost;
|
private readonly IServerApplicationHost _appHost;
|
||||||
private readonly IAssemblyInfo _assemblyInfo;
|
private static readonly Assembly _assembly = typeof(DlnaManager).Assembly;
|
||||||
|
|
||||||
private readonly Dictionary<string, Tuple<InternalProfileInfo, DeviceProfile>> _profiles = new Dictionary<string, Tuple<InternalProfileInfo, DeviceProfile>>(StringComparer.Ordinal);
|
private readonly Dictionary<string, Tuple<InternalProfileInfo, DeviceProfile>> _profiles = new Dictionary<string, Tuple<InternalProfileInfo, DeviceProfile>>(StringComparer.Ordinal);
|
||||||
|
|
||||||
public DlnaManager(IXmlSerializer xmlSerializer,
|
public DlnaManager(
|
||||||
|
IXmlSerializer xmlSerializer,
|
||||||
IFileSystem fileSystem,
|
IFileSystem fileSystem,
|
||||||
IApplicationPaths appPaths,
|
IApplicationPaths appPaths,
|
||||||
ILogger logger,
|
ILoggerFactory loggerFactory,
|
||||||
IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IAssemblyInfo assemblyInfo)
|
IJsonSerializer jsonSerializer,
|
||||||
|
IServerApplicationHost appHost)
|
||||||
{
|
{
|
||||||
_xmlSerializer = xmlSerializer;
|
_xmlSerializer = xmlSerializer;
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
_appPaths = appPaths;
|
_appPaths = appPaths;
|
||||||
_logger = logger;
|
_logger = loggerFactory.CreateLogger("Dlna");
|
||||||
_jsonSerializer = jsonSerializer;
|
_jsonSerializer = jsonSerializer;
|
||||||
_appHost = appHost;
|
_appHost = appHost;
|
||||||
_assemblyInfo = assemblyInfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InitProfiles()
|
public async Task InitProfilesAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ExtractSystemProfiles();
|
await ExtractSystemProfilesAsync();
|
||||||
LoadProfiles();
|
LoadProfiles();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -95,7 +97,7 @@ namespace Emby.Dlna
|
|||||||
{
|
{
|
||||||
if (deviceInfo == null)
|
if (deviceInfo == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException("deviceInfo");
|
throw new ArgumentNullException(nameof(deviceInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
var profile = GetProfiles()
|
var profile = GetProfiles()
|
||||||
@@ -203,16 +205,13 @@ namespace Emby.Dlna
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeviceProfile GetProfile(IDictionary<string, string> headers)
|
public DeviceProfile GetProfile(IHeaderDictionary headers)
|
||||||
{
|
{
|
||||||
if (headers == null)
|
if (headers == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException("headers");
|
throw new ArgumentNullException(nameof(headers));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to case insensitive
|
|
||||||
headers = new Dictionary<string, string>(headers, StringComparer.OrdinalIgnoreCase);
|
|
||||||
|
|
||||||
var profile = GetProfiles().FirstOrDefault(i => i.Identification != null && IsMatch(headers, i.Identification));
|
var profile = GetProfiles().FirstOrDefault(i => i.Identification != null && IsMatch(headers, i.Identification));
|
||||||
|
|
||||||
if (profile != null)
|
if (profile != null)
|
||||||
@@ -228,12 +227,12 @@ namespace Emby.Dlna
|
|||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsMatch(IDictionary<string, string> headers, DeviceIdentification profileInfo)
|
private bool IsMatch(IHeaderDictionary headers, DeviceIdentification profileInfo)
|
||||||
{
|
{
|
||||||
return profileInfo.Headers.Any(i => IsMatch(headers, i));
|
return profileInfo.Headers.Any(i => IsMatch(headers, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsMatch(IDictionary<string, string> headers, HttpHeaderInfo header)
|
private bool IsMatch(IHeaderDictionary headers, HttpHeaderInfo header)
|
||||||
{
|
{
|
||||||
// Handle invalid user setup
|
// Handle invalid user setup
|
||||||
if (string.IsNullOrEmpty(header.Name))
|
if (string.IsNullOrEmpty(header.Name))
|
||||||
@@ -241,16 +240,14 @@ namespace Emby.Dlna
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
string value;
|
if (headers.TryGetValue(header.Name, out StringValues value))
|
||||||
|
|
||||||
if (headers.TryGetValue(header.Name, out value))
|
|
||||||
{
|
{
|
||||||
switch (header.Match)
|
switch (header.Match)
|
||||||
{
|
{
|
||||||
case HeaderMatchType.Equals:
|
case HeaderMatchType.Equals:
|
||||||
return string.Equals(value, header.Value, StringComparison.OrdinalIgnoreCase);
|
return string.Equals(value, header.Value, StringComparison.OrdinalIgnoreCase);
|
||||||
case HeaderMatchType.Substring:
|
case HeaderMatchType.Substring:
|
||||||
var isMatch = value.IndexOf(header.Value, StringComparison.OrdinalIgnoreCase) != -1;
|
var isMatch = value.ToString().IndexOf(header.Value, StringComparison.OrdinalIgnoreCase) != -1;
|
||||||
//_logger.LogDebug("IsMatch-Substring value: {0} testValue: {1} isMatch: {2}", value, header.Value, isMatch);
|
//_logger.LogDebug("IsMatch-Substring value: {0} testValue: {1} isMatch: {2}", value, header.Value, isMatch);
|
||||||
return isMatch;
|
return isMatch;
|
||||||
case HeaderMatchType.Regex:
|
case HeaderMatchType.Regex:
|
||||||
@@ -263,21 +260,9 @@ namespace Emby.Dlna
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string UserProfilesPath
|
private string UserProfilesPath => Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "user");
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "user");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string SystemProfilesPath
|
private string SystemProfilesPath => Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "system");
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "system");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<DeviceProfile> GetProfiles(string path, DeviceProfileType type)
|
private IEnumerable<DeviceProfile> GetProfiles(string path, DeviceProfileType type)
|
||||||
{
|
{
|
||||||
@@ -302,8 +287,7 @@ namespace Emby.Dlna
|
|||||||
{
|
{
|
||||||
lock (_profiles)
|
lock (_profiles)
|
||||||
{
|
{
|
||||||
Tuple<InternalProfileInfo, DeviceProfile> profileTuple;
|
if (_profiles.TryGetValue(path, out Tuple<InternalProfileInfo, DeviceProfile> profileTuple))
|
||||||
if (_profiles.TryGetValue(path, out profileTuple))
|
|
||||||
{
|
{
|
||||||
return profileTuple.Item2;
|
return profileTuple.Item2;
|
||||||
}
|
}
|
||||||
@@ -316,7 +300,7 @@ namespace Emby.Dlna
|
|||||||
|
|
||||||
profile = ReserializeProfile(tempProfile);
|
profile = ReserializeProfile(tempProfile);
|
||||||
|
|
||||||
profile.Id = path.ToLower().GetMD5().ToString("N");
|
profile.Id = path.ToLowerInvariant().GetMD5().ToString("N");
|
||||||
|
|
||||||
_profiles[path] = new Tuple<InternalProfileInfo, DeviceProfile>(GetInternalProfileInfo(_fileSystem.GetFileInfo(path), type), profile);
|
_profiles[path] = new Tuple<InternalProfileInfo, DeviceProfile>(GetInternalProfileInfo(_fileSystem.GetFileInfo(path), type), profile);
|
||||||
|
|
||||||
@@ -335,7 +319,7 @@ namespace Emby.Dlna
|
|||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(id))
|
if (string.IsNullOrEmpty(id))
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException("id");
|
throw new ArgumentNullException(nameof(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
var info = GetProfileInfosInternal().First(i => string.Equals(i.Info.Id, id, StringComparison.OrdinalIgnoreCase));
|
var info = GetProfileInfosInternal().First(i => string.Equals(i.Info.Id, id, StringComparison.OrdinalIgnoreCase));
|
||||||
@@ -368,45 +352,48 @@ namespace Emby.Dlna
|
|||||||
|
|
||||||
Info = new DeviceProfileInfo
|
Info = new DeviceProfileInfo
|
||||||
{
|
{
|
||||||
Id = file.FullName.ToLower().GetMD5().ToString("N"),
|
Id = file.FullName.ToLowerInvariant().GetMD5().ToString("N"),
|
||||||
Name = _fileSystem.GetFileNameWithoutExtension(file),
|
Name = _fileSystem.GetFileNameWithoutExtension(file),
|
||||||
Type = type
|
Type = type
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExtractSystemProfiles()
|
private async Task ExtractSystemProfilesAsync()
|
||||||
{
|
{
|
||||||
var namespaceName = GetType().Namespace + ".Profiles.Xml.";
|
var namespaceName = GetType().Namespace + ".Profiles.Xml.";
|
||||||
|
|
||||||
var systemProfilesPath = SystemProfilesPath;
|
var systemProfilesPath = SystemProfilesPath;
|
||||||
|
|
||||||
foreach (var name in _assemblyInfo.GetManifestResourceNames(GetType())
|
foreach (var name in _assembly.GetManifestResourceNames())
|
||||||
.Where(i => i.StartsWith(namespaceName))
|
|
||||||
.ToList())
|
|
||||||
{
|
{
|
||||||
|
if (!name.StartsWith(namespaceName))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
var filename = Path.GetFileName(name).Substring(namespaceName.Length);
|
var filename = Path.GetFileName(name).Substring(namespaceName.Length);
|
||||||
|
|
||||||
var path = Path.Combine(systemProfilesPath, filename);
|
var path = Path.Combine(systemProfilesPath, filename);
|
||||||
|
|
||||||
using (var stream = _assemblyInfo.GetManifestResourceStream(GetType(), name))
|
using (var stream = _assembly.GetManifestResourceStream(name))
|
||||||
{
|
{
|
||||||
var fileInfo = _fileSystem.GetFileInfo(path);
|
var fileInfo = _fileSystem.GetFileInfo(path);
|
||||||
|
|
||||||
if (!fileInfo.Exists || fileInfo.Length != stream.Length)
|
if (!fileInfo.Exists || fileInfo.Length != stream.Length)
|
||||||
{
|
{
|
||||||
_fileSystem.CreateDirectory(systemProfilesPath);
|
Directory.CreateDirectory(systemProfilesPath);
|
||||||
|
|
||||||
using (var fileStream = _fileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
|
using (var fileStream = _fileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
|
||||||
{
|
{
|
||||||
stream.CopyTo(fileStream);
|
await stream.CopyToAsync(fileStream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not necessary, but just to make it easy to find
|
// Not necessary, but just to make it easy to find
|
||||||
_fileSystem.CreateDirectory(UserProfilesPath);
|
Directory.CreateDirectory(UserProfilesPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeleteProfile(string id)
|
public void DeleteProfile(string id)
|
||||||
@@ -506,7 +493,7 @@ namespace Emby.Dlna
|
|||||||
internal string Path { get; set; }
|
internal string Path { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetServerDescriptionXml(IDictionary<string, string> headers, string serverUuId, string serverAddress)
|
public string GetServerDescriptionXml(IHeaderDictionary headers, string serverUuId, string serverAddress)
|
||||||
{
|
{
|
||||||
var profile = GetProfile(headers) ??
|
var profile = GetProfile(headers) ??
|
||||||
GetDefaultProfile();
|
GetDefaultProfile();
|
||||||
@@ -522,12 +509,12 @@ namespace Emby.Dlna
|
|||||||
? ImageFormat.Png
|
? ImageFormat.Png
|
||||||
: ImageFormat.Jpg;
|
: ImageFormat.Jpg;
|
||||||
|
|
||||||
var resource = GetType().Namespace + ".Images." + filename.ToLower();
|
var resource = GetType().Namespace + ".Images." + filename.ToLowerInvariant();
|
||||||
|
|
||||||
return new ImageStream
|
return new ImageStream
|
||||||
{
|
{
|
||||||
Format = format,
|
Format = format,
|
||||||
Stream = _assemblyInfo.GetManifestResourceStream(GetType(), resource)
|
Stream = _assembly.GetManifestResourceStream(resource)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="..\SharedVersion.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
||||||
@@ -54,4 +58,9 @@
|
|||||||
<EmbeddedResource Include="Profiles\Xml\Xbox One.xml" />
|
<EmbeddedResource Include="Profiles\Xml\Xbox One.xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="2.2.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Emby.Dlna
|
namespace Emby.Dlna
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
using MediaBrowser.Common.Extensions;
|
|
||||||
using MediaBrowser.Common.Net;
|
|
||||||
using MediaBrowser.Controller.Dlna;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -9,6 +5,9 @@ using System.Globalization;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Common.Extensions;
|
||||||
|
using MediaBrowser.Common.Net;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Emby.Dlna.Eventing
|
namespace Emby.Dlna.Eventing
|
||||||
{
|
{
|
||||||
@@ -83,9 +82,7 @@ namespace Emby.Dlna.Eventing
|
|||||||
// Starts with SECOND-
|
// Starts with SECOND-
|
||||||
header = header.Split('-').Last();
|
header = header.Split('-').Last();
|
||||||
|
|
||||||
int val;
|
if (int.TryParse(header, NumberStyles.Integer, _usCulture, out var val))
|
||||||
|
|
||||||
if (int.TryParse(header, NumberStyles.Integer, _usCulture, out val))
|
|
||||||
{
|
{
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
@@ -98,8 +95,7 @@ namespace Emby.Dlna.Eventing
|
|||||||
{
|
{
|
||||||
_logger.LogDebug("Cancelling event subscription {0}", subscriptionId);
|
_logger.LogDebug("Cancelling event subscription {0}", subscriptionId);
|
||||||
|
|
||||||
EventSubscription sub;
|
_subscriptions.TryRemove(subscriptionId, out EventSubscription sub);
|
||||||
_subscriptions.TryRemove(subscriptionId, out sub);
|
|
||||||
|
|
||||||
return new EventSubscriptionResponse
|
return new EventSubscriptionResponse
|
||||||
{
|
{
|
||||||
@@ -130,9 +126,7 @@ namespace Emby.Dlna.Eventing
|
|||||||
|
|
||||||
private EventSubscription GetSubscription(string id, bool throwOnMissing)
|
private EventSubscription GetSubscription(string id, bool throwOnMissing)
|
||||||
{
|
{
|
||||||
EventSubscription e;
|
if (!_subscriptions.TryGetValue(id, out EventSubscription e) && throwOnMissing)
|
||||||
|
|
||||||
if (!_subscriptions.TryGetValue(id, out e) && throwOnMissing)
|
|
||||||
{
|
{
|
||||||
throw new ResourceNotFoundException("Event with Id " + id + " not found.");
|
throw new ResourceNotFoundException("Event with Id " + id + " not found.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Emby.Dlna.Eventing
|
namespace Emby.Dlna.Eventing
|
||||||
{
|
{
|
||||||
@@ -23,12 +23,6 @@ namespace Emby.Dlna.Eventing
|
|||||||
TriggerCount++;
|
TriggerCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsExpired
|
public bool IsExpired => SubscriptionTime.AddSeconds(TimeoutSeconds) >= DateTime.UtcNow;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return SubscriptionTime.AddSeconds(TimeoutSeconds) >= DateTime.UtcNow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
|
|
||||||
namespace Emby.Dlna
|
namespace Emby.Dlna
|
||||||
{
|
{
|
||||||
public interface IConnectionManager : IEventManager, IUpnpService
|
public interface IConnectionManager : IEventManager, IUpnpService
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
|
|
||||||
namespace Emby.Dlna
|
namespace Emby.Dlna
|
||||||
{
|
{
|
||||||
public interface IContentDirectory : IEventManager, IUpnpService
|
public interface IContentDirectory : IEventManager, IUpnpService
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
|
|
||||||
namespace Emby.Dlna
|
namespace Emby.Dlna
|
||||||
{
|
{
|
||||||
public interface IEventManager
|
public interface IEventManager
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
|
|
||||||
namespace Emby.Dlna
|
namespace Emby.Dlna
|
||||||
{
|
{
|
||||||
public interface IMediaReceiverRegistrar : IEventManager, IUpnpService
|
public interface IMediaReceiverRegistrar : IEventManager, IUpnpService
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Emby.Dlna
|
namespace Emby.Dlna
|
||||||
{
|
{
|
||||||
public interface IUpnpService
|
public interface IUpnpService
|
||||||
@@ -7,9 +5,8 @@ namespace Emby.Dlna
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the content directory XML.
|
/// Gets the content directory XML.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="headers">The headers.</param>
|
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
string GetServiceXml(IDictionary<string, string> headers);
|
string GetServiceXml();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Processes the control request.
|
/// Processes the control request.
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 6.1 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 13 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.2 KiB |
@@ -1,4 +1,9 @@
|
|||||||
using MediaBrowser.Common.Configuration;
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Emby.Dlna.PlayTo;
|
||||||
|
using Emby.Dlna.Ssdp;
|
||||||
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller;
|
using MediaBrowser.Controller;
|
||||||
@@ -6,25 +11,18 @@ using MediaBrowser.Controller.Configuration;
|
|||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Controller.Plugins;
|
using MediaBrowser.Controller.Plugins;
|
||||||
using MediaBrowser.Controller.Session;
|
using MediaBrowser.Controller.Session;
|
||||||
using MediaBrowser.Controller.TV;
|
using MediaBrowser.Controller.TV;
|
||||||
using Emby.Dlna.PlayTo;
|
|
||||||
using Emby.Dlna.Ssdp;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
|
||||||
using MediaBrowser.Model.Dlna;
|
using MediaBrowser.Model.Dlna;
|
||||||
using MediaBrowser.Model.Globalization;
|
using MediaBrowser.Model.Globalization;
|
||||||
using MediaBrowser.Model.Net;
|
using MediaBrowser.Model.Net;
|
||||||
using MediaBrowser.Model.System;
|
using MediaBrowser.Model.System;
|
||||||
using MediaBrowser.Model.Threading;
|
using Microsoft.Extensions.Logging;
|
||||||
using MediaBrowser.Model.Xml;
|
|
||||||
using Rssdp;
|
using Rssdp;
|
||||||
using Rssdp.Infrastructure;
|
using Rssdp.Infrastructure;
|
||||||
using System.Threading;
|
using OperatingSystem = MediaBrowser.Common.System.OperatingSystem;
|
||||||
|
|
||||||
namespace Emby.Dlna.Main
|
namespace Emby.Dlna.Main
|
||||||
{
|
{
|
||||||
@@ -50,9 +48,7 @@ namespace Emby.Dlna.Main
|
|||||||
|
|
||||||
private SsdpDevicePublisher _Publisher;
|
private SsdpDevicePublisher _Publisher;
|
||||||
|
|
||||||
private readonly ITimerFactory _timerFactory;
|
|
||||||
private readonly ISocketFactory _socketFactory;
|
private readonly ISocketFactory _socketFactory;
|
||||||
private readonly IEnvironmentInfo _environmentInfo;
|
|
||||||
private readonly INetworkManager _networkManager;
|
private readonly INetworkManager _networkManager;
|
||||||
|
|
||||||
private ISsdpCommunicationsServer _communicationsServer;
|
private ISsdpCommunicationsServer _communicationsServer;
|
||||||
@@ -78,11 +74,8 @@ namespace Emby.Dlna.Main
|
|||||||
IDeviceDiscovery deviceDiscovery,
|
IDeviceDiscovery deviceDiscovery,
|
||||||
IMediaEncoder mediaEncoder,
|
IMediaEncoder mediaEncoder,
|
||||||
ISocketFactory socketFactory,
|
ISocketFactory socketFactory,
|
||||||
ITimerFactory timerFactory,
|
|
||||||
IEnvironmentInfo environmentInfo,
|
|
||||||
INetworkManager networkManager,
|
INetworkManager networkManager,
|
||||||
IUserViewManager userViewManager,
|
IUserViewManager userViewManager,
|
||||||
IXmlReaderSettingsFactory xmlReaderSettingsFactory,
|
|
||||||
ITVSeriesManager tvSeriesManager)
|
ITVSeriesManager tvSeriesManager)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
@@ -99,12 +92,11 @@ namespace Emby.Dlna.Main
|
|||||||
_deviceDiscovery = deviceDiscovery;
|
_deviceDiscovery = deviceDiscovery;
|
||||||
_mediaEncoder = mediaEncoder;
|
_mediaEncoder = mediaEncoder;
|
||||||
_socketFactory = socketFactory;
|
_socketFactory = socketFactory;
|
||||||
_timerFactory = timerFactory;
|
|
||||||
_environmentInfo = environmentInfo;
|
|
||||||
_networkManager = networkManager;
|
_networkManager = networkManager;
|
||||||
_logger = loggerFactory.CreateLogger("Dlna");
|
_logger = loggerFactory.CreateLogger("Dlna");
|
||||||
|
|
||||||
ContentDirectory = new ContentDirectory.ContentDirectory(dlnaManager,
|
ContentDirectory = new ContentDirectory.ContentDirectory(
|
||||||
|
dlnaManager,
|
||||||
userDataManager,
|
userDataManager,
|
||||||
imageProcessor,
|
imageProcessor,
|
||||||
libraryManager,
|
libraryManager,
|
||||||
@@ -116,18 +108,17 @@ namespace Emby.Dlna.Main
|
|||||||
mediaSourceManager,
|
mediaSourceManager,
|
||||||
userViewManager,
|
userViewManager,
|
||||||
mediaEncoder,
|
mediaEncoder,
|
||||||
xmlReaderSettingsFactory,
|
|
||||||
tvSeriesManager);
|
tvSeriesManager);
|
||||||
|
|
||||||
ConnectionManager = new ConnectionManager.ConnectionManager(dlnaManager, config, _logger, httpClient, xmlReaderSettingsFactory);
|
ConnectionManager = new ConnectionManager.ConnectionManager(dlnaManager, config, _logger, httpClient);
|
||||||
|
|
||||||
MediaReceiverRegistrar = new MediaReceiverRegistrar.MediaReceiverRegistrar(_logger, httpClient, config, xmlReaderSettingsFactory);
|
MediaReceiverRegistrar = new MediaReceiverRegistrar.MediaReceiverRegistrar(_logger, httpClient, config);
|
||||||
Current = this;
|
Current = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Run()
|
public async Task RunAsync()
|
||||||
{
|
{
|
||||||
((DlnaManager)_dlnaManager).InitProfiles();
|
await ((DlnaManager)_dlnaManager).InitProfilesAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
ReloadComponents();
|
ReloadComponents();
|
||||||
|
|
||||||
@@ -173,9 +164,10 @@ namespace Emby.Dlna.Main
|
|||||||
{
|
{
|
||||||
if (_communicationsServer == null)
|
if (_communicationsServer == null)
|
||||||
{
|
{
|
||||||
var enableMultiSocketBinding = _environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows;
|
var enableMultiSocketBinding = OperatingSystem.Id == OperatingSystemId.Windows ||
|
||||||
|
OperatingSystem.Id == OperatingSystemId.Linux;
|
||||||
|
|
||||||
_communicationsServer = new SsdpCommunicationsServer(_socketFactory, _networkManager, _logger, enableMultiSocketBinding)
|
_communicationsServer = new SsdpCommunicationsServer(_config, _socketFactory, _networkManager, _logger, enableMultiSocketBinding)
|
||||||
{
|
{
|
||||||
IsShared = true
|
IsShared = true
|
||||||
};
|
};
|
||||||
@@ -233,7 +225,7 @@ namespace Emby.Dlna.Main
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_Publisher = new SsdpDevicePublisher(_communicationsServer, _timerFactory, _environmentInfo.OperatingSystemName, _environmentInfo.OperatingSystemVersion);
|
_Publisher = new SsdpDevicePublisher(_communicationsServer, _networkManager, OperatingSystem.Name, Environment.OSVersion.VersionString, _config.GetDlnaConfiguration().SendOnlyMatchedHost);
|
||||||
_Publisher.LogFunction = LogMessage;
|
_Publisher.LogFunction = LogMessage;
|
||||||
_Publisher.SupportPnpRootDevice = false;
|
_Publisher.SupportPnpRootDevice = false;
|
||||||
|
|
||||||
@@ -249,21 +241,21 @@ namespace Emby.Dlna.Main
|
|||||||
|
|
||||||
private async Task RegisterServerEndpoints()
|
private async Task RegisterServerEndpoints()
|
||||||
{
|
{
|
||||||
var addresses = (await _appHost.GetLocalIpAddresses(CancellationToken.None).ConfigureAwait(false)).ToList();
|
var addresses = await _appHost.GetLocalIpAddresses(CancellationToken.None).ConfigureAwait(false);
|
||||||
|
|
||||||
var udn = CreateUuid(_appHost.SystemId);
|
var udn = CreateUuid(_appHost.SystemId);
|
||||||
|
|
||||||
foreach (var address in addresses)
|
foreach (var address in addresses)
|
||||||
{
|
{
|
||||||
// TODO: Remove this condition on platforms that support it
|
if (address.AddressFamily == IpAddressFamily.InterNetworkV6)
|
||||||
//if (address.AddressFamily == IpAddressFamily.InterNetworkV6)
|
{
|
||||||
//{
|
// Not support IPv6 right now
|
||||||
// continue;
|
continue;
|
||||||
//}
|
}
|
||||||
|
|
||||||
var fullService = "urn:schemas-upnp-org:device:MediaServer:1";
|
var fullService = "urn:schemas-upnp-org:device:MediaServer:1";
|
||||||
|
|
||||||
_logger.LogInformation("Registering publisher for {0} on {1}", fullService, address.ToString());
|
_logger.LogInformation("Registering publisher for {0} on {1}", fullService, address);
|
||||||
|
|
||||||
var descriptorUri = "/dlna/" + udn + "/description.xml";
|
var descriptorUri = "/dlna/" + udn + "/description.xml";
|
||||||
var uri = new Uri(_appHost.GetLocalApiUrl(address) + descriptorUri);
|
var uri = new Uri(_appHost.GetLocalApiUrl(address) + descriptorUri);
|
||||||
@@ -272,6 +264,8 @@ namespace Emby.Dlna.Main
|
|||||||
{
|
{
|
||||||
CacheLifetime = TimeSpan.FromSeconds(1800), //How long SSDP clients can cache this info.
|
CacheLifetime = TimeSpan.FromSeconds(1800), //How long SSDP clients can cache this info.
|
||||||
Location = uri, // Must point to the URL that serves your devices UPnP description document.
|
Location = uri, // Must point to the URL that serves your devices UPnP description document.
|
||||||
|
Address = address,
|
||||||
|
SubnetMask = _networkManager.GetLocalIpSubnetMask(address),
|
||||||
FriendlyName = "Jellyfin",
|
FriendlyName = "Jellyfin",
|
||||||
Manufacturer = "Jellyfin",
|
Manufacturer = "Jellyfin",
|
||||||
ModelName = "Jellyfin Server",
|
ModelName = "Jellyfin Server",
|
||||||
@@ -282,7 +276,7 @@ namespace Emby.Dlna.Main
|
|||||||
SetProperies(device, fullService);
|
SetProperies(device, fullService);
|
||||||
_Publisher.AddDevice(device);
|
_Publisher.AddDevice(device);
|
||||||
|
|
||||||
var embeddedDevices = new []
|
var embeddedDevices = new[]
|
||||||
{
|
{
|
||||||
"urn:schemas-upnp-org:service:ContentDirectory:1",
|
"urn:schemas-upnp-org:service:ContentDirectory:1",
|
||||||
"urn:schemas-upnp-org:service:ConnectionManager:1",
|
"urn:schemas-upnp-org:service:ConnectionManager:1",
|
||||||
@@ -308,8 +302,7 @@ namespace Emby.Dlna.Main
|
|||||||
|
|
||||||
private string CreateUuid(string text)
|
private string CreateUuid(string text)
|
||||||
{
|
{
|
||||||
Guid guid;
|
if (!Guid.TryParse(text, out var guid))
|
||||||
if (!Guid.TryParse(text, out guid))
|
|
||||||
{
|
{
|
||||||
guid = text.GetMD5();
|
guid = text.GetMD5();
|
||||||
}
|
}
|
||||||
@@ -354,8 +347,7 @@ namespace Emby.Dlna.Main
|
|||||||
_userDataManager,
|
_userDataManager,
|
||||||
_localization,
|
_localization,
|
||||||
_mediaSourceManager,
|
_mediaSourceManager,
|
||||||
_mediaEncoder,
|
_mediaEncoder);
|
||||||
_timerFactory);
|
|
||||||
|
|
||||||
_manager.Start();
|
_manager.Start();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
using MediaBrowser.Common.Extensions;
|
|
||||||
using MediaBrowser.Controller.Configuration;
|
|
||||||
using Emby.Dlna.Server;
|
|
||||||
using Emby.Dlna.Service;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using MediaBrowser.Model.Xml;
|
using Emby.Dlna.Service;
|
||||||
|
using MediaBrowser.Common.Extensions;
|
||||||
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Emby.Dlna.MediaReceiverRegistrar
|
namespace Emby.Dlna.MediaReceiverRegistrar
|
||||||
{
|
{
|
||||||
@@ -21,7 +19,7 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
|||||||
throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
|
throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<KeyValuePair<string, string>> HandleIsAuthorized()
|
private static IEnumerable<KeyValuePair<string, string>> HandleIsAuthorized()
|
||||||
{
|
{
|
||||||
return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||||
{
|
{
|
||||||
@@ -29,7 +27,7 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<KeyValuePair<string, string>> HandleIsValidated()
|
private static IEnumerable<KeyValuePair<string, string>> HandleIsValidated()
|
||||||
{
|
{
|
||||||
return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||||
{
|
{
|
||||||
@@ -37,7 +35,8 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public ControlHandler(IServerConfigurationManager config, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(config, logger, xmlReaderSettingsFactory)
|
public ControlHandler(IServerConfigurationManager config, ILogger logger)
|
||||||
|
: base(config, logger)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,21 @@
|
|||||||
using MediaBrowser.Common.Net;
|
|
||||||
using MediaBrowser.Controller.Configuration;
|
|
||||||
using MediaBrowser.Controller.Dlna;
|
|
||||||
using Emby.Dlna.Service;
|
using Emby.Dlna.Service;
|
||||||
|
using MediaBrowser.Common.Net;
|
||||||
|
using MediaBrowser.Controller.Configuration;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using MediaBrowser.Model.Xml;
|
|
||||||
|
|
||||||
namespace Emby.Dlna.MediaReceiverRegistrar
|
namespace Emby.Dlna.MediaReceiverRegistrar
|
||||||
{
|
{
|
||||||
public class MediaReceiverRegistrar : BaseService, IMediaReceiverRegistrar
|
public class MediaReceiverRegistrar : BaseService, IMediaReceiverRegistrar
|
||||||
{
|
{
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
protected readonly IXmlReaderSettingsFactory XmlReaderSettingsFactory;
|
|
||||||
|
|
||||||
public MediaReceiverRegistrar(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config, IXmlReaderSettingsFactory xmlReaderSettingsFactory)
|
public MediaReceiverRegistrar(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config)
|
||||||
: base(logger, httpClient)
|
: base(logger, httpClient)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
XmlReaderSettingsFactory = xmlReaderSettingsFactory;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetServiceXml(IDictionary<string, string> headers)
|
public string GetServiceXml()
|
||||||
{
|
{
|
||||||
return new MediaReceiverRegistrarXmlBuilder().GetXml();
|
return new MediaReceiverRegistrarXmlBuilder().GetXml();
|
||||||
}
|
}
|
||||||
@@ -30,7 +24,7 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
|||||||
{
|
{
|
||||||
return new ControlHandler(
|
return new ControlHandler(
|
||||||
_config,
|
_config,
|
||||||
Logger, XmlReaderSettingsFactory)
|
Logger)
|
||||||
.ProcessControlRequest(request);
|
.ProcessControlRequest(request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using Emby.Dlna.Common;
|
|
||||||
using Emby.Dlna.Service;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Emby.Dlna.Common;
|
||||||
|
using Emby.Dlna.Service;
|
||||||
|
|
||||||
namespace Emby.Dlna.MediaReceiverRegistrar
|
namespace Emby.Dlna.MediaReceiverRegistrar
|
||||||
{
|
{
|
||||||
@@ -12,7 +12,7 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
|||||||
GetStateVariables());
|
GetStateVariables());
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<StateVariable> GetStateVariables()
|
private static IEnumerable<StateVariable> GetStateVariables()
|
||||||
{
|
{
|
||||||
var list = new List<StateVariable>();
|
var list = new List<StateVariable>();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using Emby.Dlna.Common;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Emby.Dlna.Common;
|
||||||
|
|
||||||
namespace Emby.Dlna.MediaReceiverRegistrar
|
namespace Emby.Dlna.MediaReceiverRegistrar
|
||||||
{
|
{
|
||||||
@@ -7,7 +7,7 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
|||||||
{
|
{
|
||||||
public IEnumerable<ServiceAction> GetActions()
|
public IEnumerable<ServiceAction> GetActions()
|
||||||
{
|
{
|
||||||
return new []
|
return new[]
|
||||||
{
|
{
|
||||||
GetIsValidated(),
|
GetIsValidated(),
|
||||||
GetIsAuthorized(),
|
GetIsAuthorized(),
|
||||||
@@ -19,7 +19,7 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServiceAction GetIsValidated()
|
private static ServiceAction GetIsValidated()
|
||||||
{
|
{
|
||||||
var action = new ServiceAction
|
var action = new ServiceAction
|
||||||
{
|
{
|
||||||
@@ -41,7 +41,7 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
|||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServiceAction GetIsAuthorized()
|
private static ServiceAction GetIsAuthorized()
|
||||||
{
|
{
|
||||||
var action = new ServiceAction
|
var action = new ServiceAction
|
||||||
{
|
{
|
||||||
@@ -63,7 +63,7 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
|||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServiceAction GetRegisterDevice()
|
private static ServiceAction GetRegisterDevice()
|
||||||
{
|
{
|
||||||
var action = new ServiceAction
|
var action = new ServiceAction
|
||||||
{
|
{
|
||||||
@@ -85,7 +85,7 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
|||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServiceAction GetGetValidationSucceededUpdateID()
|
private static ServiceAction GetGetValidationSucceededUpdateID()
|
||||||
{
|
{
|
||||||
var action = new ServiceAction
|
var action = new ServiceAction
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Emby.Dlna.PlayTo
|
|
||||||
{
|
|
||||||
public class CurrentIdEventArgs : EventArgs
|
|
||||||
{
|
|
||||||
public string Id { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +1,17 @@
|
|||||||
using MediaBrowser.Common.Net;
|
|
||||||
using MediaBrowser.Controller.Configuration;
|
|
||||||
using Emby.Dlna.Common;
|
|
||||||
using Emby.Dlna.Ssdp;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using MediaBrowser.Model.Net;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
|
||||||
using System.Security;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
using Emby.Dlna.Common;
|
||||||
using Emby.Dlna.Server;
|
using Emby.Dlna.Server;
|
||||||
using MediaBrowser.Model.Threading;
|
using Emby.Dlna.Ssdp;
|
||||||
using MediaBrowser.Model.Extensions;
|
using MediaBrowser.Common.Net;
|
||||||
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Emby.Dlna.PlayTo
|
namespace Emby.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
@@ -23,7 +19,7 @@ namespace Emby.Dlna.PlayTo
|
|||||||
{
|
{
|
||||||
#region Fields & Properties
|
#region Fields & Properties
|
||||||
|
|
||||||
private ITimer _timer;
|
private Timer _timer;
|
||||||
|
|
||||||
public DeviceInfo Properties { get; set; }
|
public DeviceInfo Properties { get; set; }
|
||||||
|
|
||||||
@@ -39,52 +35,20 @@ namespace Emby.Dlna.PlayTo
|
|||||||
RefreshVolumeIfNeeded();
|
RefreshVolumeIfNeeded();
|
||||||
return _volume;
|
return _volume;
|
||||||
}
|
}
|
||||||
set
|
set => _volume = value;
|
||||||
{
|
|
||||||
_volume = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimeSpan? Duration { get; set; }
|
public TimeSpan? Duration { get; set; }
|
||||||
|
|
||||||
private TimeSpan _position = TimeSpan.FromSeconds(0);
|
public TimeSpan Position { get; set; } = TimeSpan.FromSeconds(0);
|
||||||
public TimeSpan Position
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _position;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_position = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public TRANSPORTSTATE TransportState { get; private set; }
|
public TRANSPORTSTATE TransportState { get; private set; }
|
||||||
|
|
||||||
public bool IsPlaying
|
public bool IsPlaying => TransportState == TRANSPORTSTATE.PLAYING;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return TransportState == TRANSPORTSTATE.PLAYING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsPaused
|
public bool IsPaused => TransportState == TRANSPORTSTATE.PAUSED || TransportState == TRANSPORTSTATE.PAUSED_PLAYBACK;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return TransportState == TRANSPORTSTATE.PAUSED || TransportState == TRANSPORTSTATE.PAUSED_PLAYBACK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsStopped
|
public bool IsStopped => TransportState == TRANSPORTSTATE.STOPPED;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return TransportState == TRANSPORTSTATE.STOPPED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -92,24 +56,20 @@ namespace Emby.Dlna.PlayTo
|
|||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
|
|
||||||
public DateTime DateLastActivity { get; private set; }
|
|
||||||
public Action OnDeviceUnavailable { get; set; }
|
public Action OnDeviceUnavailable { get; set; }
|
||||||
|
|
||||||
private readonly ITimerFactory _timerFactory;
|
public Device(DeviceInfo deviceProperties, IHttpClient httpClient, ILogger logger, IServerConfigurationManager config)
|
||||||
|
|
||||||
public Device(DeviceInfo deviceProperties, IHttpClient httpClient, ILogger logger, IServerConfigurationManager config, ITimerFactory timerFactory)
|
|
||||||
{
|
{
|
||||||
Properties = deviceProperties;
|
Properties = deviceProperties;
|
||||||
_httpClient = httpClient;
|
_httpClient = httpClient;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_config = config;
|
_config = config;
|
||||||
_timerFactory = timerFactory;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Dlna Device.Start");
|
_logger.LogDebug("Dlna Device.Start");
|
||||||
_timer = _timerFactory.Create(TimerCallback, null, 1000, Timeout.Infinite);
|
_timer = new Timer(TimerCallback, null, 1000, Timeout.Infinite);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DateTime _lastVolumeRefresh;
|
private DateTime _lastVolumeRefresh;
|
||||||
@@ -150,7 +110,9 @@ namespace Emby.Dlna.PlayTo
|
|||||||
lock (_timerLock)
|
lock (_timerLock)
|
||||||
{
|
{
|
||||||
if (_disposed)
|
if (_disposed)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_volumeRefreshActive = true;
|
_volumeRefreshActive = true;
|
||||||
|
|
||||||
@@ -167,7 +129,9 @@ namespace Emby.Dlna.PlayTo
|
|||||||
lock (_timerLock)
|
lock (_timerLock)
|
||||||
{
|
{
|
||||||
if (_disposed)
|
if (_disposed)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_volumeRefreshActive = false;
|
_volumeRefreshActive = false;
|
||||||
|
|
||||||
@@ -175,11 +139,6 @@ namespace Emby.Dlna.PlayTo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnPlaybackStartedExternally()
|
|
||||||
{
|
|
||||||
RestartTimer(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Commanding
|
#region Commanding
|
||||||
|
|
||||||
public Task VolumeDown(CancellationToken cancellationToken)
|
public Task VolumeDown(CancellationToken cancellationToken)
|
||||||
@@ -311,7 +270,7 @@ namespace Emby.Dlna.PlayTo
|
|||||||
throw new InvalidOperationException("Unable to find service");
|
throw new InvalidOperationException("Unable to find service");
|
||||||
}
|
}
|
||||||
|
|
||||||
await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, String.Format("{0:hh}:{0:mm}:{0:ss}", value), "REL_TIME"))
|
await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, string.Format("{0:hh}:{0:mm}:{0:ss}", value), "REL_TIME"))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
RestartTimer(true);
|
RestartTimer(true);
|
||||||
@@ -364,7 +323,9 @@ namespace Emby.Dlna.PlayTo
|
|||||||
private string CreateDidlMeta(string value)
|
private string CreateDidlMeta(string value)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(value))
|
if (string.IsNullOrEmpty(value))
|
||||||
return String.Empty;
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
return DescriptionXmlBuilder.Escape(value);
|
return DescriptionXmlBuilder.Escape(value);
|
||||||
}
|
}
|
||||||
@@ -373,10 +334,11 @@ namespace Emby.Dlna.PlayTo
|
|||||||
{
|
{
|
||||||
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "Play");
|
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "Play");
|
||||||
if (command == null)
|
if (command == null)
|
||||||
|
{
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
var service = GetAvTransportService();
|
var service = GetAvTransportService();
|
||||||
|
|
||||||
if (service == null)
|
if (service == null)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Unable to find service");
|
throw new InvalidOperationException("Unable to find service");
|
||||||
@@ -400,7 +362,9 @@ namespace Emby.Dlna.PlayTo
|
|||||||
|
|
||||||
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "Stop");
|
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "Stop");
|
||||||
if (command == null)
|
if (command == null)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var service = GetAvTransportService();
|
var service = GetAvTransportService();
|
||||||
|
|
||||||
@@ -416,7 +380,9 @@ namespace Emby.Dlna.PlayTo
|
|||||||
|
|
||||||
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "Pause");
|
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "Pause");
|
||||||
if (command == null)
|
if (command == null)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var service = GetAvTransportService();
|
var service = GetAvTransportService();
|
||||||
|
|
||||||
@@ -436,7 +402,9 @@ namespace Emby.Dlna.PlayTo
|
|||||||
private async void TimerCallback(object sender)
|
private async void TimerCallback(object sender)
|
||||||
{
|
{
|
||||||
if (_disposed)
|
if (_disposed)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -456,8 +424,6 @@ namespace Emby.Dlna.PlayTo
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DateLastActivity = DateTime.UtcNow;
|
|
||||||
|
|
||||||
if (transportState.HasValue)
|
if (transportState.HasValue)
|
||||||
{
|
{
|
||||||
// If we're not playing anything no need to get additional data
|
// If we're not playing anything no need to get additional data
|
||||||
@@ -536,7 +502,9 @@ namespace Emby.Dlna.PlayTo
|
|||||||
|
|
||||||
var command = rendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetVolume");
|
var command = rendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetVolume");
|
||||||
if (command == null)
|
if (command == null)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var service = GetServiceRenderingControl();
|
var service = GetServiceRenderingControl();
|
||||||
|
|
||||||
@@ -549,13 +517,17 @@ namespace Emby.Dlna.PlayTo
|
|||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (result == null || result.Document == null)
|
if (result == null || result.Document == null)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var volume = result.Document.Descendants(uPnpNamespaces.RenderingControl + "GetVolumeResponse").Select(i => i.Element("CurrentVolume")).FirstOrDefault(i => i != null);
|
var volume = result.Document.Descendants(uPnpNamespaces.RenderingControl + "GetVolumeResponse").Select(i => i.Element("CurrentVolume")).FirstOrDefault(i => i != null);
|
||||||
var volumeValue = volume == null ? null : volume.Value;
|
var volumeValue = volume?.Value;
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(volumeValue))
|
if (string.IsNullOrWhiteSpace(volumeValue))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Volume = int.Parse(volumeValue, UsCulture);
|
Volume = int.Parse(volumeValue, UsCulture);
|
||||||
|
|
||||||
@@ -576,7 +548,9 @@ namespace Emby.Dlna.PlayTo
|
|||||||
|
|
||||||
var command = rendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetMute");
|
var command = rendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetMute");
|
||||||
if (command == null)
|
if (command == null)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var service = GetServiceRenderingControl();
|
var service = GetServiceRenderingControl();
|
||||||
|
|
||||||
@@ -591,41 +565,44 @@ namespace Emby.Dlna.PlayTo
|
|||||||
if (result == null || result.Document == null)
|
if (result == null || result.Document == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var valueNode = result.Document.Descendants(uPnpNamespaces.RenderingControl + "GetMuteResponse").Select(i => i.Element("CurrentMute")).FirstOrDefault(i => i != null);
|
var valueNode = result.Document.Descendants(uPnpNamespaces.RenderingControl + "GetMuteResponse")
|
||||||
var value = valueNode == null ? null : valueNode.Value;
|
.Select(i => i.Element("CurrentMute"))
|
||||||
|
.FirstOrDefault(i => i != null);
|
||||||
|
|
||||||
IsMuted = string.Equals(value, "1", StringComparison.OrdinalIgnoreCase);
|
IsMuted = string.Equals(valueNode?.Value, "1", StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<TRANSPORTSTATE?> GetTransportInfo(TransportCommands avCommands, CancellationToken cancellationToken)
|
private async Task<TRANSPORTSTATE?> GetTransportInfo(TransportCommands avCommands, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetTransportInfo");
|
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetTransportInfo");
|
||||||
if (command == null)
|
if (command == null)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var service = GetAvTransportService();
|
var service = GetAvTransportService();
|
||||||
if (service == null)
|
if (service == null)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType), false)
|
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType), false)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (result == null || result.Document == null)
|
if (result == null || result.Document == null)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var transportState =
|
var transportState =
|
||||||
result.Document.Descendants(uPnpNamespaces.AvTransport + "GetTransportInfoResponse").Select(i => i.Element("CurrentTransportState")).FirstOrDefault(i => i != null);
|
result.Document.Descendants(uPnpNamespaces.AvTransport + "GetTransportInfoResponse").Select(i => i.Element("CurrentTransportState")).FirstOrDefault(i => i != null);
|
||||||
|
|
||||||
var transportStateValue = transportState == null ? null : transportState.Value;
|
var transportStateValue = transportState == null ? null : transportState.Value;
|
||||||
|
|
||||||
if (transportStateValue != null)
|
if (transportStateValue != null
|
||||||
|
&& Enum.TryParse(transportStateValue, true, out TRANSPORTSTATE state))
|
||||||
{
|
{
|
||||||
TRANSPORTSTATE state;
|
return state;
|
||||||
|
|
||||||
if (Enum.TryParse(transportStateValue, true, out state))
|
|
||||||
{
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -635,10 +612,11 @@ namespace Emby.Dlna.PlayTo
|
|||||||
{
|
{
|
||||||
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetMediaInfo");
|
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetMediaInfo");
|
||||||
if (command == null)
|
if (command == null)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var service = GetAvTransportService();
|
var service = GetAvTransportService();
|
||||||
|
|
||||||
if (service == null)
|
if (service == null)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Unable to find service");
|
throw new InvalidOperationException("Unable to find service");
|
||||||
@@ -650,7 +628,9 @@ namespace Emby.Dlna.PlayTo
|
|||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (result == null || result.Document == null)
|
if (result == null || result.Document == null)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var track = result.Document.Descendants("CurrentURIMetaData").FirstOrDefault();
|
var track = result.Document.Descendants("CurrentURIMetaData").FirstOrDefault();
|
||||||
|
|
||||||
@@ -690,11 +670,13 @@ namespace Emby.Dlna.PlayTo
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Tuple<bool, uBaseObject>> GetPositionInfo(TransportCommands avCommands, CancellationToken cancellationToken)
|
private async Task<(bool, uBaseObject)> GetPositionInfo(TransportCommands avCommands, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetPositionInfo");
|
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetPositionInfo");
|
||||||
if (command == null)
|
if (command == null)
|
||||||
return new Tuple<bool, uBaseObject>(false, null);
|
{
|
||||||
|
return (false, null);
|
||||||
|
}
|
||||||
|
|
||||||
var service = GetAvTransportService();
|
var service = GetAvTransportService();
|
||||||
|
|
||||||
@@ -709,7 +691,9 @@ namespace Emby.Dlna.PlayTo
|
|||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (result == null || result.Document == null)
|
if (result == null || result.Document == null)
|
||||||
return new Tuple<bool, uBaseObject>(false, null);
|
{
|
||||||
|
return (false, null);
|
||||||
|
}
|
||||||
|
|
||||||
var trackUriElem = result.Document.Descendants(uPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("TrackURI")).FirstOrDefault(i => i != null);
|
var trackUriElem = result.Document.Descendants(uPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("TrackURI")).FirstOrDefault(i => i != null);
|
||||||
var trackUri = trackUriElem == null ? null : trackUriElem.Value;
|
var trackUri = trackUriElem == null ? null : trackUriElem.Value;
|
||||||
@@ -717,8 +701,8 @@ namespace Emby.Dlna.PlayTo
|
|||||||
var durationElem = result.Document.Descendants(uPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("TrackDuration")).FirstOrDefault(i => i != null);
|
var durationElem = result.Document.Descendants(uPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("TrackDuration")).FirstOrDefault(i => i != null);
|
||||||
var duration = durationElem == null ? null : durationElem.Value;
|
var duration = durationElem == null ? null : durationElem.Value;
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(duration) &&
|
if (!string.IsNullOrWhiteSpace(duration)
|
||||||
!string.Equals(duration, "NOT_IMPLEMENTED", StringComparison.OrdinalIgnoreCase))
|
&& !string.Equals(duration, "NOT_IMPLEMENTED", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
Duration = TimeSpan.Parse(duration, UsCulture);
|
Duration = TimeSpan.Parse(duration, UsCulture);
|
||||||
}
|
}
|
||||||
@@ -740,50 +724,82 @@ namespace Emby.Dlna.PlayTo
|
|||||||
if (track == null)
|
if (track == null)
|
||||||
{
|
{
|
||||||
//If track is null, some vendors do this, use GetMediaInfo instead
|
//If track is null, some vendors do this, use GetMediaInfo instead
|
||||||
return new Tuple<bool, uBaseObject>(true, null);
|
return (true, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
var trackString = (string)track;
|
var trackString = (string)track;
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(trackString) || string.Equals(trackString, "NOT_IMPLEMENTED", StringComparison.OrdinalIgnoreCase))
|
if (string.IsNullOrWhiteSpace(trackString) || string.Equals(trackString, "NOT_IMPLEMENTED", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return new Tuple<bool, uBaseObject>(true, null);
|
return (true, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
XElement uPnpResponse;
|
XElement uPnpResponse = null;
|
||||||
|
|
||||||
// Handle different variations sent back by devices
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
uPnpResponse = XElement.Parse(trackString);
|
uPnpResponse = ParseResponse(trackString);
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// first try to add a root node with a dlna namesapce
|
_logger.LogError(ex, "Uncaught exception while parsing xml");
|
||||||
try
|
}
|
||||||
{
|
|
||||||
uPnpResponse = XElement.Parse("<data xmlns:dlna=\"urn:schemas-dlna-org:device-1-0\">" + trackString + "</data>");
|
if (uPnpResponse == null)
|
||||||
uPnpResponse = uPnpResponse.Descendants().First();
|
{
|
||||||
}
|
_logger.LogError("Failed to parse xml: \n {Xml}", trackString);
|
||||||
catch (Exception ex)
|
return (true, null);
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Unable to parse xml {0}", trackString);
|
|
||||||
return new Tuple<bool, uBaseObject>(true, null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var e = uPnpResponse.Element(uPnpNamespaces.items);
|
var e = uPnpResponse.Element(uPnpNamespaces.items);
|
||||||
|
|
||||||
var uTrack = CreateUBaseObject(e, trackUri);
|
var uTrack = CreateUBaseObject(e, trackUri);
|
||||||
|
|
||||||
return new Tuple<bool, uBaseObject>(true, uTrack);
|
return (true, uTrack);
|
||||||
|
}
|
||||||
|
|
||||||
|
private XElement ParseResponse(string xml)
|
||||||
|
{
|
||||||
|
// Handle different variations sent back by devices
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return XElement.Parse(xml);
|
||||||
|
}
|
||||||
|
catch (XmlException)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// first try to add a root node with a dlna namesapce
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return XElement.Parse("<data xmlns:dlna=\"urn:schemas-dlna-org:device-1-0\">" + xml + "</data>")
|
||||||
|
.Descendants()
|
||||||
|
.First();
|
||||||
|
}
|
||||||
|
catch (XmlException)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// some devices send back invalid xml
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return XElement.Parse(xml.Replace("&", "&"));
|
||||||
|
}
|
||||||
|
catch (XmlException)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static uBaseObject CreateUBaseObject(XElement container, string trackUri)
|
private static uBaseObject CreateUBaseObject(XElement container, string trackUri)
|
||||||
{
|
{
|
||||||
if (container == null)
|
if (container == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException("container");
|
throw new ArgumentNullException(nameof(container));
|
||||||
}
|
}
|
||||||
|
|
||||||
var url = container.GetValue(uPnpNamespaces.Res);
|
var url = container.GetValue(uPnpNamespaces.Res);
|
||||||
@@ -810,7 +826,7 @@ namespace Emby.Dlna.PlayTo
|
|||||||
{
|
{
|
||||||
if (container == null)
|
if (container == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException("container");
|
throw new ArgumentNullException(nameof(container));
|
||||||
}
|
}
|
||||||
|
|
||||||
var resElement = container.Element(uPnpNamespaces.Res);
|
var resElement = container.Element(uPnpNamespaces.Res);
|
||||||
@@ -834,11 +850,9 @@ namespace Emby.Dlna.PlayTo
|
|||||||
|
|
||||||
private async Task<TransportCommands> GetAVProtocolAsync(CancellationToken cancellationToken)
|
private async Task<TransportCommands> GetAVProtocolAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var avCommands = AvCommands;
|
if (AvCommands != null)
|
||||||
|
|
||||||
if (avCommands != null)
|
|
||||||
{
|
{
|
||||||
return avCommands;
|
return AvCommands;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_disposed)
|
if (_disposed)
|
||||||
@@ -858,18 +872,15 @@ namespace Emby.Dlna.PlayTo
|
|||||||
|
|
||||||
var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
|
var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
avCommands = TransportCommands.Create(document);
|
AvCommands = TransportCommands.Create(document);
|
||||||
AvCommands = avCommands;
|
return AvCommands;
|
||||||
return avCommands;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<TransportCommands> GetRenderingProtocolAsync(CancellationToken cancellationToken)
|
private async Task<TransportCommands> GetRenderingProtocolAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var rendererCommands = RendererCommands;
|
if (RendererCommands != null)
|
||||||
|
|
||||||
if (rendererCommands != null)
|
|
||||||
{
|
{
|
||||||
return rendererCommands;
|
return RendererCommands;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_disposed)
|
if (_disposed)
|
||||||
@@ -878,7 +889,6 @@ namespace Emby.Dlna.PlayTo
|
|||||||
}
|
}
|
||||||
|
|
||||||
var avService = GetServiceRenderingControl();
|
var avService = GetServiceRenderingControl();
|
||||||
|
|
||||||
if (avService == null)
|
if (avService == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Device AvService is null");
|
throw new ArgumentException("Device AvService is null");
|
||||||
@@ -890,9 +900,8 @@ namespace Emby.Dlna.PlayTo
|
|||||||
_logger.LogDebug("Dlna Device.GetRenderingProtocolAsync");
|
_logger.LogDebug("Dlna Device.GetRenderingProtocolAsync");
|
||||||
var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
|
var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
rendererCommands = TransportCommands.Create(document);
|
RendererCommands = TransportCommands.Create(document);
|
||||||
RendererCommands = rendererCommands;
|
return RendererCommands;
|
||||||
return rendererCommands;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string NormalizeUrl(string baseUrl, string url)
|
private string NormalizeUrl(string baseUrl, string url)
|
||||||
@@ -904,85 +913,103 @@ namespace Emby.Dlna.PlayTo
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!url.Contains("/"))
|
if (!url.Contains("/"))
|
||||||
|
{
|
||||||
url = "/dmr/" + url;
|
url = "/dmr/" + url;
|
||||||
|
}
|
||||||
|
|
||||||
if (!url.StartsWith("/"))
|
if (!url.StartsWith("/"))
|
||||||
|
{
|
||||||
url = "/" + url;
|
url = "/" + url;
|
||||||
|
}
|
||||||
|
|
||||||
return baseUrl + url;
|
return baseUrl + url;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TransportCommands AvCommands
|
private TransportCommands AvCommands { get; set; }
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TransportCommands RendererCommands
|
private TransportCommands RendererCommands { get; set; }
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClient httpClient, IServerConfigurationManager config, ILogger logger, ITimerFactory timerFactory, CancellationToken cancellationToken)
|
public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClient httpClient, IServerConfigurationManager config, ILogger logger, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var ssdpHttpClient = new SsdpHttpClient(httpClient, config);
|
var ssdpHttpClient = new SsdpHttpClient(httpClient, config);
|
||||||
|
|
||||||
var document = await ssdpHttpClient.GetDataAsync(url.ToString(), cancellationToken).ConfigureAwait(false);
|
var document = await ssdpHttpClient.GetDataAsync(url.ToString(), cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var deviceProperties = new DeviceInfo();
|
|
||||||
|
|
||||||
var friendlyNames = new List<string>();
|
var friendlyNames = new List<string>();
|
||||||
|
|
||||||
var name = document.Descendants(uPnpNamespaces.ud.GetName("friendlyName")).FirstOrDefault();
|
var name = document.Descendants(uPnpNamespaces.ud.GetName("friendlyName")).FirstOrDefault();
|
||||||
if (name != null && !string.IsNullOrWhiteSpace(name.Value))
|
if (name != null && !string.IsNullOrWhiteSpace(name.Value))
|
||||||
|
{
|
||||||
friendlyNames.Add(name.Value);
|
friendlyNames.Add(name.Value);
|
||||||
|
}
|
||||||
|
|
||||||
var room = document.Descendants(uPnpNamespaces.ud.GetName("roomName")).FirstOrDefault();
|
var room = document.Descendants(uPnpNamespaces.ud.GetName("roomName")).FirstOrDefault();
|
||||||
if (room != null && !string.IsNullOrWhiteSpace(room.Value))
|
if (room != null && !string.IsNullOrWhiteSpace(room.Value))
|
||||||
|
{
|
||||||
friendlyNames.Add(room.Value);
|
friendlyNames.Add(room.Value);
|
||||||
|
}
|
||||||
|
|
||||||
deviceProperties.Name = string.Join(" ", friendlyNames.ToArray());
|
var deviceProperties = new DeviceInfo()
|
||||||
|
{
|
||||||
|
Name = string.Join(" ", friendlyNames),
|
||||||
|
BaseUrl = string.Format("http://{0}:{1}", url.Host, url.Port)
|
||||||
|
};
|
||||||
|
|
||||||
var model = document.Descendants(uPnpNamespaces.ud.GetName("modelName")).FirstOrDefault();
|
var model = document.Descendants(uPnpNamespaces.ud.GetName("modelName")).FirstOrDefault();
|
||||||
if (model != null)
|
if (model != null)
|
||||||
|
{
|
||||||
deviceProperties.ModelName = model.Value;
|
deviceProperties.ModelName = model.Value;
|
||||||
|
}
|
||||||
|
|
||||||
var modelNumber = document.Descendants(uPnpNamespaces.ud.GetName("modelNumber")).FirstOrDefault();
|
var modelNumber = document.Descendants(uPnpNamespaces.ud.GetName("modelNumber")).FirstOrDefault();
|
||||||
if (modelNumber != null)
|
if (modelNumber != null)
|
||||||
|
{
|
||||||
deviceProperties.ModelNumber = modelNumber.Value;
|
deviceProperties.ModelNumber = modelNumber.Value;
|
||||||
|
}
|
||||||
|
|
||||||
var uuid = document.Descendants(uPnpNamespaces.ud.GetName("UDN")).FirstOrDefault();
|
var uuid = document.Descendants(uPnpNamespaces.ud.GetName("UDN")).FirstOrDefault();
|
||||||
if (uuid != null)
|
if (uuid != null)
|
||||||
|
{
|
||||||
deviceProperties.UUID = uuid.Value;
|
deviceProperties.UUID = uuid.Value;
|
||||||
|
}
|
||||||
|
|
||||||
var manufacturer = document.Descendants(uPnpNamespaces.ud.GetName("manufacturer")).FirstOrDefault();
|
var manufacturer = document.Descendants(uPnpNamespaces.ud.GetName("manufacturer")).FirstOrDefault();
|
||||||
if (manufacturer != null)
|
if (manufacturer != null)
|
||||||
|
{
|
||||||
deviceProperties.Manufacturer = manufacturer.Value;
|
deviceProperties.Manufacturer = manufacturer.Value;
|
||||||
|
}
|
||||||
|
|
||||||
var manufacturerUrl = document.Descendants(uPnpNamespaces.ud.GetName("manufacturerURL")).FirstOrDefault();
|
var manufacturerUrl = document.Descendants(uPnpNamespaces.ud.GetName("manufacturerURL")).FirstOrDefault();
|
||||||
if (manufacturerUrl != null)
|
if (manufacturerUrl != null)
|
||||||
|
{
|
||||||
deviceProperties.ManufacturerUrl = manufacturerUrl.Value;
|
deviceProperties.ManufacturerUrl = manufacturerUrl.Value;
|
||||||
|
}
|
||||||
|
|
||||||
var presentationUrl = document.Descendants(uPnpNamespaces.ud.GetName("presentationURL")).FirstOrDefault();
|
var presentationUrl = document.Descendants(uPnpNamespaces.ud.GetName("presentationURL")).FirstOrDefault();
|
||||||
if (presentationUrl != null)
|
if (presentationUrl != null)
|
||||||
|
{
|
||||||
deviceProperties.PresentationUrl = presentationUrl.Value;
|
deviceProperties.PresentationUrl = presentationUrl.Value;
|
||||||
|
}
|
||||||
|
|
||||||
var modelUrl = document.Descendants(uPnpNamespaces.ud.GetName("modelURL")).FirstOrDefault();
|
var modelUrl = document.Descendants(uPnpNamespaces.ud.GetName("modelURL")).FirstOrDefault();
|
||||||
if (modelUrl != null)
|
if (modelUrl != null)
|
||||||
|
{
|
||||||
deviceProperties.ModelUrl = modelUrl.Value;
|
deviceProperties.ModelUrl = modelUrl.Value;
|
||||||
|
}
|
||||||
|
|
||||||
var serialNumber = document.Descendants(uPnpNamespaces.ud.GetName("serialNumber")).FirstOrDefault();
|
var serialNumber = document.Descendants(uPnpNamespaces.ud.GetName("serialNumber")).FirstOrDefault();
|
||||||
if (serialNumber != null)
|
if (serialNumber != null)
|
||||||
|
{
|
||||||
deviceProperties.SerialNumber = serialNumber.Value;
|
deviceProperties.SerialNumber = serialNumber.Value;
|
||||||
|
}
|
||||||
|
|
||||||
var modelDescription = document.Descendants(uPnpNamespaces.ud.GetName("modelDescription")).FirstOrDefault();
|
var modelDescription = document.Descendants(uPnpNamespaces.ud.GetName("modelDescription")).FirstOrDefault();
|
||||||
if (modelDescription != null)
|
if (modelDescription != null)
|
||||||
|
{
|
||||||
deviceProperties.ModelDescription = modelDescription.Value;
|
deviceProperties.ModelDescription = modelDescription.Value;
|
||||||
|
}
|
||||||
deviceProperties.BaseUrl = String.Format("http://{0}:{1}", url.Host, url.Port);
|
|
||||||
|
|
||||||
var icon = document.Descendants(uPnpNamespaces.ud.GetName("icon")).FirstOrDefault();
|
var icon = document.Descendants(uPnpNamespaces.ud.GetName("icon")).FirstOrDefault();
|
||||||
|
|
||||||
if (icon != null)
|
if (icon != null)
|
||||||
{
|
{
|
||||||
deviceProperties.Icon = CreateIcon(icon);
|
deviceProperties.Icon = CreateIcon(icon);
|
||||||
@@ -991,12 +1018,15 @@ namespace Emby.Dlna.PlayTo
|
|||||||
foreach (var services in document.Descendants(uPnpNamespaces.ud.GetName("serviceList")))
|
foreach (var services in document.Descendants(uPnpNamespaces.ud.GetName("serviceList")))
|
||||||
{
|
{
|
||||||
if (services == null)
|
if (services == null)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
var servicesList = services.Descendants(uPnpNamespaces.ud.GetName("service"));
|
var servicesList = services.Descendants(uPnpNamespaces.ud.GetName("service"));
|
||||||
|
|
||||||
if (servicesList == null)
|
if (servicesList == null)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var element in servicesList)
|
foreach (var element in servicesList)
|
||||||
{
|
{
|
||||||
@@ -1009,9 +1039,7 @@ namespace Emby.Dlna.PlayTo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var device = new Device(deviceProperties, httpClient, logger, config, timerFactory);
|
return new Device(deviceProperties, httpClient, logger, config);
|
||||||
|
|
||||||
return device;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -1021,7 +1049,7 @@ namespace Emby.Dlna.PlayTo
|
|||||||
{
|
{
|
||||||
if (element == null)
|
if (element == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException("element");
|
throw new ArgumentNullException(nameof(element));
|
||||||
}
|
}
|
||||||
|
|
||||||
var mimeType = element.GetDescendantValue(uPnpNamespaces.ud.GetName("mimetype"));
|
var mimeType = element.GetDescendantValue(uPnpNamespaces.ud.GetName("mimetype"));
|
||||||
@@ -1098,82 +1126,80 @@ namespace Emby.Dlna.PlayTo
|
|||||||
|
|
||||||
private void OnPlaybackStart(uBaseObject mediaInfo)
|
private void OnPlaybackStart(uBaseObject mediaInfo)
|
||||||
{
|
{
|
||||||
if (PlaybackStart != null)
|
if (string.IsNullOrWhiteSpace(mediaInfo.Url))
|
||||||
{
|
|
||||||
PlaybackStart.Invoke(this, new PlaybackStartEventArgs
|
|
||||||
{
|
|
||||||
MediaInfo = mediaInfo
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPlaybackProgress(uBaseObject mediaInfo)
|
|
||||||
{
|
|
||||||
var mediaUrl = mediaInfo.Url;
|
|
||||||
if (string.IsNullOrWhiteSpace(mediaUrl))
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PlaybackProgress != null)
|
PlaybackStart?.Invoke(this, new PlaybackStartEventArgs
|
||||||
{
|
{
|
||||||
PlaybackProgress.Invoke(this, new PlaybackProgressEventArgs
|
MediaInfo = mediaInfo
|
||||||
{
|
});
|
||||||
MediaInfo = mediaInfo
|
}
|
||||||
});
|
|
||||||
|
private void OnPlaybackProgress(uBaseObject mediaInfo)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(mediaInfo.Url))
|
||||||
|
{
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PlaybackProgress?.Invoke(this, new PlaybackProgressEventArgs
|
||||||
|
{
|
||||||
|
MediaInfo = mediaInfo
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPlaybackStop(uBaseObject mediaInfo)
|
private void OnPlaybackStop(uBaseObject mediaInfo)
|
||||||
{
|
{
|
||||||
if (PlaybackStopped != null)
|
PlaybackStopped?.Invoke(this, new PlaybackStoppedEventArgs
|
||||||
{
|
{
|
||||||
PlaybackStopped.Invoke(this, new PlaybackStoppedEventArgs
|
MediaInfo = mediaInfo
|
||||||
{
|
});
|
||||||
MediaInfo = mediaInfo
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnMediaChanged(uBaseObject old, uBaseObject newMedia)
|
private void OnMediaChanged(uBaseObject old, uBaseObject newMedia)
|
||||||
{
|
{
|
||||||
if (MediaChanged != null)
|
MediaChanged?.Invoke(this, new MediaChangedEventArgs
|
||||||
{
|
{
|
||||||
MediaChanged.Invoke(this, new MediaChangedEventArgs
|
OldMediaInfo = old,
|
||||||
{
|
NewMediaInfo = newMedia
|
||||||
OldMediaInfo = old,
|
});
|
||||||
NewMediaInfo = newMedia
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region IDisposable
|
#region IDisposable
|
||||||
|
|
||||||
bool _disposed;
|
bool _disposed;
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (!_disposed)
|
Dispose(true);
|
||||||
{
|
GC.SuppressFinalize(this);
|
||||||
_disposed = true;
|
|
||||||
|
|
||||||
DisposeTimer();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DisposeTimer()
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (_timer != null)
|
if (_disposed)
|
||||||
{
|
{
|
||||||
_timer.Dispose();
|
return;
|
||||||
_timer = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
_timer?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
_timer = null;
|
||||||
|
Properties = null;
|
||||||
|
|
||||||
|
_disposed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return String.Format("{0} - {1}", Properties.Name, Properties.BaseUrl);
|
return string.Format("{0} - {1}", Properties.Name, Properties.BaseUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using Emby.Dlna.Common;
|
|
||||||
using MediaBrowser.Model.Dlna;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Emby.Dlna.Common;
|
||||||
|
using MediaBrowser.Model.Dlna;
|
||||||
|
|
||||||
namespace Emby.Dlna.PlayTo
|
namespace Emby.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
@@ -34,26 +34,14 @@ namespace Emby.Dlna.PlayTo
|
|||||||
private string _baseUrl = string.Empty;
|
private string _baseUrl = string.Empty;
|
||||||
public string BaseUrl
|
public string BaseUrl
|
||||||
{
|
{
|
||||||
get
|
get => _baseUrl;
|
||||||
{
|
set => _baseUrl = value;
|
||||||
return _baseUrl;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_baseUrl = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeviceIcon Icon { get; set; }
|
public DeviceIcon Icon { get; set; }
|
||||||
|
|
||||||
private readonly List<DeviceService> _services = new List<DeviceService>();
|
private readonly List<DeviceService> _services = new List<DeviceService>();
|
||||||
public List<DeviceService> Services
|
public List<DeviceService> Services => _services;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _services;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public DeviceIdentification ToDeviceIdentification()
|
public DeviceIdentification ToDeviceIdentification()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,28 +1,26 @@
|
|||||||
using MediaBrowser.Controller.Dlna;
|
|
||||||
using MediaBrowser.Controller.Drawing;
|
|
||||||
using MediaBrowser.Controller.Entities;
|
|
||||||
using MediaBrowser.Controller.Library;
|
|
||||||
using MediaBrowser.Controller.Session;
|
|
||||||
using Emby.Dlna.Didl;
|
|
||||||
using MediaBrowser.Model.Dlna;
|
|
||||||
using MediaBrowser.Model.Dto;
|
|
||||||
using MediaBrowser.Model.Entities;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using MediaBrowser.Model.Session;
|
|
||||||
using MediaBrowser.Model.System;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Emby.Dlna.Didl;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
|
using MediaBrowser.Common.Extensions;
|
||||||
|
using MediaBrowser.Controller.Dlna;
|
||||||
|
using MediaBrowser.Controller.Drawing;
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
|
using MediaBrowser.Controller.Session;
|
||||||
|
using MediaBrowser.Model.Dlna;
|
||||||
|
using MediaBrowser.Model.Dto;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Events;
|
using MediaBrowser.Model.Events;
|
||||||
using MediaBrowser.Model.Globalization;
|
using MediaBrowser.Model.Globalization;
|
||||||
using MediaBrowser.Model.Extensions;
|
using MediaBrowser.Model.Session;
|
||||||
using System.Net.Http;
|
using Microsoft.AspNetCore.WebUtilities;
|
||||||
using MediaBrowser.Model.Services;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Emby.Dlna.PlayTo
|
namespace Emby.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
@@ -45,39 +43,43 @@ namespace Emby.Dlna.PlayTo
|
|||||||
private readonly IDeviceDiscovery _deviceDiscovery;
|
private readonly IDeviceDiscovery _deviceDiscovery;
|
||||||
private readonly string _serverAddress;
|
private readonly string _serverAddress;
|
||||||
private readonly string _accessToken;
|
private readonly string _accessToken;
|
||||||
private readonly DateTime _creationTime;
|
|
||||||
|
|
||||||
public bool IsSessionActive
|
public bool IsSessionActive => !_disposed && _device != null;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return !_disposed && _device != null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SupportsMediaControl
|
public bool SupportsMediaControl => IsSessionActive;
|
||||||
{
|
|
||||||
get { return IsSessionActive; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public PlayToController(SessionInfo session, ISessionManager sessionManager, ILibraryManager libraryManager, ILogger logger, IDlnaManager dlnaManager, IUserManager userManager, IImageProcessor imageProcessor, string serverAddress, string accessToken, IDeviceDiscovery deviceDiscovery, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IConfigurationManager config, IMediaEncoder mediaEncoder)
|
public PlayToController(
|
||||||
|
SessionInfo session,
|
||||||
|
ISessionManager sessionManager,
|
||||||
|
ILibraryManager libraryManager,
|
||||||
|
ILogger logger,
|
||||||
|
IDlnaManager dlnaManager,
|
||||||
|
IUserManager userManager,
|
||||||
|
IImageProcessor imageProcessor,
|
||||||
|
string serverAddress,
|
||||||
|
string accessToken,
|
||||||
|
IDeviceDiscovery deviceDiscovery,
|
||||||
|
IUserDataManager userDataManager,
|
||||||
|
ILocalizationManager localization,
|
||||||
|
IMediaSourceManager mediaSourceManager,
|
||||||
|
IConfigurationManager config,
|
||||||
|
IMediaEncoder mediaEncoder)
|
||||||
{
|
{
|
||||||
_session = session;
|
_session = session;
|
||||||
_sessionManager = sessionManager;
|
_sessionManager = sessionManager;
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
|
_logger = logger;
|
||||||
_dlnaManager = dlnaManager;
|
_dlnaManager = dlnaManager;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_imageProcessor = imageProcessor;
|
_imageProcessor = imageProcessor;
|
||||||
_serverAddress = serverAddress;
|
_serverAddress = serverAddress;
|
||||||
|
_accessToken = accessToken;
|
||||||
_deviceDiscovery = deviceDiscovery;
|
_deviceDiscovery = deviceDiscovery;
|
||||||
_userDataManager = userDataManager;
|
_userDataManager = userDataManager;
|
||||||
_localization = localization;
|
_localization = localization;
|
||||||
_mediaSourceManager = mediaSourceManager;
|
_mediaSourceManager = mediaSourceManager;
|
||||||
_config = config;
|
_config = config;
|
||||||
_mediaEncoder = mediaEncoder;
|
_mediaEncoder = mediaEncoder;
|
||||||
_accessToken = accessToken;
|
|
||||||
_logger = logger;
|
|
||||||
_creationTime = DateTime.UtcNow;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Init(Device device)
|
public void Init(Device device)
|
||||||
@@ -100,9 +102,10 @@ namespace Emby.Dlna.PlayTo
|
|||||||
{
|
{
|
||||||
_sessionManager.ReportSessionEnded(_session.Id);
|
_sessionManager.ReportSessionEnded(_session.Id);
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// Could throw if the session is already gone
|
// Could throw if the session is already gone
|
||||||
|
_logger.LogError(ex, "Error reporting the end of session {Id}", _session.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,23 +113,14 @@ namespace Emby.Dlna.PlayTo
|
|||||||
{
|
{
|
||||||
var info = e.Argument;
|
var info = e.Argument;
|
||||||
|
|
||||||
string nts;
|
if (!_disposed
|
||||||
info.Headers.TryGetValue("NTS", out nts);
|
&& info.Headers.TryGetValue("USN", out string usn)
|
||||||
|
&& usn.IndexOf(_device.Properties.UUID, StringComparison.OrdinalIgnoreCase) != -1
|
||||||
string usn;
|
&& (usn.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) != -1
|
||||||
if (!info.Headers.TryGetValue("USN", out usn)) usn = String.Empty;
|
|| (info.Headers.TryGetValue("NT", out string nt)
|
||||||
|
&& nt.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) != -1)))
|
||||||
string nt;
|
|
||||||
if (!info.Headers.TryGetValue("NT", out nt)) nt = String.Empty;
|
|
||||||
|
|
||||||
if (usn.IndexOf(_device.Properties.UUID, StringComparison.OrdinalIgnoreCase) != -1 &&
|
|
||||||
!_disposed)
|
|
||||||
{
|
{
|
||||||
if (usn.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) != -1 ||
|
OnDeviceUnavailable();
|
||||||
nt.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) != -1)
|
|
||||||
{
|
|
||||||
OnDeviceUnavailable();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,9 +383,7 @@ namespace Emby.Dlna.PlayTo
|
|||||||
return _device.IsPaused ? _device.SetPlay(CancellationToken.None) : _device.SetPause(CancellationToken.None);
|
return _device.IsPaused ? _device.SetPlay(CancellationToken.None) : _device.SetPause(CancellationToken.None);
|
||||||
|
|
||||||
case PlaystateCommand.Seek:
|
case PlaystateCommand.Seek:
|
||||||
{
|
return Seek(command.SeekPositionTicks ?? 0);
|
||||||
return Seek(command.SeekPositionTicks ?? 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
case PlaystateCommand.NextTrack:
|
case PlaystateCommand.NextTrack:
|
||||||
return SetPlaylistIndex(_currentPlaylistIndex + 1);
|
return SetPlaylistIndex(_currentPlaylistIndex + 1);
|
||||||
@@ -439,13 +431,7 @@ namespace Emby.Dlna.PlayTo
|
|||||||
|
|
||||||
private int _currentPlaylistIndex;
|
private int _currentPlaylistIndex;
|
||||||
private readonly List<PlaylistItem> _playlist = new List<PlaylistItem>();
|
private readonly List<PlaylistItem> _playlist = new List<PlaylistItem>();
|
||||||
private List<PlaylistItem> Playlist
|
private List<PlaylistItem> Playlist => _playlist;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _playlist;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddItemFromId(Guid id, List<BaseItem> list)
|
private void AddItemFromId(Guid id, List<BaseItem> list)
|
||||||
{
|
{
|
||||||
@@ -463,8 +449,7 @@ namespace Emby.Dlna.PlayTo
|
|||||||
var profile = _dlnaManager.GetProfile(deviceInfo.ToDeviceIdentification()) ??
|
var profile = _dlnaManager.GetProfile(deviceInfo.ToDeviceIdentification()) ??
|
||||||
_dlnaManager.GetDefaultProfile();
|
_dlnaManager.GetDefaultProfile();
|
||||||
|
|
||||||
var hasMediaSources = item as IHasMediaSources;
|
var mediaSources = item is IHasMediaSources
|
||||||
var mediaSources = hasMediaSources != null
|
|
||||||
? (_mediaSourceManager.GetStaticMediaSources(item, true, user))
|
? (_mediaSourceManager.GetStaticMediaSources(item, true, user))
|
||||||
: new List<MediaSourceInfo>();
|
: new List<MediaSourceInfo>();
|
||||||
|
|
||||||
@@ -473,7 +458,7 @@ namespace Emby.Dlna.PlayTo
|
|||||||
|
|
||||||
playlistItem.StreamUrl = DidlBuilder.NormalizeDlnaMediaUrl(playlistItem.StreamInfo.ToUrl(_serverAddress, _accessToken));
|
playlistItem.StreamUrl = DidlBuilder.NormalizeDlnaMediaUrl(playlistItem.StreamInfo.ToUrl(_serverAddress, _accessToken));
|
||||||
|
|
||||||
var itemXml = new DidlBuilder(profile, user, _imageProcessor, _serverAddress, _accessToken, _userDataManager, _localization, _mediaSourceManager, _logger, _libraryManager, _mediaEncoder)
|
var itemXml = new DidlBuilder(profile, user, _imageProcessor, _serverAddress, _accessToken, _userDataManager, _localization, _mediaSourceManager, _logger, _mediaEncoder)
|
||||||
.GetItemDidl(_config.GetDlnaConfiguration(), item, user, null, _session.DeviceId, new Filter(), playlistItem.StreamInfo);
|
.GetItemDidl(_config.GetDlnaConfiguration(), item, user, null, _session.DeviceId, new Filter(), playlistItem.StreamInfo);
|
||||||
|
|
||||||
playlistItem.Didl = itemXml;
|
playlistItem.Didl = itemXml;
|
||||||
@@ -622,28 +607,38 @@ namespace Emby.Dlna.PlayTo
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (!_disposed)
|
Dispose(true);
|
||||||
{
|
GC.SuppressFinalize(this);
|
||||||
_disposed = true;
|
|
||||||
|
|
||||||
_device.PlaybackStart -= _device_PlaybackStart;
|
|
||||||
_device.PlaybackProgress -= _device_PlaybackProgress;
|
|
||||||
_device.PlaybackStopped -= _device_PlaybackStopped;
|
|
||||||
_device.MediaChanged -= _device_MediaChanged;
|
|
||||||
//_deviceDiscovery.DeviceLeft -= _deviceDiscovery_DeviceLeft;
|
|
||||||
_device.OnDeviceUnavailable = null;
|
|
||||||
|
|
||||||
_device.Dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (_disposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
_device.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
_device.PlaybackStart -= _device_PlaybackStart;
|
||||||
|
_device.PlaybackProgress -= _device_PlaybackProgress;
|
||||||
|
_device.PlaybackStopped -= _device_PlaybackStopped;
|
||||||
|
_device.MediaChanged -= _device_MediaChanged;
|
||||||
|
_deviceDiscovery.DeviceLeft -= _deviceDiscovery_DeviceLeft;
|
||||||
|
_device.OnDeviceUnavailable = null;
|
||||||
|
_device = null;
|
||||||
|
|
||||||
|
_disposed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly CultureInfo _usCulture = CultureInfo.ReadOnly(new CultureInfo("en-US"));
|
||||||
|
|
||||||
private Task SendGeneralCommand(GeneralCommand command, CancellationToken cancellationToken)
|
private Task SendGeneralCommand(GeneralCommand command, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
GeneralCommandType commandType;
|
if (Enum.TryParse(command.Name, true, out GeneralCommandType commandType))
|
||||||
|
|
||||||
if (Enum.TryParse(command.Name, true, out commandType))
|
|
||||||
{
|
{
|
||||||
switch (commandType)
|
switch (commandType)
|
||||||
{
|
{
|
||||||
@@ -659,13 +654,9 @@ namespace Emby.Dlna.PlayTo
|
|||||||
return _device.ToggleMute(cancellationToken);
|
return _device.ToggleMute(cancellationToken);
|
||||||
case GeneralCommandType.SetAudioStreamIndex:
|
case GeneralCommandType.SetAudioStreamIndex:
|
||||||
{
|
{
|
||||||
string arg;
|
if (command.Arguments.TryGetValue("Index", out string arg))
|
||||||
|
|
||||||
if (command.Arguments.TryGetValue("Index", out arg))
|
|
||||||
{
|
{
|
||||||
int val;
|
if (int.TryParse(arg, NumberStyles.Integer, _usCulture, out var val))
|
||||||
|
|
||||||
if (int.TryParse(arg, NumberStyles.Integer, _usCulture, out val))
|
|
||||||
{
|
{
|
||||||
return SetAudioStreamIndex(val);
|
return SetAudioStreamIndex(val);
|
||||||
}
|
}
|
||||||
@@ -677,13 +668,9 @@ namespace Emby.Dlna.PlayTo
|
|||||||
}
|
}
|
||||||
case GeneralCommandType.SetSubtitleStreamIndex:
|
case GeneralCommandType.SetSubtitleStreamIndex:
|
||||||
{
|
{
|
||||||
string arg;
|
if (command.Arguments.TryGetValue("Index", out string arg))
|
||||||
|
|
||||||
if (command.Arguments.TryGetValue("Index", out arg))
|
|
||||||
{
|
{
|
||||||
int val;
|
if (int.TryParse(arg, NumberStyles.Integer, _usCulture, out var val))
|
||||||
|
|
||||||
if (int.TryParse(arg, NumberStyles.Integer, _usCulture, out val))
|
|
||||||
{
|
{
|
||||||
return SetSubtitleStreamIndex(val);
|
return SetSubtitleStreamIndex(val);
|
||||||
}
|
}
|
||||||
@@ -695,13 +682,9 @@ namespace Emby.Dlna.PlayTo
|
|||||||
}
|
}
|
||||||
case GeneralCommandType.SetVolume:
|
case GeneralCommandType.SetVolume:
|
||||||
{
|
{
|
||||||
string arg;
|
if (command.Arguments.TryGetValue("Volume", out string arg))
|
||||||
|
|
||||||
if (command.Arguments.TryGetValue("Volume", out arg))
|
|
||||||
{
|
{
|
||||||
int volume;
|
if (int.TryParse(arg, NumberStyles.Integer, _usCulture, out var volume))
|
||||||
|
|
||||||
if (int.TryParse(arg, NumberStyles.Integer, _usCulture, out volume))
|
|
||||||
{
|
{
|
||||||
return _device.SetVolume(volume, cancellationToken);
|
return _device.SetVolume(volume, cancellationToken);
|
||||||
}
|
}
|
||||||
@@ -829,7 +812,7 @@ namespace Emby.Dlna.PlayTo
|
|||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(url))
|
if (string.IsNullOrEmpty(url))
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException("url");
|
throw new ArgumentNullException(nameof(url));
|
||||||
}
|
}
|
||||||
|
|
||||||
var parts = url.Split('/');
|
var parts = url.Split('/');
|
||||||
@@ -855,7 +838,7 @@ namespace Emby.Dlna.PlayTo
|
|||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(url))
|
if (string.IsNullOrEmpty(url))
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException("url");
|
throw new ArgumentNullException(nameof(url));
|
||||||
}
|
}
|
||||||
|
|
||||||
var request = new StreamParams
|
var request = new StreamParams
|
||||||
@@ -872,13 +855,13 @@ namespace Emby.Dlna.PlayTo
|
|||||||
if (index == -1) return request;
|
if (index == -1) return request;
|
||||||
|
|
||||||
var query = url.Substring(index + 1);
|
var query = url.Substring(index + 1);
|
||||||
QueryParamCollection values = MyHttpUtility.ParseQueryString(query);
|
Dictionary<string, string> values = QueryHelpers.ParseQuery(query).ToDictionary(kv => kv.Key, kv => kv.Value.ToString());
|
||||||
|
|
||||||
request.DeviceProfileId = values.Get("DeviceProfileId");
|
request.DeviceProfileId = values.GetValueOrDefault("DeviceProfileId");
|
||||||
request.DeviceId = values.Get("DeviceId");
|
request.DeviceId = values.GetValueOrDefault("DeviceId");
|
||||||
request.MediaSourceId = values.Get("MediaSourceId");
|
request.MediaSourceId = values.GetValueOrDefault("MediaSourceId");
|
||||||
request.LiveStreamId = values.Get("LiveStreamId");
|
request.LiveStreamId = values.GetValueOrDefault("LiveStreamId");
|
||||||
request.IsDirectStream = string.Equals("true", values.Get("Static"), StringComparison.OrdinalIgnoreCase);
|
request.IsDirectStream = string.Equals("true", values.GetValueOrDefault("Static"), StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
request.AudioStreamIndex = GetIntValue(values, "AudioStreamIndex");
|
request.AudioStreamIndex = GetIntValue(values, "AudioStreamIndex");
|
||||||
request.SubtitleStreamIndex = GetIntValue(values, "SubtitleStreamIndex");
|
request.SubtitleStreamIndex = GetIntValue(values, "SubtitleStreamIndex");
|
||||||
@@ -892,12 +875,11 @@ namespace Emby.Dlna.PlayTo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int? GetIntValue(QueryParamCollection values, string name)
|
private static int? GetIntValue(IReadOnlyDictionary<string, string> values, string name)
|
||||||
{
|
{
|
||||||
var value = values.Get(name);
|
var value = values.GetValueOrDefault(name);
|
||||||
|
|
||||||
int result;
|
if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
|
||||||
if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out result))
|
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -905,12 +887,11 @@ namespace Emby.Dlna.PlayTo
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long GetLongValue(QueryParamCollection values, string name)
|
private static long GetLongValue(IReadOnlyDictionary<string, string> values, string name)
|
||||||
{
|
{
|
||||||
var value = values.Get(name);
|
var value = values.GetValueOrDefault(name);
|
||||||
|
|
||||||
long result;
|
if (long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
|
||||||
if (long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out result))
|
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user