mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-12-10 11:03:04 +03:00
Compare commits
974 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aadff77531 | ||
|
|
89fc5aa11a | ||
|
|
cb91595a24 | ||
|
|
6233bae7f0 | ||
|
|
623c0b6daa | ||
|
|
d8d37671ff | ||
|
|
9e89cbbc3a | ||
|
|
72bf920291 | ||
|
|
8dbb1c9257 | ||
|
|
2f0b4cc24c | ||
|
|
a0fdceb4bc | ||
|
|
86190aa7e9 | ||
|
|
f8b391538d | ||
|
|
acf1698d2b | ||
|
|
26c778eb16 | ||
|
|
cbd1e92486 | ||
|
|
01b51388f5 | ||
|
|
b4e81f2f0c | ||
|
|
d38eab50ef | ||
|
|
796bdd46df | ||
|
|
ae9948ce04 | ||
|
|
3d563ca3a3 | ||
|
|
1295f6c79b | ||
|
|
adc3ab1991 | ||
|
|
7ecb16a46e | ||
|
|
2610bb2cc1 | ||
|
|
e0381c8854 | ||
|
|
e8c593f413 | ||
|
|
f3db3cacf6 | ||
|
|
b373721d29 | ||
|
|
4c2b543b30 | ||
|
|
6660006f01 | ||
|
|
1a9908d094 | ||
|
|
f2fdf50b3b | ||
|
|
5a0f1fe848 | ||
|
|
098d3538e3 | ||
|
|
d4564d8e29 | ||
|
|
b99a5843dd | ||
|
|
e36c4de9f6 | ||
|
|
216e425cc5 | ||
|
|
55b429e5e8 | ||
|
|
ccafebca68 | ||
|
|
ecaa7f8014 | ||
|
|
66e11879ef | ||
|
|
dcf3dbb250 | ||
|
|
9eef0e8ca0 | ||
|
|
ca585f12b3 | ||
|
|
acd67c7152 | ||
|
|
e80c9bb8c6 | ||
|
|
375cf212dd | ||
|
|
434f665e81 | ||
|
|
be1d4b32c6 | ||
|
|
ada3f96668 | ||
|
|
7931a7a7d0 | ||
|
|
a987b68f7c | ||
|
|
3016e78aef | ||
|
|
0e98d8bbad | ||
|
|
5276c75cde | ||
|
|
c07e1e4f84 | ||
|
|
2dc1a18203 | ||
|
|
c1aafd2ba0 | ||
|
|
20ac3c36e2 | ||
|
|
464039043d | ||
|
|
a4bf645ba5 | ||
|
|
9a6c279473 | ||
|
|
c376f4ca51 | ||
|
|
76e49a1eb7 | ||
|
|
1c1484389a | ||
|
|
1c21248e2e | ||
|
|
13d30a0a79 | ||
|
|
ba8d8cede9 | ||
|
|
9a9f2aa293 | ||
|
|
376bbb40bd | ||
|
|
3ab51712b8 | ||
|
|
1204818698 | ||
|
|
41a26f8ecd | ||
|
|
f00356e9fe | ||
|
|
49f6809254 | ||
|
|
0b0c5984f9 | ||
|
|
03a294a706 | ||
|
|
d86e5c2ab7 | ||
|
|
630d79fc96 | ||
|
|
2e856ad9fe | ||
|
|
6261e4e7f6 | ||
|
|
77963c7a8c | ||
|
|
7f38af3701 | ||
|
|
f81cd037f0 | ||
|
|
ae1f975b99 | ||
|
|
0f0b89f344 | ||
|
|
e125db4fe3 | ||
|
|
e80444d11b | ||
|
|
d1670f8180 | ||
|
|
8e20d2e931 | ||
|
|
13bf5e94b3 | ||
|
|
107974e3f8 | ||
|
|
9d53fd0e73 | ||
|
|
fd3ee279de | ||
|
|
6c6b5d7f28 | ||
|
|
f11678ae4b | ||
|
|
a075fefca9 | ||
|
|
4ae80a5d56 | ||
|
|
b40ac479a2 | ||
|
|
3e2f09ecf8 | ||
|
|
6b634026e6 | ||
|
|
697aee5b0c | ||
|
|
940990708e | ||
|
|
19a609a889 | ||
|
|
a34826008f | ||
|
|
0a55eb9106 | ||
|
|
a3bb81553d | ||
|
|
de40f22a46 | ||
|
|
496bdc65f3 | ||
|
|
fd5f0c54a6 | ||
|
|
b306b8b881 | ||
|
|
4dabc50f09 | ||
|
|
c2fe628c79 | ||
|
|
72c98e41ca | ||
|
|
21f11c600a | ||
|
|
6e239c52c5 | ||
|
|
6715450598 | ||
|
|
ffc9eb67f0 | ||
|
|
4becaf83dd | ||
|
|
65a9d618cc | ||
|
|
804ca0543b | ||
|
|
583f171f9e | ||
|
|
557b165f01 | ||
|
|
4355b453d4 | ||
|
|
61015c1d0f | ||
|
|
eb67117b83 | ||
|
|
b02a3a29f5 | ||
|
|
28cc210a5e | ||
|
|
d240321e87 | ||
|
|
b2bf0f1796 | ||
|
|
107e43aaac | ||
|
|
7df6d4e7a0 | ||
|
|
c73370ad92 | ||
|
|
adc9fc282c | ||
|
|
dfd74adc15 | ||
|
|
620047ab9a | ||
|
|
0f173e1778 | ||
|
|
184ad29f3f | ||
|
|
3bd7633cbf | ||
|
|
a9e744bea0 | ||
|
|
3d9dc59554 | ||
|
|
f4d0fa8dc8 | ||
|
|
d6971581d6 | ||
|
|
0f2ee2686d | ||
|
|
b16ba7d985 | ||
|
|
7005326685 | ||
|
|
4d0ee3f6cc | ||
|
|
39b6d6586f | ||
|
|
8f5ffba29f | ||
|
|
a4e0364139 | ||
|
|
b375aeb56a | ||
|
|
967f8c6dcd | ||
|
|
5fed4d10ab | ||
|
|
a62196afc7 | ||
|
|
cef796a5ba | ||
|
|
a68d4396e5 | ||
|
|
b672d105b6 | ||
|
|
e2a36a5b14 | ||
|
|
6783878711 | ||
|
|
b6ae5242c5 | ||
|
|
d7f199bb1c | ||
|
|
3bc0ce070d | ||
|
|
0387c73d64 | ||
|
|
ae049f7fc8 | ||
|
|
6b4f1f3b5b | ||
|
|
0591d118f9 | ||
|
|
eff8d2466e | ||
|
|
dcac99c1a4 | ||
|
|
63f13df6fc | ||
|
|
53db526667 | ||
|
|
cf2626428c | ||
|
|
407ba755f1 | ||
|
|
8ee917143f | ||
|
|
40ad6f843f | ||
|
|
f5db4c8402 | ||
|
|
64800de29d | ||
|
|
8ffb073ccb | ||
|
|
a2490a7ae5 | ||
|
|
33761c3658 | ||
|
|
e241f83ff1 | ||
|
|
a26c1ab17d | ||
|
|
42066ee326 | ||
|
|
684568e6d2 | ||
|
|
6813efd1a2 | ||
|
|
a7c7d536a7 | ||
|
|
00073c162a | ||
|
|
662e1164c9 | ||
|
|
fd55164410 | ||
|
|
b5342bb7d9 | ||
|
|
8fb86cb5ff | ||
|
|
e47185160e | ||
|
|
8acfc264fc | ||
|
|
a381eb884c | ||
|
|
422c440743 | ||
|
|
4d324046ac | ||
|
|
867835a474 | ||
|
|
f96bc23c4f | ||
|
|
77428d338d | ||
|
|
e7dcaa7d08 | ||
|
|
75d6545145 | ||
|
|
81396a11cb | ||
|
|
ab59848d92 | ||
|
|
a73ce1d781 | ||
|
|
c3f749ec66 | ||
|
|
7060934792 | ||
|
|
cefac4f886 | ||
|
|
1ae9ed6e2a | ||
|
|
0a43814596 | ||
|
|
3fe84c3213 | ||
|
|
22510909fb | ||
|
|
df739b5b2f | ||
|
|
d5fcca3d05 | ||
|
|
1cb51a8ac7 | ||
|
|
a954d5e953 | ||
|
|
c2733ac0dc | ||
|
|
e8984ed3a9 | ||
|
|
ebd0771dca | ||
|
|
e3c64b9fee | ||
|
|
9af149b02d | ||
|
|
91707f13a8 | ||
|
|
6a6472bb8a | ||
|
|
ba1ffbabd3 | ||
|
|
c9e11c95ee | ||
|
|
3b6a4c3a33 | ||
|
|
32dcd372f4 | ||
|
|
f47ad85011 | ||
|
|
176e850973 | ||
|
|
f93edb7ade | ||
|
|
241e351a61 | ||
|
|
b7a9900556 | ||
|
|
fe325a6e73 | ||
|
|
ba724f158c | ||
|
|
c1ecd886d9 | ||
|
|
c149fcb3ee | ||
|
|
2c3b1bb8cb | ||
|
|
7472ae5ca9 | ||
|
|
8eced835c0 | ||
|
|
4302f16925 | ||
|
|
78bb45e8fa | ||
|
|
021427d881 | ||
|
|
994481213f | ||
|
|
1bc8ca2542 | ||
|
|
26dd67a441 | ||
|
|
6341d986a9 | ||
|
|
87c5047b13 | ||
|
|
692a9bfdd0 | ||
|
|
7df6f8d54e | ||
|
|
afe9ed977b | ||
|
|
ab2349ff3c | ||
|
|
70bc03c795 | ||
|
|
acc1846e3e | ||
|
|
71abf1d3ce | ||
|
|
87d2479b78 | ||
|
|
cd13f718fb | ||
|
|
6cd9c84ddf | ||
|
|
b3811a9498 | ||
|
|
a3615dec69 | ||
|
|
d69870680b | ||
|
|
d4470b5709 | ||
|
|
a012a4574f | ||
|
|
2186df8ac4 | ||
|
|
81fae5932b | ||
|
|
1ff74dd8f0 | ||
|
|
f7b4dfc1cb | ||
|
|
6ee04855cd | ||
|
|
ae9c1e29e7 | ||
|
|
acfacabf0c | ||
|
|
36d62c3093 | ||
|
|
84fbf64867 | ||
|
|
6b68521bae | ||
|
|
fc578de3b3 | ||
|
|
0a95c3a1c2 | ||
|
|
71bdcd7307 | ||
|
|
04b9e94c7c | ||
|
|
1ed92b05fb | ||
|
|
8c520160cc | ||
|
|
b5be0c567f | ||
|
|
bade35958a | ||
|
|
3a338c1899 | ||
|
|
918df5e352 | ||
|
|
d6786c7304 | ||
|
|
e58aa57ed7 | ||
|
|
ad5081f276 | ||
|
|
eb04126473 | ||
|
|
4f3bfd9146 | ||
|
|
d3de91dab6 | ||
|
|
48e9c004b4 | ||
|
|
8ff07e17e6 | ||
|
|
c751ba9f70 | ||
|
|
c8409d2ea1 | ||
|
|
dc62e436c4 | ||
|
|
82112b6788 | ||
|
|
6eac7f0fa7 | ||
|
|
1dd4abebbd | ||
|
|
5340eb9363 | ||
|
|
ddf9b38799 | ||
|
|
ac3b958c67 | ||
|
|
d4de78693f | ||
|
|
f23434f4f7 | ||
|
|
4abcbc66be | ||
|
|
ef487441d1 | ||
|
|
11c758b6be | ||
|
|
2f8f064a23 | ||
|
|
da2c998e28 | ||
|
|
075dad8720 | ||
|
|
f2eea89ff0 | ||
|
|
a562a4d505 | ||
|
|
e700fc8a07 | ||
|
|
c618f3f8eb | ||
|
|
1e65cc4695 | ||
|
|
2610f377c0 | ||
|
|
549a2d8b6d | ||
|
|
8e71046a3c | ||
|
|
73a47e934d | ||
|
|
c601def484 | ||
|
|
686d1ff9fb | ||
|
|
47d3337124 | ||
|
|
0cbae4a06d | ||
|
|
bdbf7a69f6 | ||
|
|
1cb142fbab | ||
|
|
dcd6ceb9a2 | ||
|
|
f3a1729964 | ||
|
|
ad481322f6 | ||
|
|
88d66d5f5c | ||
|
|
e882b03e81 | ||
|
|
96c9af5904 | ||
|
|
bc4c67e6fa | ||
|
|
2ce16d4bb5 | ||
|
|
0a7ea36c68 | ||
|
|
e92e105c42 | ||
|
|
ac0b30285e | ||
|
|
15c52867ea | ||
|
|
42213d94e5 | ||
|
|
d4745957b3 | ||
|
|
4aa0b940e3 | ||
|
|
884c3e5614 | ||
|
|
3b3718e437 | ||
|
|
2cad58e5cd | ||
|
|
ec8baaf48d | ||
|
|
2c10891b66 | ||
|
|
8868ff2ffa | ||
|
|
67cae37308 | ||
|
|
1ad6f01617 | ||
|
|
9aa870cf24 | ||
|
|
d3bd22d7a2 | ||
|
|
3ab979c6ba | ||
|
|
22f408201a | ||
|
|
da91b4fa4c | ||
|
|
c6484c0220 | ||
|
|
b1e76db21e | ||
|
|
d43d39f9b8 | ||
|
|
c1350f30d2 | ||
|
|
cd5e5cda61 | ||
|
|
402691b5e1 | ||
|
|
facbd87cfc | ||
|
|
65fe243afb | ||
|
|
138bff4327 | ||
|
|
ab0130e9e2 | ||
|
|
7b91df1994 | ||
|
|
faf898ea0d | ||
|
|
31347de792 | ||
|
|
9c2c31b0c6 | ||
|
|
536237c35d | ||
|
|
d461f46bef | ||
|
|
9eac19c75a | ||
|
|
cf13e89ad6 | ||
|
|
665ca5cf1f | ||
|
|
d00fd7ca82 | ||
|
|
65e9a705d3 | ||
|
|
a8cd963d46 | ||
|
|
c3efcbf77e | ||
|
|
56f580cdf6 | ||
|
|
93ab829df5 | ||
|
|
84d1b12530 | ||
|
|
da5893b0f1 | ||
|
|
ce7744806c | ||
|
|
ea075c1b48 | ||
|
|
ded9857f45 | ||
|
|
d217f1614e | ||
|
|
2a09f05ff3 | ||
|
|
08c4d3797f | ||
|
|
081d942d03 | ||
|
|
9f5bbb126e | ||
|
|
abf03f7d3a | ||
|
|
ec0ef2a2c5 | ||
|
|
cd0592ea8f | ||
|
|
dd254eddac | ||
|
|
b1dc595be1 | ||
|
|
a647dc5705 | ||
|
|
a272638a84 | ||
|
|
bca48b5d5c | ||
|
|
d63debd008 | ||
|
|
801c356d66 | ||
|
|
dd7feacd34 | ||
|
|
0d6a4c2909 | ||
|
|
aca4d678a2 | ||
|
|
fa1aeeb18a | ||
|
|
d9ec502ff9 | ||
|
|
bb236b9591 | ||
|
|
e714b9930e | ||
|
|
e95239e281 | ||
|
|
0a39e54984 | ||
|
|
81ae6d8afd | ||
|
|
0a92200c6f | ||
|
|
c3ff4e0b9f | ||
|
|
64baca9fac | ||
|
|
b50c4938e1 | ||
|
|
a40cb7bbd8 | ||
|
|
312987aea5 | ||
|
|
654336990f | ||
|
|
d328fc51cf | ||
|
|
6792fa111e | ||
|
|
1ea613a9bd | ||
|
|
1fecb9efb2 | ||
|
|
fdbb329118 | ||
|
|
d5204f572a | ||
|
|
162c1ac7b7 | ||
|
|
140673fcf6 | ||
|
|
43c76b48c9 | ||
|
|
b1af8a4178 | ||
|
|
277e9d2b0b | ||
|
|
c3752b1a30 | ||
|
|
124a852787 | ||
|
|
75f19a762c | ||
|
|
423d50e978 | ||
|
|
73fac50e57 | ||
|
|
8a0ef41036 | ||
|
|
a253fa616d | ||
|
|
aca31457c0 | ||
|
|
9dfafb9e9f | ||
|
|
49fef5f09c | ||
|
|
534716d9c9 | ||
|
|
70210b47a4 | ||
|
|
e5c68834a3 | ||
|
|
f48269a319 | ||
|
|
80dfc78ba5 | ||
|
|
a4d0e4b38e | ||
|
|
0a483c83f9 | ||
|
|
a21645d6be | ||
|
|
21b78f44c8 | ||
|
|
65f65db8b9 | ||
|
|
2ca7200a05 | ||
|
|
5b55997984 | ||
|
|
d599124508 | ||
|
|
c7d5f35eb7 | ||
|
|
303385dfa2 | ||
|
|
f1008ab58d | ||
|
|
e5e0166951 | ||
|
|
0b592376d5 | ||
|
|
aa7aadb2b2 | ||
|
|
aac0a1ed26 | ||
|
|
77a9ebf13f | ||
|
|
2497573b7f | ||
|
|
5cd8338e73 | ||
|
|
295eaa2ccb | ||
|
|
5994328903 | ||
|
|
09d1f976d9 | ||
|
|
59cdfdc2d9 | ||
|
|
d756233f62 | ||
|
|
653610d578 | ||
|
|
fb61a1f882 | ||
|
|
d3bce6e380 | ||
|
|
72d2b5910a | ||
|
|
c62599f873 | ||
|
|
529cff3920 | ||
|
|
c10cb66169 | ||
|
|
167549f5f1 | ||
|
|
e476125cf8 | ||
|
|
f672ecbac5 | ||
|
|
49330e3082 | ||
|
|
ab57b504fe | ||
|
|
49ce876c2c | ||
|
|
d7164d2eb7 | ||
|
|
b3963058db | ||
|
|
5bf0eb2b0e | ||
|
|
ef62df69df | ||
|
|
a41ec5c9d4 | ||
|
|
a22f1dabb4 | ||
|
|
d1461b4238 | ||
|
|
00c6d392a1 | ||
|
|
ef75455178 | ||
|
|
8d06d0dbdf | ||
|
|
8c4e679ff4 | ||
|
|
f9a454628d | ||
|
|
cf2e2a3f30 | ||
|
|
57aec873d0 | ||
|
|
f47c7959af | ||
|
|
c2db45bad9 | ||
|
|
1bab76d80c | ||
|
|
0e920a6d5f | ||
|
|
963b69c7b2 | ||
|
|
82911c8a20 | ||
|
|
b87750d8e0 | ||
|
|
5751d86536 | ||
|
|
5dc3874ebd | ||
|
|
94d3dda324 | ||
|
|
d720d8f356 | ||
|
|
7f5a174dff | ||
|
|
6a6e02e1ec | ||
|
|
137db45fc7 | ||
|
|
ce8754d052 | ||
|
|
1f323683b3 | ||
|
|
bb62dd14c2 | ||
|
|
06dfa2e687 | ||
|
|
a5cd11735c | ||
|
|
eb12754fc5 | ||
|
|
5c9e849b85 | ||
|
|
a1ca50fd5a | ||
|
|
8723bdbb4f | ||
|
|
bc7cbfb21a | ||
|
|
0f444c21e9 | ||
|
|
742d84e53f | ||
|
|
91562a4392 | ||
|
|
6b185119aa | ||
|
|
d2e9ce7644 | ||
|
|
b626508bc8 | ||
|
|
f3e7c72bac | ||
|
|
b31f4ccbc2 | ||
|
|
db61a58c39 | ||
|
|
dda431dff1 | ||
|
|
6fb7999a14 | ||
|
|
a7a4974d95 | ||
|
|
c6851bd72c | ||
|
|
5a9e08e0de | ||
|
|
4e43c70439 | ||
|
|
c96d3c35a0 | ||
|
|
0d571b3ad1 | ||
|
|
2457e43dec | ||
|
|
46442e24f8 | ||
|
|
3fb7aabfde | ||
|
|
64c313a8fb | ||
|
|
77fc77eb82 | ||
|
|
1443583a41 | ||
|
|
be956dfd02 | ||
|
|
61b9845e0f | ||
|
|
d063300af4 | ||
|
|
b8c61a5c40 | ||
|
|
d79242c3c7 | ||
|
|
28e922326d | ||
|
|
3924df9c51 | ||
|
|
d9c0721e3d | ||
|
|
47805d89fe | ||
|
|
4c30557527 | ||
|
|
f7eef1aa7f | ||
|
|
623e85a9e4 | ||
|
|
831d1daa68 | ||
|
|
c1c1672d0f | ||
|
|
c05933234a | ||
|
|
2c3e1b8562 | ||
|
|
b8c8d45b8d | ||
|
|
c824c564cd | ||
|
|
1b2453b4e9 | ||
|
|
02928128b9 | ||
|
|
bafcadbe58 | ||
|
|
d0febd6c37 | ||
|
|
802a66a9e6 | ||
|
|
867b61025d | ||
|
|
f18d3ed33b | ||
|
|
c36467c496 | ||
|
|
0cf9e59d5a | ||
|
|
88928118eb | ||
|
|
5a8e972952 | ||
|
|
54dbdc695a | ||
|
|
dc32050a2e | ||
|
|
7e987b9642 | ||
|
|
6231fc18ea | ||
|
|
55317b5c74 | ||
|
|
12bb4a92eb | ||
|
|
554c967dd6 | ||
|
|
a2462704d1 | ||
|
|
a4ca259a64 | ||
|
|
6464bca791 | ||
|
|
2c0259f920 | ||
|
|
baadb504bb | ||
|
|
96a5dda9ff | ||
|
|
9744f5aee3 | ||
|
|
421092b478 | ||
|
|
1e0967f43c | ||
|
|
2ef4ffd698 | ||
|
|
0bf8bfbb0c | ||
|
|
b98e25a07e | ||
|
|
b20b648659 | ||
|
|
f1fc6ef59f | ||
|
|
67922dff50 | ||
|
|
2a7210ca28 | ||
|
|
19844a2c2a | ||
|
|
affb58ef9e | ||
|
|
dee3076eaf | ||
|
|
b5d0bd0d76 | ||
|
|
1b5da55ae5 | ||
|
|
f25c1e40d4 | ||
|
|
cf1eb2798c | ||
|
|
7d4c4c369e | ||
|
|
f0dbcfca6e | ||
|
|
52f31775fc | ||
|
|
4fa8f9ccfe | ||
|
|
1cec41baf8 | ||
|
|
ec70f3ac75 | ||
|
|
c8f403238e | ||
|
|
408cf017a4 | ||
|
|
5b5d527a09 | ||
|
|
68edb9734d | ||
|
|
6f283d80dc | ||
|
|
803ec15150 | ||
|
|
35151553e3 | ||
|
|
8befab5b5d | ||
|
|
a2c35e6dba | ||
|
|
94edb5b9f9 | ||
|
|
935525e77a | ||
|
|
75426d0004 | ||
|
|
3f43aef997 | ||
|
|
535390bb64 | ||
|
|
a9766992b7 | ||
|
|
9ee0804407 | ||
|
|
7d2bfabb32 | ||
|
|
8368815788 | ||
|
|
caa57d5bda | ||
|
|
8694577c71 | ||
|
|
8718e1ea6b | ||
|
|
5f6bca8aeb | ||
|
|
a6f883345f | ||
|
|
e05c02263a | ||
|
|
e41dd316d1 | ||
|
|
7cde256402 | ||
|
|
82575db662 | ||
|
|
fccc90ae1a | ||
|
|
fc4bbee39f | ||
|
|
9144c84dc9 | ||
|
|
5234c686e7 | ||
|
|
7d2f066cd4 | ||
|
|
383733044f | ||
|
|
70530e1f14 | ||
|
|
3d8f3da5d6 | ||
|
|
78a161138f | ||
|
|
89605d4fb1 | ||
|
|
a7ef1aa7ec | ||
|
|
4a0df15bbd | ||
|
|
f7d71a2bc7 | ||
|
|
5cab79c839 | ||
|
|
e44a7ae3f6 | ||
|
|
903752b77b | ||
|
|
df10cf8012 | ||
|
|
caca2b31fe | ||
|
|
01c5dcea77 | ||
|
|
7765b43eea | ||
|
|
203bf7b794 | ||
|
|
a7461f3ba7 | ||
|
|
3b7b8eba4c | ||
|
|
84c136b1f2 | ||
|
|
28f71b445f | ||
|
|
be14b91f23 | ||
|
|
12dd2c51a7 | ||
|
|
8f56baf6d9 | ||
|
|
32519a5471 | ||
|
|
6f45d95951 | ||
|
|
60691349a1 | ||
|
|
42ffddc269 | ||
|
|
f3ca4631c3 | ||
|
|
5263aaa026 | ||
|
|
c45d54efb2 | ||
|
|
1606706070 | ||
|
|
22f50de1fe | ||
|
|
5bb6e605fa | ||
|
|
3dc1bfc179 | ||
|
|
080b106991 | ||
|
|
50a535e6e4 | ||
|
|
94ef239de0 | ||
|
|
65ae4eb0dd | ||
|
|
c6d48f51f6 | ||
|
|
47e6eede71 | ||
|
|
cc5acf37f7 | ||
|
|
3221e837f9 | ||
|
|
a4c2886ac0 | ||
|
|
69d76af054 | ||
|
|
e7098f1997 | ||
|
|
f12c9bf3b0 | ||
|
|
afa1d6b708 | ||
|
|
48120d01dc | ||
|
|
e808e8b2d2 | ||
|
|
db581c4d9b | ||
|
|
47a4f2f387 | ||
|
|
2af5922af0 | ||
|
|
6a6bfa6da9 | ||
|
|
27e3cf1558 | ||
|
|
47ad21b6e3 | ||
|
|
6889d09cf7 | ||
|
|
dbda76e842 | ||
|
|
602ebe3fdb | ||
|
|
111b46599a | ||
|
|
c2cdbc909b | ||
|
|
c9669a0d21 | ||
|
|
706739dbe6 | ||
|
|
3f651de24c | ||
|
|
51cdc6ea16 | ||
|
|
d7335f6ae6 | ||
|
|
7b3c394a3e | ||
|
|
526776372e | ||
|
|
d884ed353f | ||
|
|
06596feaa7 | ||
|
|
b477b3874e | ||
|
|
7846e9cb3c | ||
|
|
ace45fb3f6 | ||
|
|
13dd63d631 | ||
|
|
883011dd64 | ||
|
|
413ae86dbc | ||
|
|
3cf9313c86 | ||
|
|
d4b438791f | ||
|
|
d868a8da6c | ||
|
|
37eed8cf1f | ||
|
|
b1f9b03b17 | ||
|
|
f3ca37e523 | ||
|
|
05b7e22808 | ||
|
|
c011fa2ea8 | ||
|
|
e5d57bd82f | ||
|
|
c0d10800ab | ||
|
|
a8c878f48c | ||
|
|
0836241e90 | ||
|
|
84009b534d | ||
|
|
9989b7b68f | ||
|
|
78e0afae2f | ||
|
|
5ee070eb29 | ||
|
|
6c7b592131 | ||
|
|
c87f459ec2 | ||
|
|
d161b9cbfc | ||
|
|
aea4ef9471 | ||
|
|
b14d6d0417 | ||
|
|
dee247453e | ||
|
|
0b02c77691 | ||
|
|
f51f59d675 | ||
|
|
522df3196d | ||
|
|
92b6d84433 | ||
|
|
dd749dde5f | ||
|
|
03fe0e762d | ||
|
|
a2df6e0e36 | ||
|
|
7ea05bb86b | ||
|
|
79858eb26c | ||
|
|
61b9b4046a | ||
|
|
3a9bf84e3b | ||
|
|
1eb3df1d6c | ||
|
|
380d023351 | ||
|
|
2f728fd2a1 | ||
|
|
2338a53229 | ||
|
|
c6855e6a2a | ||
|
|
743685110c | ||
|
|
0fd7886a12 | ||
|
|
d73f46dcda | ||
|
|
492bbc9e13 | ||
|
|
92aae268a3 | ||
|
|
8b2d7062c4 | ||
|
|
193a1fa474 | ||
|
|
d6aa02ff09 | ||
|
|
4b75e6518e | ||
|
|
f60e9b0b62 | ||
|
|
c09eb34708 | ||
|
|
6defe80b62 | ||
|
|
b103aa20c1 | ||
|
|
126165080b | ||
|
|
983d38a43b | ||
|
|
2779d9d3bc | ||
|
|
ad852ffd9a | ||
|
|
9cd62d661f | ||
|
|
74fb63a898 | ||
|
|
4f3b883155 | ||
|
|
79bbf09ecb | ||
|
|
8505ee9d6c | ||
|
|
cc7741efd4 | ||
|
|
3602251cf5 | ||
|
|
a78aec56e3 | ||
|
|
e5b65ed034 | ||
|
|
cdc7d83c22 | ||
|
|
d33e0a4e2c | ||
|
|
349310787c | ||
|
|
25bc7b81c3 | ||
|
|
24a460dc93 | ||
|
|
b936c530aa | ||
|
|
bd4da93d1e | ||
|
|
6ca252ba5c | ||
|
|
28a6718d8e | ||
|
|
04a96788f9 | ||
|
|
154fb1fe9b | ||
|
|
c7d303a6ae | ||
|
|
262a8f47af | ||
|
|
9eef5f860d | ||
|
|
e9c893f07e | ||
|
|
bd545891c0 | ||
|
|
7110069b39 | ||
|
|
ad2101ce52 | ||
|
|
c2d8f210b1 | ||
|
|
0dde5e46df | ||
|
|
4573fb5301 | ||
|
|
1600d5b53f | ||
|
|
90dfe729bb | ||
|
|
9756bdb76e | ||
|
|
a460814182 | ||
|
|
5d5fa55fe5 | ||
|
|
d4474d493b | ||
|
|
f0e2f243ad | ||
|
|
45a670f15b | ||
|
|
387051c409 | ||
|
|
e877ef92d7 | ||
|
|
210af0e73e | ||
|
|
fd4a9d13b7 | ||
|
|
4fc2bd56ee | ||
|
|
e40c82be88 | ||
|
|
0f769fe979 | ||
|
|
558baeac48 | ||
|
|
b0a25c4237 | ||
|
|
33ddca12ed | ||
|
|
3a741936c5 | ||
|
|
3bfb36a67d | ||
|
|
28df726c33 | ||
|
|
48a99366b6 | ||
|
|
81c135c5bb | ||
|
|
d529f81cd9 | ||
|
|
5e0858d13f | ||
|
|
3f7836d9eb | ||
|
|
60cb256835 | ||
|
|
593107e190 | ||
|
|
b6627af65f | ||
|
|
a245f5a0d4 | ||
|
|
89a21c96c0 | ||
|
|
846857b60e | ||
|
|
92abc202a4 | ||
|
|
443422ddb4 | ||
|
|
43f51b2d90 | ||
|
|
57cf3e24f8 | ||
|
|
0c003feac6 | ||
|
|
da9a59de1e | ||
|
|
bde1af5def | ||
|
|
e6e9cd8ce2 | ||
|
|
aca4f83333 | ||
|
|
d868530d1e | ||
|
|
10ae815bb4 | ||
|
|
016be02cd6 | ||
|
|
d9a03c9bb1 | ||
|
|
2b1e766c17 | ||
|
|
24c076eff3 | ||
|
|
1258a3766f | ||
|
|
ef623f5129 | ||
|
|
0449d7c5e1 | ||
|
|
9c65853ddd | ||
|
|
8c0580aa24 | ||
|
|
fd8d4894ca | ||
|
|
8edb1c49d8 | ||
|
|
b1e65c6cd4 | ||
|
|
26ce62d318 | ||
|
|
5eb9d10287 | ||
|
|
435c30aed9 | ||
|
|
53ee78170a | ||
|
|
2cdf5c203a | ||
|
|
8cf8c36708 | ||
|
|
dd7ae7747e | ||
|
|
c9f4a74af0 | ||
|
|
2702dca8b6 | ||
|
|
588b554ef0 | ||
|
|
67be3f8c9e | ||
|
|
ee488dcb83 | ||
|
|
bf11426f7d | ||
|
|
d5cbfee82b | ||
|
|
873225a7f2 | ||
|
|
f1167ace7e | ||
|
|
0add74240f | ||
|
|
cb0aeeb189 | ||
|
|
f8556b3d89 | ||
|
|
da7ba822b0 | ||
|
|
c3eac58dda | ||
|
|
5e90747541 | ||
|
|
cfaf2b97fe | ||
|
|
14a850b4a8 | ||
|
|
90c1eceec7 | ||
|
|
752cf08e5c | ||
|
|
20727906c8 | ||
|
|
01b1c847e9 | ||
|
|
8c89d89932 | ||
|
|
a9a85f251e | ||
|
|
12f752d8b1 | ||
|
|
f22ca6dd9e | ||
|
|
1513c76a3e | ||
|
|
03ecf57548 | ||
|
|
321e5cba60 | ||
|
|
94932ea216 | ||
|
|
a278b380b6 | ||
|
|
4a20260a27 | ||
|
|
59995c20f1 | ||
|
|
3743137c31 | ||
|
|
ae2b95024f | ||
|
|
91600b1c81 | ||
|
|
fef35d0505 | ||
|
|
17c1de7bf2 | ||
|
|
44e2d91b2f | ||
|
|
f02ab9818a | ||
|
|
9a48486838 | ||
|
|
d9f6c6f289 | ||
|
|
07d45e82f0 | ||
|
|
c30866fc93 | ||
|
|
d57ee0b2b8 | ||
|
|
fdb0c3a1df | ||
|
|
bbc0875387 | ||
|
|
4ace99ad76 | ||
|
|
64eca9e1c7 | ||
|
|
cd3c14961f | ||
|
|
e3f1f62a8b | ||
|
|
3f16e6d947 | ||
|
|
f469f18756 | ||
|
|
e211f821c9 | ||
|
|
145df92265 | ||
|
|
ef3df7baaf | ||
|
|
6b6fede2e0 | ||
|
|
9040ef87dc | ||
|
|
dd83784da2 | ||
|
|
330395e8b6 | ||
|
|
6f504a246b | ||
|
|
63e0bd1d61 | ||
|
|
5232302532 | ||
|
|
dc46620a81 | ||
|
|
f80343bf9d | ||
|
|
5edb8159a7 | ||
|
|
0ccbc2f374 | ||
|
|
9ad781324e | ||
|
|
adccc18298 | ||
|
|
3132280b07 | ||
|
|
1bd12083c3 | ||
|
|
82f8345aa5 | ||
|
|
2f6879e869 | ||
|
|
986ea5c636 | ||
|
|
3740228100 | ||
|
|
7aea9266d0 | ||
|
|
c1f9107b8b | ||
|
|
6746f708f2 | ||
|
|
c9851db4c7 | ||
|
|
aa5cd46b6c | ||
|
|
510c2d01c7 | ||
|
|
05fb84ba22 | ||
|
|
04c4ad731e | ||
|
|
c8ffa2fb1d | ||
|
|
fffc5e3a6f | ||
|
|
516933aab5 | ||
|
|
d64b43286e | ||
|
|
45f906c556 | ||
|
|
79f9887625 | ||
|
|
c6cb4b7cf8 | ||
|
|
094852ce30 | ||
|
|
697450a619 | ||
|
|
8da012c8c5 | ||
|
|
b7586335a6 | ||
|
|
1176749f14 | ||
|
|
5437434339 | ||
|
|
9d4ce82ab9 | ||
|
|
345a14ff55 | ||
|
|
b10e06ff45 | ||
|
|
d8d2e52e3f | ||
|
|
b96079fee6 | ||
|
|
8d7ac291bc | ||
|
|
0c329736cc | ||
|
|
cadfd5bf3f | ||
|
|
03450f383f | ||
|
|
8109c7eb30 | ||
|
|
33b69a7099 | ||
|
|
2a79ae0a6e | ||
|
|
ac93a5a85c | ||
|
|
e553eba31e | ||
|
|
531642fc53 | ||
|
|
aa9d7d7f04 | ||
|
|
f20555bf4a | ||
|
|
3fc71731a3 | ||
|
|
218015063b | ||
|
|
416155c35f | ||
|
|
0cd2bfc428 | ||
|
|
1745f0181c | ||
|
|
c5995af493 | ||
|
|
984e415c66 |
96
.ci/azure-pipelines-compat.yml
Normal file
96
.ci/azure-pipelines-compat.yml
Normal file
@@ -0,0 +1,96 @@
|
||||
parameters:
|
||||
- name: Packages
|
||||
type: object
|
||||
default: {}
|
||||
- name: LinuxImage
|
||||
type: string
|
||||
default: "ubuntu-latest"
|
||||
- name: DotNetSdkVersion
|
||||
type: string
|
||||
default: 3.1.100
|
||||
|
||||
jobs:
|
||||
- job: CompatibilityCheck
|
||||
displayName: Compatibility Check
|
||||
pool:
|
||||
vmImage: "${{ parameters.LinuxImage }}"
|
||||
# only execute for pull requests
|
||||
condition: and(succeeded(), variables['System.PullRequest.PullRequestNumber'])
|
||||
strategy:
|
||||
matrix:
|
||||
${{ each Package in parameters.Packages }}:
|
||||
${{ Package.key }}:
|
||||
NugetPackageName: ${{ Package.value.NugetPackageName }}
|
||||
AssemblyFileName: ${{ Package.value.AssemblyFileName }}
|
||||
maxParallel: 2
|
||||
dependsOn: MainBuild
|
||||
steps:
|
||||
- checkout: none
|
||||
|
||||
- task: UseDotNet@2
|
||||
displayName: "Update DotNet"
|
||||
inputs:
|
||||
packageType: sdk
|
||||
version: ${{ parameters.DotNetSdkVersion }}
|
||||
|
||||
- task: DownloadPipelineArtifact@2
|
||||
displayName: "Download New Assembly Build Artifact"
|
||||
inputs:
|
||||
source: "current"
|
||||
artifact: "$(NugetPackageName)"
|
||||
path: "$(System.ArtifactsDirectory)/new-artifacts"
|
||||
runVersion: "latest"
|
||||
|
||||
- task: CopyFiles@2
|
||||
displayName: "Copy New Assembly Build Artifact"
|
||||
inputs:
|
||||
sourceFolder: $(System.ArtifactsDirectory)/new-artifacts
|
||||
contents: "**/*.dll"
|
||||
targetFolder: $(System.ArtifactsDirectory)/new-release
|
||||
cleanTargetFolder: true
|
||||
overWrite: true
|
||||
flattenFolders: true
|
||||
|
||||
- task: DownloadPipelineArtifact@2
|
||||
displayName: "Download Reference Assembly Build Artifact"
|
||||
inputs:
|
||||
source: "specific"
|
||||
artifact: "$(NugetPackageName)"
|
||||
path: "$(System.ArtifactsDirectory)/current-artifacts"
|
||||
project: "$(System.TeamProjectId)"
|
||||
pipeline: "$(System.DefinitionId)"
|
||||
runVersion: "latestFromBranch"
|
||||
runBranch: "refs/heads/$(System.PullRequest.TargetBranch)"
|
||||
|
||||
- task: CopyFiles@2
|
||||
displayName: "Copy Reference Assembly Build Artifact"
|
||||
inputs:
|
||||
sourceFolder: $(System.ArtifactsDirectory)/current-artifacts
|
||||
contents: "**/*.dll"
|
||||
targetFolder: $(System.ArtifactsDirectory)/current-release
|
||||
cleanTargetFolder: true
|
||||
overWrite: true
|
||||
flattenFolders: true
|
||||
|
||||
- task: DownloadGitHubRelease@0
|
||||
displayName: "Download ABI Compatibility Check Tool"
|
||||
inputs:
|
||||
connection: Jellyfin Release Download
|
||||
userRepository: EraYaN/dotnet-compatibility
|
||||
defaultVersionType: "latest"
|
||||
itemPattern: "**-ci.zip"
|
||||
downloadPath: "$(System.ArtifactsDirectory)"
|
||||
|
||||
- task: ExtractFiles@1
|
||||
displayName: "Extract ABI Compatibility Check Tool"
|
||||
inputs:
|
||||
archiveFilePatterns: "$(System.ArtifactsDirectory)/*-ci.zip"
|
||||
destinationFolder: $(System.ArtifactsDirectory)/tools
|
||||
cleanDestinationFolder: true
|
||||
|
||||
# The `--warnings-only` switch will swallow the return code and not emit any errors.
|
||||
- task: CmdLine@2
|
||||
displayName: "Execute ABI Compatibility Check Tool"
|
||||
inputs:
|
||||
script: "dotnet tools/CompatibilityCheckerCLI.dll current-release/$(AssemblyFileName) new-release/$(AssemblyFileName) --azure-pipelines --warnings-only"
|
||||
workingDirectory: $(System.ArtifactsDirectory)
|
||||
101
.ci/azure-pipelines-main.yml
Normal file
101
.ci/azure-pipelines-main.yml
Normal file
@@ -0,0 +1,101 @@
|
||||
parameters:
|
||||
LinuxImage: "ubuntu-latest"
|
||||
RestoreBuildProjects: "Jellyfin.Server/Jellyfin.Server.csproj"
|
||||
DotNetSdkVersion: 3.1.100
|
||||
|
||||
jobs:
|
||||
- job: MainBuild
|
||||
displayName: Main Build
|
||||
strategy:
|
||||
matrix:
|
||||
Release:
|
||||
BuildConfiguration: Release
|
||||
Debug:
|
||||
BuildConfiguration: Debug
|
||||
maxParallel: 2
|
||||
pool:
|
||||
vmImage: "${{ parameters.LinuxImage }}"
|
||||
steps:
|
||||
- checkout: self
|
||||
clean: true
|
||||
submodules: true
|
||||
persistCredentials: true
|
||||
|
||||
- task: CmdLine@2
|
||||
displayName: "Clone Web Client (Master, Release, or Tag)"
|
||||
condition: and(succeeded(), or(contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')), eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||
inputs:
|
||||
script: "git clone --single-branch --branch $(Build.SourceBranchName) --depth=1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web"
|
||||
|
||||
- task: CmdLine@2
|
||||
displayName: "Clone Web Client (PR)"
|
||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master')), eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest'))
|
||||
inputs:
|
||||
script: "git clone --single-branch --branch $(System.PullRequest.TargetBranch) --depth 1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web"
|
||||
|
||||
- task: NodeTool@0
|
||||
displayName: "Install Node"
|
||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')), eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||
inputs:
|
||||
versionSpec: "10.x"
|
||||
|
||||
- task: CmdLine@2
|
||||
displayName: "Build Web Client"
|
||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')), eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||
inputs:
|
||||
script: yarn install
|
||||
workingDirectory: $(Agent.TempDirectory)/jellyfin-web
|
||||
|
||||
- task: CopyFiles@2
|
||||
displayName: "Copy Web Client"
|
||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')), eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||
inputs:
|
||||
sourceFolder: $(Agent.TempDirectory)/jellyfin-web/dist
|
||||
contents: "**"
|
||||
targetFolder: $(Build.SourcesDirectory)/MediaBrowser.WebDashboard/jellyfin-web
|
||||
cleanTargetFolder: true
|
||||
overWrite: true
|
||||
flattenFolders: false
|
||||
|
||||
- task: UseDotNet@2
|
||||
displayName: "Update DotNet"
|
||||
inputs:
|
||||
packageType: sdk
|
||||
version: ${{ parameters.DotNetSdkVersion }}
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: "Publish Server"
|
||||
inputs:
|
||||
command: publish
|
||||
publishWebProjects: false
|
||||
projects: "${{ parameters.RestoreBuildProjects }}"
|
||||
arguments: "--configuration $(BuildConfiguration) --output $(build.artifactstagingdirectory)"
|
||||
zipAfterPublish: false
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
displayName: "Publish Artifact Naming"
|
||||
condition: and(succeeded(), eq(variables['BuildConfiguration'], 'Release'))
|
||||
inputs:
|
||||
targetPath: "$(build.artifactstagingdirectory)/Jellyfin.Server/Emby.Naming.dll"
|
||||
artifactName: "Jellyfin.Naming"
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
displayName: "Publish Artifact Controller"
|
||||
condition: and(succeeded(), eq(variables['BuildConfiguration'], 'Release'))
|
||||
inputs:
|
||||
targetPath: "$(build.artifactstagingdirectory)/Jellyfin.Server/MediaBrowser.Controller.dll"
|
||||
artifactName: "Jellyfin.Controller"
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
displayName: "Publish Artifact Model"
|
||||
condition: and(succeeded(), eq(variables['BuildConfiguration'], 'Release'))
|
||||
inputs:
|
||||
targetPath: "$(build.artifactstagingdirectory)/Jellyfin.Server/MediaBrowser.Model.dll"
|
||||
artifactName: "Jellyfin.Model"
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
displayName: "Publish Artifact Common"
|
||||
condition: and(succeeded(), eq(variables['BuildConfiguration'], 'Release'))
|
||||
inputs:
|
||||
targetPath: "$(build.artifactstagingdirectory)/Jellyfin.Server/MediaBrowser.Common.dll"
|
||||
artifactName: "Jellyfin.Common"
|
||||
65
.ci/azure-pipelines-test.yml
Normal file
65
.ci/azure-pipelines-test.yml
Normal file
@@ -0,0 +1,65 @@
|
||||
parameters:
|
||||
- name: ImageNames
|
||||
type: object
|
||||
default:
|
||||
Linux: "ubuntu-latest"
|
||||
Windows: "windows-latest"
|
||||
macOS: "macos-latest"
|
||||
- name: TestProjects
|
||||
type: string
|
||||
default: "tests/**/*Tests.csproj"
|
||||
- name: DotNetSdkVersion
|
||||
type: string
|
||||
default: 3.1.100
|
||||
|
||||
jobs:
|
||||
- job: MainTest
|
||||
displayName: Main Test
|
||||
strategy:
|
||||
matrix:
|
||||
${{ each imageName in parameters.ImageNames }}:
|
||||
${{ imageName.key }}:
|
||||
ImageName: ${{ imageName.value }}
|
||||
maxParallel: 3
|
||||
pool:
|
||||
vmImage: "$(ImageName)"
|
||||
steps:
|
||||
- checkout: self
|
||||
clean: true
|
||||
submodules: true
|
||||
persistCredentials: false
|
||||
|
||||
- task: UseDotNet@2
|
||||
displayName: "Update DotNet"
|
||||
inputs:
|
||||
packageType: sdk
|
||||
version: ${{ parameters.DotNetSdkVersion }}
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: Run .NET Core CLI tests
|
||||
inputs:
|
||||
command: "test"
|
||||
projects: ${{ parameters.TestProjects }}
|
||||
arguments: '--configuration Release --collect:"XPlat Code Coverage" --settings tests/coverletArgs.runsettings --verbosity minimal "-p:GenerateDocumentationFile=False"'
|
||||
publishTestResults: true
|
||||
testRunTitle: $(Agent.JobName)
|
||||
workingDirectory: "$(Build.SourcesDirectory)"
|
||||
|
||||
- task: Palmmedia.reportgenerator.reportgenerator-build-release-task.reportgenerator@4
|
||||
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux')) # !! THIS is for V1 only V2 will/should support merging
|
||||
displayName: ReportGenerator (merge)
|
||||
inputs:
|
||||
reports: "$(Agent.TempDirectory)/**/coverage.cobertura.xml"
|
||||
targetdir: "$(Agent.TempDirectory)/merged/"
|
||||
reporttypes: "Cobertura"
|
||||
|
||||
## V2 is already in the repository but it does not work "wrong number of segments" YAML error.
|
||||
- task: PublishCodeCoverageResults@1
|
||||
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux')) # !! THIS is for V1 only V2 will/should support merging
|
||||
displayName: Publish Code Coverage
|
||||
inputs:
|
||||
codeCoverageTool: "cobertura"
|
||||
#summaryFileLocation: '$(Agent.TempDirectory)/**/coverage.cobertura.xml' # !!THIS IS FOR V2
|
||||
summaryFileLocation: "$(Agent.TempDirectory)/merged/**.xml"
|
||||
pathToSources: $(Build.SourcesDirectory)
|
||||
failIfCoverageEmpty: true
|
||||
82
.ci/azure-pipelines-windows.yml
Normal file
82
.ci/azure-pipelines-windows.yml
Normal file
@@ -0,0 +1,82 @@
|
||||
parameters:
|
||||
WindowsImage: "windows-latest"
|
||||
TestProjects: "tests/**/*Tests.csproj"
|
||||
DotNetSdkVersion: 3.1.100
|
||||
|
||||
jobs:
|
||||
- job: PublishWindows
|
||||
displayName: Publish Windows
|
||||
pool:
|
||||
vmImage: ${{ parameters.WindowsImage }}
|
||||
steps:
|
||||
- checkout: self
|
||||
clean: true
|
||||
submodules: true
|
||||
persistCredentials: true
|
||||
|
||||
- task: CmdLine@2
|
||||
displayName: "Clone Web Client (Master, Release, or Tag)"
|
||||
condition: and(succeeded(), or(contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master'), contains(variables['Build.SourceBranch'], 'tag')), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||
inputs:
|
||||
script: "git clone --single-branch --branch $(Build.SourceBranchName) --depth=1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web"
|
||||
|
||||
- task: CmdLine@2
|
||||
displayName: "Clone Web Client (PR)"
|
||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master')), in(variables['Build.Reason'], 'PullRequest'))
|
||||
inputs:
|
||||
script: "git clone --single-branch --branch $(System.PullRequest.TargetBranch) --depth 1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web"
|
||||
|
||||
- task: NodeTool@0
|
||||
displayName: "Install Node"
|
||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||
inputs:
|
||||
versionSpec: "10.x"
|
||||
|
||||
- task: CmdLine@2
|
||||
displayName: "Build Web Client"
|
||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||
inputs:
|
||||
script: yarn install
|
||||
workingDirectory: $(Agent.TempDirectory)/jellyfin-web
|
||||
|
||||
- task: CopyFiles@2
|
||||
displayName: "Copy Web Client"
|
||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||
inputs:
|
||||
sourceFolder: $(Agent.TempDirectory)/jellyfin-web/dist
|
||||
contents: "**"
|
||||
targetFolder: $(Build.SourcesDirectory)/MediaBrowser.WebDashboard/jellyfin-web
|
||||
cleanTargetFolder: true
|
||||
overWrite: true
|
||||
flattenFolders: false
|
||||
|
||||
- task: CmdLine@2
|
||||
displayName: "Clone UX Repository"
|
||||
inputs:
|
||||
script: git clone --depth=1 https://github.com/jellyfin/jellyfin-ux $(Agent.TempDirectory)\jellyfin-ux
|
||||
|
||||
- task: PowerShell@2
|
||||
displayName: "Build NSIS Installer"
|
||||
inputs:
|
||||
targetType: "filePath"
|
||||
filePath: ./deployment/windows/build-jellyfin.ps1
|
||||
arguments: -InstallFFMPEG -InstallNSSM -MakeNSIS -InstallTrayApp -UXLocation $(Agent.TempDirectory)\jellyfin-ux -InstallLocation $(build.artifactstagingdirectory)
|
||||
errorActionPreference: "stop"
|
||||
workingDirectory: $(Build.SourcesDirectory)
|
||||
|
||||
- task: CopyFiles@2
|
||||
displayName: "Copy NSIS Installer"
|
||||
inputs:
|
||||
sourceFolder: $(Build.SourcesDirectory)/deployment/windows/
|
||||
contents: "jellyfin*.exe"
|
||||
targetFolder: $(System.ArtifactsDirectory)/setup
|
||||
cleanTargetFolder: true
|
||||
overWrite: true
|
||||
flattenFolders: true
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
displayName: "Publish Artifact Setup"
|
||||
condition: succeeded()
|
||||
inputs:
|
||||
targetPath: "$(build.artifactstagingdirectory)/setup"
|
||||
artifactName: "Jellyfin Server Setup"
|
||||
@@ -2,9 +2,11 @@ name: $(Date:yyyyMMdd)$(Rev:.r)
|
||||
|
||||
variables:
|
||||
- name: TestProjects
|
||||
value: 'tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj'
|
||||
value: "tests/**/*Tests.csproj"
|
||||
- name: RestoreBuildProjects
|
||||
value: 'Jellyfin.Server/Jellyfin.Server.csproj'
|
||||
value: "Jellyfin.Server/Jellyfin.Server.csproj"
|
||||
- name: DotNetSdkVersion
|
||||
value: 3.1.100
|
||||
|
||||
pr:
|
||||
autoCancel: true
|
||||
@@ -13,271 +15,26 @@ trigger:
|
||||
batch: true
|
||||
|
||||
jobs:
|
||||
- job: main_build
|
||||
displayName: Main Build
|
||||
pool:
|
||||
vmImage: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
release:
|
||||
BuildConfiguration: Release
|
||||
debug:
|
||||
BuildConfiguration: Debug
|
||||
maxParallel: 2
|
||||
steps:
|
||||
- checkout: self
|
||||
clean: true
|
||||
submodules: true
|
||||
persistCredentials: true
|
||||
- template: azure-pipelines-main.yml
|
||||
parameters:
|
||||
LinuxImage: "ubuntu-latest"
|
||||
RestoreBuildProjects: $(RestoreBuildProjects)
|
||||
|
||||
- task: CmdLine@2
|
||||
displayName: "Check out web"
|
||||
condition: and(succeeded(), or(contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||
inputs:
|
||||
script: 'git clone --single-branch --branch $(Build.SourceBranchName) --depth=1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web'
|
||||
- template: azure-pipelines-test.yml
|
||||
parameters:
|
||||
ImageNames:
|
||||
Linux: "ubuntu-latest"
|
||||
Windows: "windows-latest"
|
||||
macOS: "macos-latest"
|
||||
|
||||
- task: CmdLine@2
|
||||
displayName: "Check out web (PR)"
|
||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest'))
|
||||
inputs:
|
||||
script: 'git clone --single-branch --branch $(System.PullRequest.TargetBranch) --depth 1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web'
|
||||
- template: azure-pipelines-windows.yml
|
||||
parameters:
|
||||
WindowsImage: "windows-latest"
|
||||
TestProjects: $(TestProjects)
|
||||
|
||||
- task: NodeTool@0
|
||||
displayName: 'Install Node.js'
|
||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||
inputs:
|
||||
versionSpec: '10.x'
|
||||
|
||||
- task: CmdLine@2
|
||||
displayName: "Build Web UI"
|
||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||
inputs:
|
||||
script: yarn install
|
||||
workingDirectory: $(Agent.TempDirectory)/jellyfin-web
|
||||
|
||||
- task: CopyFiles@2
|
||||
displayName: Copy the web UI
|
||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||
inputs:
|
||||
sourceFolder: $(Agent.TempDirectory)/jellyfin-web/dist # Optional
|
||||
contents: '**'
|
||||
targetFolder: $(Build.SourcesDirectory)/MediaBrowser.WebDashboard/jellyfin-web
|
||||
cleanTargetFolder: true # Optional
|
||||
overWrite: true # Optional
|
||||
flattenFolders: false # Optional
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: Publish
|
||||
inputs:
|
||||
command: publish
|
||||
publishWebProjects: false
|
||||
projects: '$(RestoreBuildProjects)'
|
||||
arguments: '--configuration $(BuildConfiguration) --output $(build.artifactstagingdirectory)'
|
||||
zipAfterPublish: false
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
displayName: 'Publish Artifact Naming'
|
||||
condition: and(eq(variables['BuildConfiguration'], 'Release'), succeeded())
|
||||
inputs:
|
||||
targetPath: '$(build.artifactstagingdirectory)/Jellyfin.Server/Emby.Naming.dll'
|
||||
artifactName: 'Jellyfin.Naming'
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
displayName: 'Publish Artifact Controller'
|
||||
condition: and(eq(variables['BuildConfiguration'], 'Release'), succeeded())
|
||||
inputs:
|
||||
targetPath: '$(build.artifactstagingdirectory)/Jellyfin.Server/MediaBrowser.Controller.dll'
|
||||
artifactName: 'Jellyfin.Controller'
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
displayName: 'Publish Artifact Model'
|
||||
condition: and(eq(variables['BuildConfiguration'], 'Release'), succeeded())
|
||||
inputs:
|
||||
targetPath: '$(build.artifactstagingdirectory)/Jellyfin.Server/MediaBrowser.Model.dll'
|
||||
artifactName: 'Jellyfin.Model'
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
displayName: 'Publish Artifact Common'
|
||||
condition: and(eq(variables['BuildConfiguration'], 'Release'), succeeded())
|
||||
inputs:
|
||||
targetPath: '$(build.artifactstagingdirectory)/Jellyfin.Server/MediaBrowser.Common.dll'
|
||||
artifactName: 'Jellyfin.Common'
|
||||
|
||||
- job: main_test
|
||||
displayName: Main Test
|
||||
pool:
|
||||
vmImage: windows-latest
|
||||
steps:
|
||||
- checkout: self
|
||||
clean: true
|
||||
submodules: true
|
||||
persistCredentials: false
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: Build
|
||||
inputs:
|
||||
command: build
|
||||
publishWebProjects: false
|
||||
projects: '$(TestProjects)'
|
||||
arguments: '--configuration $(BuildConfiguration)'
|
||||
zipAfterPublish: false
|
||||
|
||||
- task: VisualStudioTestPlatformInstaller@1
|
||||
inputs:
|
||||
packageFeedSelector: 'nugetOrg' # Options: nugetOrg, customFeed, netShare
|
||||
versionSelector: 'latestPreRelease' # Required when packageFeedSelector == NugetOrg || PackageFeedSelector == CustomFeed# Options: latestPreRelease, latestStable, specificVersion
|
||||
|
||||
- task: VSTest@2
|
||||
inputs:
|
||||
testSelector: 'testAssemblies' # Options: testAssemblies, testPlan, testRun
|
||||
testAssemblyVer2: | # Required when testSelector == TestAssemblies
|
||||
**\bin\$(BuildConfiguration)\**\*test*.dll
|
||||
!**\obj\**
|
||||
!**\xunit.runner.visualstudio.testadapter.dll
|
||||
!**\xunit.runner.visualstudio.dotnetcore.testadapter.dll
|
||||
#testPlan: # Required when testSelector == TestPlan
|
||||
#testSuite: # Required when testSelector == TestPlan
|
||||
#testConfiguration: # Required when testSelector == TestPlan
|
||||
#tcmTestRun: '$(test.RunId)' # Optional
|
||||
searchFolder: '$(System.DefaultWorkingDirectory)'
|
||||
#testFiltercriteria: # Optional
|
||||
#runOnlyImpactedTests: False # Optional
|
||||
#runAllTestsAfterXBuilds: '50' # Optional
|
||||
#uiTests: false # Optional
|
||||
#vstestLocationMethod: 'version' # Optional. Options: version, location
|
||||
#vsTestVersion: 'latest' # Optional. Options: latest, 16.0, 15.0, 14.0, toolsInstaller
|
||||
#vstestLocation: # Optional
|
||||
#runSettingsFile: # Optional
|
||||
#overrideTestrunParameters: # Optional
|
||||
#pathtoCustomTestAdapters: # Optional
|
||||
runInParallel: True # Optional
|
||||
runTestsInIsolation: True # Optional
|
||||
codeCoverageEnabled: True # Optional
|
||||
#otherConsoleOptions: # Optional
|
||||
#distributionBatchType: 'basedOnTestCases' # Optional. Options: basedOnTestCases, basedOnExecutionTime, basedOnAssembly
|
||||
#batchingBasedOnAgentsOption: 'autoBatchSize' # Optional. Options: autoBatchSize, customBatchSize
|
||||
#customBatchSizeValue: '10' # Required when distributionBatchType == BasedOnTestCases && BatchingBasedOnAgentsOption == CustomBatchSize
|
||||
#batchingBasedOnExecutionTimeOption: 'autoBatchSize' # Optional. Options: autoBatchSize, customTimeBatchSize
|
||||
#customRunTimePerBatchValue: '60' # Required when distributionBatchType == BasedOnExecutionTime && BatchingBasedOnExecutionTimeOption == CustomTimeBatchSize
|
||||
#dontDistribute: False # Optional
|
||||
#testRunTitle: # Optional
|
||||
#platform: # Optional
|
||||
configuration: 'Debug' # Optional
|
||||
publishRunAttachments: true # Optional
|
||||
#diagnosticsEnabled: false # Optional
|
||||
#collectDumpOn: 'onAbortOnly' # Optional. Options: onAbortOnly, always, never
|
||||
#rerunFailedTests: False # Optional
|
||||
#rerunType: 'basedOnTestFailurePercentage' # Optional. Options: basedOnTestFailurePercentage, basedOnTestFailureCount
|
||||
#rerunFailedThreshold: '30' # Optional
|
||||
#rerunFailedTestCasesMaxLimit: '5' # Optional
|
||||
#rerunMaxAttempts: '3' # Optional
|
||||
|
||||
# - task: PublishTestResults@2
|
||||
# inputs:
|
||||
# testResultsFormat: 'VSTest' # Options: JUnit, NUnit, VSTest, xUnit, cTest
|
||||
# testResultsFiles: '**/*.trx'
|
||||
# #searchFolder: '$(System.DefaultWorkingDirectory)' # Optional
|
||||
# mergeTestResults: true # Optional
|
||||
# #failTaskOnFailedTests: false # Optional
|
||||
# #testRunTitle: # Optional
|
||||
# #buildPlatform: # Optional
|
||||
# #buildConfiguration: # Optional
|
||||
# #publishRunAttachments: true # Optional
|
||||
|
||||
- job: main_build_win
|
||||
displayName: Main Build Windows
|
||||
pool:
|
||||
vmImage: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
release:
|
||||
BuildConfiguration: Release
|
||||
maxParallel: 2
|
||||
steps:
|
||||
- checkout: self
|
||||
clean: true
|
||||
submodules: true
|
||||
persistCredentials: true
|
||||
|
||||
- task: CmdLine@2
|
||||
displayName: "Check out web"
|
||||
condition: and(succeeded(), or(contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||
inputs:
|
||||
script: 'git clone --single-branch --branch $(Build.SourceBranchName) --depth=1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web'
|
||||
|
||||
- task: CmdLine@2
|
||||
displayName: "Check out web (PR)"
|
||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest'))
|
||||
inputs:
|
||||
script: 'git clone --single-branch --branch $(System.PullRequest.TargetBranch) --depth 1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web'
|
||||
|
||||
- task: NodeTool@0
|
||||
displayName: 'Install Node.js'
|
||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||
inputs:
|
||||
versionSpec: '10.x'
|
||||
|
||||
- task: CmdLine@2
|
||||
displayName: "Build Web UI"
|
||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||
inputs:
|
||||
script: yarn install
|
||||
workingDirectory: $(Agent.TempDirectory)/jellyfin-web
|
||||
|
||||
- task: CopyFiles@2
|
||||
displayName: Copy the web UI
|
||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||
inputs:
|
||||
sourceFolder: $(Agent.TempDirectory)/jellyfin-web/dist # Optional
|
||||
contents: '**'
|
||||
targetFolder: $(Build.SourcesDirectory)/MediaBrowser.WebDashboard/jellyfin-web
|
||||
cleanTargetFolder: true # Optional
|
||||
overWrite: true # Optional
|
||||
flattenFolders: false # Optional
|
||||
|
||||
- task: CmdLine@2
|
||||
displayName: Clone the UX repository
|
||||
inputs:
|
||||
script: git clone --depth=1 https://github.com/jellyfin/jellyfin-ux $(Agent.TempDirectory)\jellyfin-ux
|
||||
|
||||
- task: PowerShell@2
|
||||
displayName: Build the NSIS Installer
|
||||
inputs:
|
||||
targetType: 'filePath' # Optional. Options: filePath, inline
|
||||
filePath: ./deployment/windows/build-jellyfin.ps1 # Required when targetType == FilePath
|
||||
arguments: -InstallFFMPEG -InstallNSSM -MakeNSIS -UXLocation $(Agent.TempDirectory)\jellyfin-ux -InstallLocation $(build.artifactstagingdirectory)
|
||||
#script: '# Write your PowerShell commands here.Write-Host Hello World' # Required when targetType == Inline
|
||||
errorActionPreference: 'stop' # Optional. Options: stop, continue, silentlyContinue
|
||||
#failOnStderr: false # Optional
|
||||
#ignoreLASTEXITCODE: false # Optional
|
||||
#pwsh: false # Optional
|
||||
workingDirectory: $(Build.SourcesDirectory) # Optional
|
||||
|
||||
- task: CopyFiles@2
|
||||
displayName: Copy the NSIS Installer to the artifact directory
|
||||
inputs:
|
||||
sourceFolder: $(Build.SourcesDirectory)/deployment/windows/ # Optional
|
||||
contents: 'jellyfin*.exe'
|
||||
targetFolder: $(System.ArtifactsDirectory)/setup
|
||||
cleanTargetFolder: true # Optional
|
||||
overWrite: true # Optional
|
||||
flattenFolders: true # Optional
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
displayName: 'Publish Setup Artifact'
|
||||
condition: and(eq(variables['BuildConfiguration'], 'Release'), succeeded())
|
||||
inputs:
|
||||
targetPath: '$(build.artifactstagingdirectory)/setup'
|
||||
artifactName: 'Jellyfin Server Setup'
|
||||
|
||||
- job: dotnet_compat
|
||||
displayName: Compatibility Check
|
||||
pool:
|
||||
vmImage: ubuntu-latest
|
||||
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:
|
||||
- template: azure-pipelines-compat.yml
|
||||
parameters:
|
||||
Packages:
|
||||
Naming:
|
||||
NugetPackageName: Jellyfin.Naming
|
||||
AssemblyFileName: Emby.Naming.dll
|
||||
@@ -290,82 +47,4 @@ jobs:
|
||||
Common:
|
||||
NugetPackageName: Jellyfin.Common
|
||||
AssemblyFileName: MediaBrowser.Common.dll
|
||||
maxParallel: 2
|
||||
steps:
|
||||
- checkout: none
|
||||
|
||||
- task: DownloadPipelineArtifact@2
|
||||
displayName: Download the New Assembly Build Artifact
|
||||
inputs:
|
||||
source: 'current' # Options: current, specific
|
||||
#preferTriggeringPipeline: false # Optional
|
||||
#tags: # Optional
|
||||
artifact: '$(NugetPackageName)' # Optional
|
||||
#patterns: '**' # Optional
|
||||
path: '$(System.ArtifactsDirectory)/new-artifacts'
|
||||
#project: # Required when source == Specific
|
||||
#pipeline: # Required when source == Specific
|
||||
runVersion: 'latest' # Required when source == Specific. Options: latest, latestFromBranch, specific
|
||||
#runBranch: 'refs/heads/master' # Required when source == Specific && runVersion == LatestFromBranch
|
||||
#runId: # Required when source == Specific && runVersion == Specific
|
||||
|
||||
- task: CopyFiles@2
|
||||
displayName: Copy New 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: DownloadPipelineArtifact@2
|
||||
displayName: Download the Reference Assembly Build Artifact
|
||||
inputs:
|
||||
source: 'specific' # Options: current, specific
|
||||
#preferTriggeringPipeline: false # Optional
|
||||
#tags: # Optional
|
||||
artifact: '$(NugetPackageName)' # Optional
|
||||
#patterns: '**' # Optional
|
||||
path: '$(System.ArtifactsDirectory)/current-artifacts'
|
||||
project: '$(System.TeamProjectId)' # Required when source == Specific
|
||||
pipeline: '$(System.DefinitionId)' # Required when source == Specific
|
||||
runVersion: 'latestFromBranch' # Required when source == Specific. Options: latest, latestFromBranch, specific
|
||||
runBranch: 'refs/heads/$(System.PullRequest.TargetBranch)' # Required when source == Specific && runVersion == LatestFromBranch
|
||||
#runId: # Required when source == Specific && runVersion == Specific
|
||||
|
||||
- task: CopyFiles@2
|
||||
displayName: Copy Reference 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: DownloadGitHubRelease@0
|
||||
displayName: Download ABI compatibility check tool from GitHub
|
||||
inputs:
|
||||
connection: Jellyfin Release Download
|
||||
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) --azure-pipelines'
|
||||
workingDirectory: $(System.ArtifactsDirectory) # Optional
|
||||
#failOnStderr: false # Optional
|
||||
|
||||
|
||||
LinuxImage: "ubuntu-latest"
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
name: Nightly-$(date:yyyyMMdd).$(rev:r)
|
||||
|
||||
variables:
|
||||
- name: Version
|
||||
value: '1.0.0'
|
||||
|
||||
trigger: none
|
||||
pr: none
|
||||
|
||||
jobs:
|
||||
- job: publish_artifacts_nightly
|
||||
displayName: Publish Artifacts Nightly
|
||||
pool:
|
||||
vmImage: ubuntu-latest
|
||||
steps:
|
||||
- checkout: none
|
||||
- task: DownloadPipelineArtifact@2
|
||||
displayName: Download the Windows Setup Artifact
|
||||
inputs:
|
||||
source: 'specific' # Options: current, specific
|
||||
artifact: 'Jellyfin Server Setup' # Optional
|
||||
path: '$(System.ArtifactsDirectory)/win-installer'
|
||||
project: '$(System.TeamProjectId)' # Required when source == Specific
|
||||
pipelineId: 1 # Required when source == Specific
|
||||
runVersion: 'latestFromBranch' # Required when source == Specific. Options: latest, latestFromBranch, specific
|
||||
runBranch: 'refs/heads/master' # Required when source == Specific && runVersion == LatestFromBranch
|
||||
|
||||
- task: SSH@0
|
||||
displayName: 'Create Drop directory'
|
||||
inputs:
|
||||
sshEndpoint: 'Jellyfin Build Server'
|
||||
commands: 'mkdir -p /srv/incoming/jellyfin_$(Version)/win-installer && ln -s /srv/incoming/jellyfin_$(Version) /srv/incoming/jellyfin_nightly_azure_upload'
|
||||
|
||||
- task: CopyFilesOverSSH@0
|
||||
displayName: 'Copy the Windows Setup to the Repo'
|
||||
inputs:
|
||||
sshEndpoint: 'Jellyfin Build Server'
|
||||
sourceFolder: '$(System.ArtifactsDirectory)/win-installer'
|
||||
contents: 'jellyfin_*.exe'
|
||||
targetFolder: '/srv/incoming/jellyfin_nightly_azure_upload/win-installer'
|
||||
|
||||
- task: SSH@0
|
||||
displayName: 'Clean up SCP symlink'
|
||||
inputs:
|
||||
sshEndpoint: 'Jellyfin Build Server'
|
||||
commands: 'rm -f /srv/incoming/jellyfin_nightly_azure_upload'
|
||||
@@ -1,48 +0,0 @@
|
||||
name: Release-$(Version)-$(date:yyyyMMdd).$(rev:r)
|
||||
|
||||
variables:
|
||||
- name: Version
|
||||
value: '1.0.0'
|
||||
- name: UsedRunId
|
||||
value: 0
|
||||
|
||||
trigger: none
|
||||
pr: none
|
||||
|
||||
jobs:
|
||||
- job: publish_artifacts_release
|
||||
displayName: Publish Artifacts Release
|
||||
pool:
|
||||
vmImage: ubuntu-latest
|
||||
steps:
|
||||
- checkout: none
|
||||
- task: DownloadPipelineArtifact@2
|
||||
displayName: Download the Windows Setup Artifact
|
||||
inputs:
|
||||
source: 'specific' # Options: current, specific
|
||||
artifact: 'Jellyfin Server Setup' # Optional
|
||||
path: '$(System.ArtifactsDirectory)/win-installer'
|
||||
project: '$(System.TeamProjectId)' # Required when source == Specific
|
||||
pipelineId: 1 # Required when source == Specific
|
||||
runVersion: 'specific' # Required when source == Specific. Options: latest, latestFromBranch, specific
|
||||
runId: $(UsedRunId)
|
||||
|
||||
- task: SSH@0
|
||||
displayName: 'Create Drop directory'
|
||||
inputs:
|
||||
sshEndpoint: 'Jellyfin Build Server'
|
||||
commands: 'mkdir -p /srv/incoming/jellyfin_$(Version)/win-installer && ln -s /srv/incoming/jellyfin_$(Version) /srv/incoming/jellyfin_release_azure_upload'
|
||||
|
||||
- task: CopyFilesOverSSH@0
|
||||
displayName: 'Copy the Windows Setup to the Repo'
|
||||
inputs:
|
||||
sshEndpoint: 'Jellyfin Build Server'
|
||||
sourceFolder: '$(System.ArtifactsDirectory)/win-installer'
|
||||
contents: 'jellyfin_*.exe'
|
||||
targetFolder: '/srv/incoming/jellyfin_release_azure_upload/win-installer'
|
||||
|
||||
- task: SSH@0
|
||||
displayName: 'Clean up SCP symlink'
|
||||
inputs:
|
||||
sshEndpoint: 'Jellyfin Build Server'
|
||||
commands: 'rm -f /srv/incoming/jellyfin_release_azure_upload'
|
||||
@@ -1,8 +1,59 @@
|
||||
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)"
|
||||
VERSION := $(shell sed -ne '/^Version:/s/.* *//p' \
|
||||
deployment/fedora-package-x64/pkg-src/jellyfin.spec)
|
||||
|
||||
deployment/fedora-package-x64/pkg-src/jellyfin-web-$(VERSION).tar.gz:
|
||||
curl -f -L -o deployment/fedora-package-x64/pkg-src/jellyfin-web-$(VERSION).tar.gz \
|
||||
https://github.com/jellyfin/jellyfin-web/archive/v$(VERSION).tar.gz \
|
||||
|| curl -f -L -o deployment/fedora-package-x64/pkg-src/jellyfin-web-$(VERSION).tar.gz \
|
||||
https://github.com/jellyfin/jellyfin-web/archive/master.tar.gz \
|
||||
|
||||
srpm: deployment/fedora-package-x64/pkg-src/jellyfin-web-$(VERSION).tar.gz
|
||||
cd deployment/fedora-package-x64; \
|
||||
SOURCE_DIR=../.. \
|
||||
WORKDIR="$${PWD}"; \
|
||||
package_temporary_dir="$${WORKDIR}/pkg-dist-tmp"; \
|
||||
pkg_src_dir="$${WORKDIR}/pkg-src"; \
|
||||
GNU_TAR=1; \
|
||||
tar \
|
||||
--transform "s,^\.,jellyfin-$(VERSION)," \
|
||||
--exclude='.git*' \
|
||||
--exclude='**/.git' \
|
||||
--exclude='**/.hg' \
|
||||
--exclude='**/.vs' \
|
||||
--exclude='**/.vscode' \
|
||||
--exclude='deployment' \
|
||||
--exclude='**/bin' \
|
||||
--exclude='**/obj' \
|
||||
--exclude='**/.nuget' \
|
||||
--exclude='*.deb' \
|
||||
--exclude='*.rpm' \
|
||||
-czf "pkg-src/jellyfin-$(VERSION).tar.gz" \
|
||||
-C $${SOURCE_DIR} ./ || GNU_TAR=0; \
|
||||
if [ $${GNU_TAR} -eq 0 ]; then \
|
||||
package_temporary_dir="$$(mktemp -d)"; \
|
||||
mkdir -p "$${package_temporary_dir}/jellyfin"; \
|
||||
tar \
|
||||
--exclude='.git*' \
|
||||
--exclude='**/.git' \
|
||||
--exclude='**/.hg' \
|
||||
--exclude='**/.vs' \
|
||||
--exclude='**/.vscode' \
|
||||
--exclude='deployment' \
|
||||
--exclude='**/bin' \
|
||||
--exclude='**/obj' \
|
||||
--exclude='**/.nuget' \
|
||||
--exclude='*.deb' \
|
||||
--exclude='*.rpm' \
|
||||
-czf "$${package_temporary_dir}/jellyfin/jellyfin-$(VERSION).tar.gz" \
|
||||
-C $${SOURCE_DIR} ./; \
|
||||
mkdir -p "$${package_temporary_dir}/jellyfin-$(VERSION)"; \
|
||||
tar -xzf "$${package_temporary_dir}/jellyfin/jellyfin-$(VERSION).tar.gz" \
|
||||
-C "$${package_temporary_dir}/jellyfin-$(VERSION); \
|
||||
rm -f "$${package_temporary_dir}/jellyfin/jellyfin-$(VERSION).tar.gz"; \
|
||||
tar -czf "$${SOURCE_DIR}/SOURCES/pkg-src/jellyfin-$(VERSION).tar.gz" \
|
||||
-C "$${package_temporary_dir}" "jellyfin-$(VERSION); \
|
||||
rm -rf $${package_temporary_dir}; \
|
||||
fi; \
|
||||
rpmbuild -bs pkg-src/jellyfin.spec \
|
||||
--define "_sourcedir $$PWD/pkg-src/" \
|
||||
--define "_srcrpmdir $(outdir)"
|
||||
|
||||
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -1,3 +1,5 @@
|
||||
* text=auto eol=lf
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
|
||||
CONTRIBUTORS.md merge=union
|
||||
|
||||
19
.github/ISSUE_TEMPLATE/bug_report.md
vendored
19
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -10,6 +10,19 @@ assignees: ''
|
||||
**Describe the bug**
|
||||
<!-- A clear and concise description of what the bug is. -->
|
||||
|
||||
**System (please complete the following information):**
|
||||
- OS: [e.g. Debian, Windows]
|
||||
- Virtualization: [e.g. Docker, KVM, LXC]
|
||||
- Clients: [Browser, Android, Fire Stick, etc.]
|
||||
- Browser: [e.g. Firefox 72, Chrome 80, Safari 13]
|
||||
- Jellyfin Version: [e.g. 10.4.3, nightly 20191231]
|
||||
- Playback: [Direct Play, Remux, Direct Stream, Transcode]
|
||||
- Installed Plugins: [e.g. none, Fanart, Anime, etc.]
|
||||
- Reverse Proxy: [e.g. none, nginx, apache, etc.]
|
||||
- Base URL: [e.g. none, yes: /example]
|
||||
- Networking: [e.g. Host, Bridge/NAT]
|
||||
- Storage: [e.g. local, NFS, cloud]
|
||||
|
||||
**To Reproduce**
|
||||
<!-- Steps to reproduce the behavior: -->
|
||||
1. Go to '...'
|
||||
@@ -26,11 +39,5 @@ assignees: ''
|
||||
**Screenshots**
|
||||
<!-- If applicable, add screenshots to help explain your problem. -->
|
||||
|
||||
**System (please complete the following information):**
|
||||
- OS: [e.g. Docker, Debian, Windows]
|
||||
- Browser: [e.g. Firefox, Chrome, Safari]
|
||||
- Jellyfin Version: [e.g. 10.0.1]
|
||||
- Reverse proxy: [e.g. no, nginx, apache, etc.]
|
||||
|
||||
**Additional context**
|
||||
<!-- Add any other context about the problem here. -->
|
||||
|
||||
6
.github/ISSUE_TEMPLATE/media_playback.md
vendored
6
.github/ISSUE_TEMPLATE/media_playback.md
vendored
@@ -11,7 +11,10 @@ assignees: ''
|
||||
<!-- Use the Media Info tool (set to text format, download here: https://mediaarea.net/en/MediaInfo) or copy the info from the web ui for the file with the playback issue. -->
|
||||
|
||||
**Logs**
|
||||
<!-- Please paste any log message from during the playback issue, for example the ffmpeg command line can be very useful. -->
|
||||
<!-- Please paste any log messages from during the playback issue. -->
|
||||
|
||||
**FFmpeg Logs**
|
||||
<!-- Please paste any FFmpeg logs if remuxing or transcoding appears to be part of the issue. -->
|
||||
|
||||
**Stats for Nerds Screenshots**
|
||||
<!-- If available, add screenshots of the stats for nerds screen to help show the issue problem. -->
|
||||
@@ -29,4 +32,3 @@ assignees: ''
|
||||
- Client: [e.g. Web/Browser, webOS, Android, Android TV, Electron]
|
||||
- Browser (if Web client): [e.g. Firefox, Chrome, Safari]
|
||||
- Client and Browser Version: [e.g. 10.3.4 and 68.0]
|
||||
|
||||
|
||||
13
.github/stale.yml
vendored
13
.github/stale.yml
vendored
@@ -1,7 +1,7 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 90
|
||||
daysUntilStale: 120
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 14
|
||||
daysUntilClose: 21
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- regression
|
||||
@@ -11,12 +11,15 @@ exemptLabels:
|
||||
- future
|
||||
- feature
|
||||
- enhancement
|
||||
- confirmed
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: stale
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
Issues go stale after 90d of inactivity. Mark the issue as fresh by adding a comment or commit. Stale issues close after an additional 14d of inactivity.
|
||||
If this issue is safe to close now please do so.
|
||||
If you have any questions you can reach us on [Matrix or Social Media](https://docs.jellyfin.org/general/getting-help.html).
|
||||
This issue has gone 120 days without comment. To avoid abandoned issues, it will be closed in 21 days if there are no new comments.
|
||||
|
||||
If you're the original submitter of this issue, please comment confirming if this issue still affects you in the latest release or nightlies, or close the issue if it has been fixed. If you're another user also affected by this bug, please comment confirming so. Either action will remove the stale label.
|
||||
|
||||
This bot exists to prevent issues from becoming stale and forgotten. Jellyfin is always moving forward, and bugs are often fixed as side effects of other changes. We therefore ask that bug report authors remain vigilant about their issues to ensure they are closed if fixed, or re-confirmed - perhaps with fresh logs or reproduction examples - regularly. If you have any questions you can reach us on [Matrix or Social Media](https://docs.jellyfin.org/general/getting-help.html).
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -268,3 +268,6 @@ doc/
|
||||
# Deployment artifacts
|
||||
dist
|
||||
*.exe
|
||||
|
||||
# BenchmarkDotNet artifacts
|
||||
BenchmarkDotNet.Artifacts
|
||||
|
||||
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@@ -10,7 +10,7 @@
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
// If you have changed target frameworks, make sure to update the program path.
|
||||
"program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/netcoreapp2.1/jellyfin.dll",
|
||||
"program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/netcoreapp3.1/jellyfin.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}/Jellyfin.Server",
|
||||
// For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window
|
||||
@@ -25,4 +25,4 @@
|
||||
"processId": "${command:pickProcess}"
|
||||
}
|
||||
,]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\SharedVersion.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,33 +0,0 @@
|
||||
|
||||
namespace BDInfo
|
||||
{
|
||||
class BDInfoSettings
|
||||
{
|
||||
public static bool GenerateStreamDiagnostics => true;
|
||||
|
||||
public static bool EnableSSIF => true;
|
||||
|
||||
public static bool AutosaveReport => false;
|
||||
|
||||
public static bool GenerateFrameDataFile => false;
|
||||
|
||||
public static bool FilterLoopingPlaylists => true;
|
||||
|
||||
public static bool FilterShortPlaylists => false;
|
||||
|
||||
public static int FilterShortPlaylistsValue => 0;
|
||||
|
||||
public static bool UseImagePrefix => false;
|
||||
|
||||
public static string UseImagePrefixValue => null;
|
||||
|
||||
/// <summary>
|
||||
/// Setting this to false throws an IComparer error on some discs.
|
||||
/// </summary>
|
||||
public static bool KeepStreamOrder => true;
|
||||
|
||||
public static bool GenerateTextSummary => false;
|
||||
|
||||
public static string LastPath => string.Empty;
|
||||
}
|
||||
}
|
||||
449
BDInfo/BDROM.cs
449
BDInfo/BDROM.cs
@@ -1,449 +0,0 @@
|
||||
//============================================================================
|
||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||
// Copyright © 2010 Cinema Squid
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//=============================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Model.IO;
|
||||
|
||||
namespace BDInfo
|
||||
{
|
||||
public class BDROM
|
||||
{
|
||||
public FileSystemMetadata DirectoryRoot = null;
|
||||
public FileSystemMetadata DirectoryBDMV = null;
|
||||
public FileSystemMetadata DirectoryBDJO = null;
|
||||
public FileSystemMetadata DirectoryCLIPINF = null;
|
||||
public FileSystemMetadata DirectoryPLAYLIST = null;
|
||||
public FileSystemMetadata DirectorySNP = null;
|
||||
public FileSystemMetadata DirectorySSIF = null;
|
||||
public FileSystemMetadata DirectorySTREAM = null;
|
||||
|
||||
public string VolumeLabel = null;
|
||||
public ulong Size = 0;
|
||||
public bool IsBDPlus = false;
|
||||
public bool IsBDJava = false;
|
||||
public bool IsDBOX = false;
|
||||
public bool IsPSP = false;
|
||||
public bool Is3D = false;
|
||||
public bool Is50Hz = false;
|
||||
|
||||
private readonly IFileSystem _fileSystem;
|
||||
|
||||
public Dictionary<string, TSPlaylistFile> PlaylistFiles =
|
||||
new Dictionary<string, TSPlaylistFile>();
|
||||
public Dictionary<string, TSStreamClipFile> StreamClipFiles =
|
||||
new Dictionary<string, TSStreamClipFile>();
|
||||
public Dictionary<string, TSStreamFile> StreamFiles =
|
||||
new Dictionary<string, TSStreamFile>();
|
||||
public Dictionary<string, TSInterleavedFile> InterleavedFiles =
|
||||
new Dictionary<string, TSInterleavedFile>();
|
||||
|
||||
public delegate bool OnStreamClipFileScanError(
|
||||
TSStreamClipFile streamClipFile, Exception ex);
|
||||
|
||||
public event OnStreamClipFileScanError StreamClipFileScanError;
|
||||
|
||||
public delegate bool OnStreamFileScanError(
|
||||
TSStreamFile streamClipFile, Exception ex);
|
||||
|
||||
public event OnStreamFileScanError StreamFileScanError;
|
||||
|
||||
public delegate bool OnPlaylistFileScanError(
|
||||
TSPlaylistFile playlistFile, Exception ex);
|
||||
|
||||
public event OnPlaylistFileScanError PlaylistFileScanError;
|
||||
|
||||
public BDROM(string path, IFileSystem fileSystem)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(path));
|
||||
}
|
||||
|
||||
_fileSystem = fileSystem;
|
||||
//
|
||||
// Locate BDMV directories.
|
||||
//
|
||||
|
||||
DirectoryBDMV =
|
||||
GetDirectoryBDMV(path);
|
||||
|
||||
if (DirectoryBDMV == null)
|
||||
{
|
||||
throw new Exception("Unable to locate BD structure.");
|
||||
}
|
||||
|
||||
DirectoryRoot =
|
||||
_fileSystem.GetDirectoryInfo(Path.GetDirectoryName(DirectoryBDMV.FullName));
|
||||
DirectoryBDJO =
|
||||
GetDirectory("BDJO", DirectoryBDMV, 0);
|
||||
DirectoryCLIPINF =
|
||||
GetDirectory("CLIPINF", DirectoryBDMV, 0);
|
||||
DirectoryPLAYLIST =
|
||||
GetDirectory("PLAYLIST", DirectoryBDMV, 0);
|
||||
DirectorySNP =
|
||||
GetDirectory("SNP", DirectoryRoot, 0);
|
||||
DirectorySTREAM =
|
||||
GetDirectory("STREAM", DirectoryBDMV, 0);
|
||||
DirectorySSIF =
|
||||
GetDirectory("SSIF", DirectorySTREAM, 0);
|
||||
|
||||
if (DirectoryCLIPINF == null
|
||||
|| DirectoryPLAYLIST == null)
|
||||
{
|
||||
throw new Exception("Unable to locate BD structure.");
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize basic disc properties.
|
||||
//
|
||||
|
||||
VolumeLabel = GetVolumeLabel(DirectoryRoot);
|
||||
Size = (ulong)GetDirectorySize(DirectoryRoot);
|
||||
|
||||
if (null != GetDirectory("BDSVM", DirectoryRoot, 0))
|
||||
{
|
||||
IsBDPlus = true;
|
||||
}
|
||||
if (null != GetDirectory("SLYVM", DirectoryRoot, 0))
|
||||
{
|
||||
IsBDPlus = true;
|
||||
}
|
||||
if (null != GetDirectory("ANYVM", DirectoryRoot, 0))
|
||||
{
|
||||
IsBDPlus = true;
|
||||
}
|
||||
|
||||
if (DirectoryBDJO != null &&
|
||||
_fileSystem.GetFilePaths(DirectoryBDJO.FullName).Any())
|
||||
{
|
||||
IsBDJava = true;
|
||||
}
|
||||
|
||||
if (DirectorySNP != null &&
|
||||
GetFilePaths(DirectorySNP.FullName, ".mnv").Any())
|
||||
{
|
||||
IsPSP = true;
|
||||
}
|
||||
|
||||
if (DirectorySSIF != null &&
|
||||
_fileSystem.GetFilePaths(DirectorySSIF.FullName).Any())
|
||||
{
|
||||
Is3D = true;
|
||||
}
|
||||
|
||||
if (File.Exists(Path.Combine(DirectoryRoot.FullName, "FilmIndex.xml")))
|
||||
{
|
||||
IsDBOX = true;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize file lists.
|
||||
//
|
||||
|
||||
if (DirectoryPLAYLIST != null)
|
||||
{
|
||||
FileSystemMetadata[] files = GetFiles(DirectoryPLAYLIST.FullName, ".mpls").ToArray();
|
||||
foreach (var file in files)
|
||||
{
|
||||
PlaylistFiles.Add(
|
||||
file.Name.ToUpper(), new TSPlaylistFile(this, file));
|
||||
}
|
||||
}
|
||||
|
||||
if (DirectorySTREAM != null)
|
||||
{
|
||||
FileSystemMetadata[] files = GetFiles(DirectorySTREAM.FullName, ".m2ts").ToArray();
|
||||
foreach (var file in files)
|
||||
{
|
||||
StreamFiles.Add(
|
||||
file.Name.ToUpper(), new TSStreamFile(file, _fileSystem));
|
||||
}
|
||||
}
|
||||
|
||||
if (DirectoryCLIPINF != null)
|
||||
{
|
||||
FileSystemMetadata[] files = GetFiles(DirectoryCLIPINF.FullName, ".clpi").ToArray();
|
||||
foreach (var file in files)
|
||||
{
|
||||
StreamClipFiles.Add(
|
||||
file.Name.ToUpper(), new TSStreamClipFile(file));
|
||||
}
|
||||
}
|
||||
|
||||
if (DirectorySSIF != null)
|
||||
{
|
||||
FileSystemMetadata[] files = GetFiles(DirectorySSIF.FullName, ".ssif").ToArray();
|
||||
foreach (var file in files)
|
||||
{
|
||||
InterleavedFiles.Add(
|
||||
file.Name.ToUpper(), new TSInterleavedFile(file));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<FileSystemMetadata> GetFiles(string path, string extension)
|
||||
{
|
||||
return _fileSystem.GetFiles(path, new[] { extension }, false, false);
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetFilePaths(string path, string extension)
|
||||
{
|
||||
return _fileSystem.GetFilePaths(path, new[] { extension }, false, false);
|
||||
}
|
||||
|
||||
public void Scan()
|
||||
{
|
||||
foreach (var streamClipFile in StreamClipFiles.Values)
|
||||
{
|
||||
try
|
||||
{
|
||||
streamClipFile.Scan();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (StreamClipFileScanError != null)
|
||||
{
|
||||
if (StreamClipFileScanError(streamClipFile, ex))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else throw;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var streamFile in StreamFiles.Values)
|
||||
{
|
||||
string ssifName = Path.GetFileNameWithoutExtension(streamFile.Name) + ".SSIF";
|
||||
if (InterleavedFiles.ContainsKey(ssifName))
|
||||
{
|
||||
streamFile.InterleavedFile = InterleavedFiles[ssifName];
|
||||
}
|
||||
}
|
||||
|
||||
TSStreamFile[] streamFiles = new TSStreamFile[StreamFiles.Count];
|
||||
StreamFiles.Values.CopyTo(streamFiles, 0);
|
||||
Array.Sort(streamFiles, CompareStreamFiles);
|
||||
|
||||
foreach (var playlistFile in PlaylistFiles.Values)
|
||||
{
|
||||
try
|
||||
{
|
||||
playlistFile.Scan(StreamFiles, StreamClipFiles);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (PlaylistFileScanError != null)
|
||||
{
|
||||
if (PlaylistFileScanError(playlistFile, ex))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else throw;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var streamFile in streamFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
var playlists = new List<TSPlaylistFile>();
|
||||
foreach (var playlist in PlaylistFiles.Values)
|
||||
{
|
||||
foreach (var streamClip in playlist.StreamClips)
|
||||
{
|
||||
if (streamClip.Name == streamFile.Name)
|
||||
{
|
||||
playlists.Add(playlist);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
streamFile.Scan(playlists, false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (StreamFileScanError != null)
|
||||
{
|
||||
if (StreamFileScanError(streamFile, ex))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else throw;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var playlistFile in PlaylistFiles.Values)
|
||||
{
|
||||
playlistFile.Initialize();
|
||||
if (!Is50Hz)
|
||||
{
|
||||
foreach (var videoStream in playlistFile.VideoStreams)
|
||||
{
|
||||
if (videoStream.FrameRate == TSFrameRate.FRAMERATE_25 ||
|
||||
videoStream.FrameRate == TSFrameRate.FRAMERATE_50)
|
||||
{
|
||||
Is50Hz = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private FileSystemMetadata GetDirectoryBDMV(
|
||||
string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(path));
|
||||
}
|
||||
|
||||
FileSystemMetadata dir = _fileSystem.GetDirectoryInfo(path);
|
||||
|
||||
while (dir != null)
|
||||
{
|
||||
if (string.Equals(dir.Name, "BDMV", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return dir;
|
||||
}
|
||||
var parentFolder = Path.GetDirectoryName(dir.FullName);
|
||||
if (string.IsNullOrEmpty(parentFolder))
|
||||
{
|
||||
dir = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
dir = _fileSystem.GetDirectoryInfo(parentFolder);
|
||||
}
|
||||
}
|
||||
|
||||
return GetDirectory("BDMV", _fileSystem.GetDirectoryInfo(path), 0);
|
||||
}
|
||||
|
||||
private FileSystemMetadata GetDirectory(
|
||||
string name,
|
||||
FileSystemMetadata dir,
|
||||
int searchDepth)
|
||||
{
|
||||
if (dir != null)
|
||||
{
|
||||
FileSystemMetadata[] children = _fileSystem.GetDirectories(dir.FullName).ToArray();
|
||||
foreach (var child in children)
|
||||
{
|
||||
if (string.Equals(child.Name, name, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return child;
|
||||
}
|
||||
}
|
||||
if (searchDepth > 0)
|
||||
{
|
||||
foreach (var child in children)
|
||||
{
|
||||
GetDirectory(
|
||||
name, child, searchDepth - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private long GetDirectorySize(FileSystemMetadata directoryInfo)
|
||||
{
|
||||
long size = 0;
|
||||
|
||||
//if (!ExcludeDirs.Contains(directoryInfo.Name.ToUpper())) // TODO: Keep?
|
||||
{
|
||||
FileSystemMetadata[] pathFiles = _fileSystem.GetFiles(directoryInfo.FullName).ToArray();
|
||||
foreach (var pathFile in pathFiles)
|
||||
{
|
||||
if (pathFile.Extension.ToUpper() == ".SSIF")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
size += pathFile.Length;
|
||||
}
|
||||
|
||||
FileSystemMetadata[] pathChildren = _fileSystem.GetDirectories(directoryInfo.FullName).ToArray();
|
||||
foreach (var pathChild in pathChildren)
|
||||
{
|
||||
size += GetDirectorySize(pathChild);
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
private string GetVolumeLabel(FileSystemMetadata dir)
|
||||
{
|
||||
return dir.Name;
|
||||
}
|
||||
|
||||
public int CompareStreamFiles(
|
||||
TSStreamFile x,
|
||||
TSStreamFile y)
|
||||
{
|
||||
// TODO: Use interleaved file sizes
|
||||
|
||||
if ((x == null || x.FileInfo == null) && (y == null || y.FileInfo == null))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if ((x == null || x.FileInfo == null) && (y != null && y.FileInfo != null))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if ((x != null && x.FileInfo != null) && (y == null || y.FileInfo == null))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x.FileInfo.Length > y.FileInfo.Length)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (y.FileInfo.Length > x.FileInfo.Length)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,493 +0,0 @@
|
||||
//============================================================================
|
||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||
// Copyright © 2010 Cinema Squid
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//=============================================================================
|
||||
|
||||
|
||||
namespace BDInfo
|
||||
{
|
||||
public abstract class LanguageCodes
|
||||
{
|
||||
public static string GetName(string code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case "abk": return "Abkhazian";
|
||||
case "ace": return "Achinese";
|
||||
case "ach": return "Acoli";
|
||||
case "ada": return "Adangme";
|
||||
case "aar": return "Afar";
|
||||
case "afh": return "Afrihili";
|
||||
case "afr": return "Afrikaans";
|
||||
case "afa": return "Afro-Asiatic (Other)";
|
||||
case "aka": return "Akan";
|
||||
case "akk": return "Akkadian";
|
||||
case "alb": return "Albanian";
|
||||
case "sqi": return "Albanian";
|
||||
case "ale": return "Aleut";
|
||||
case "alg": return "Algonquian languages";
|
||||
case "tut": return "Altaic (Other)";
|
||||
case "amh": return "Amharic";
|
||||
case "apa": return "Apache languages";
|
||||
case "ara": return "Arabic";
|
||||
case "arc": return "Aramaic";
|
||||
case "arp": return "Arapaho";
|
||||
case "arn": return "Araucanian";
|
||||
case "arw": return "Arawak";
|
||||
case "arm": return "Armenian";
|
||||
case "hye": return "Armenian";
|
||||
case "art": return "Artificial (Other)";
|
||||
case "asm": return "Assamese";
|
||||
case "ath": return "Athapascan languages";
|
||||
case "aus": return "Australian languages";
|
||||
case "map": return "Austronesian (Other)";
|
||||
case "ava": return "Avaric";
|
||||
case "ave": return "Avestan";
|
||||
case "awa": return "Awadhi";
|
||||
case "aym": return "Aymara";
|
||||
case "aze": return "Azerbaijani";
|
||||
case "ban": return "Balinese";
|
||||
case "bat": return "Baltic (Other)";
|
||||
case "bal": return "Baluchi";
|
||||
case "bam": return "Bambara";
|
||||
case "bai": return "Bamileke languages";
|
||||
case "bad": return "Banda";
|
||||
case "bnt": return "Bantu (Other)";
|
||||
case "bas": return "Basa";
|
||||
case "bak": return "Bashkir";
|
||||
case "baq": return "Basque";
|
||||
case "eus": return "Basque";
|
||||
case "btk": return "Batak (Indonesia)";
|
||||
case "bej": return "Beja";
|
||||
case "bel": return "Belarusian";
|
||||
case "bem": return "Bemba";
|
||||
case "ben": return "Bengali";
|
||||
case "ber": return "Berber (Other)";
|
||||
case "bho": return "Bhojpuri";
|
||||
case "bih": return "Bihari";
|
||||
case "bik": return "Bikol";
|
||||
case "bin": return "Bini";
|
||||
case "bis": return "Bislama";
|
||||
case "bos": return "Bosnian";
|
||||
case "bra": return "Braj";
|
||||
case "bre": return "Breton";
|
||||
case "bug": return "Buginese";
|
||||
case "bul": return "Bulgarian";
|
||||
case "bua": return "Buriat";
|
||||
case "bur": return "Burmese";
|
||||
case "mya": return "Burmese";
|
||||
case "cad": return "Caddo";
|
||||
case "car": return "Carib";
|
||||
case "cat": return "Catalan";
|
||||
case "cau": return "Caucasian (Other)";
|
||||
case "ceb": return "Cebuano";
|
||||
case "cel": return "Celtic (Other)";
|
||||
case "cai": return "Central American Indian (Other)";
|
||||
case "chg": return "Chagatai";
|
||||
case "cmc": return "Chamic languages";
|
||||
case "cha": return "Chamorro";
|
||||
case "che": return "Chechen";
|
||||
case "chr": return "Cherokee";
|
||||
case "chy": return "Cheyenne";
|
||||
case "chb": return "Chibcha";
|
||||
case "chi": return "Chinese";
|
||||
case "zho": return "Chinese";
|
||||
case "chn": return "Chinook jargon";
|
||||
case "chp": return "Chipewyan";
|
||||
case "cho": return "Choctaw";
|
||||
case "chu": return "Church Slavic";
|
||||
case "chk": return "Chuukese";
|
||||
case "chv": return "Chuvash";
|
||||
case "cop": return "Coptic";
|
||||
case "cor": return "Cornish";
|
||||
case "cos": return "Corsican";
|
||||
case "cre": return "Cree";
|
||||
case "mus": return "Creek";
|
||||
case "crp": return "Creoles and pidgins (Other)";
|
||||
case "cpe": return "Creoles and pidgins,";
|
||||
case "cpf": return "Creoles and pidgins,";
|
||||
case "cpp": return "Creoles and pidgins,";
|
||||
case "scr": return "Croatian";
|
||||
case "hrv": return "Croatian";
|
||||
case "cus": return "Cushitic (Other)";
|
||||
case "cze": return "Czech";
|
||||
case "ces": return "Czech";
|
||||
case "dak": return "Dakota";
|
||||
case "dan": return "Danish";
|
||||
case "day": return "Dayak";
|
||||
case "del": return "Delaware";
|
||||
case "din": return "Dinka";
|
||||
case "div": return "Divehi";
|
||||
case "doi": return "Dogri";
|
||||
case "dgr": return "Dogrib";
|
||||
case "dra": return "Dravidian (Other)";
|
||||
case "dua": return "Duala";
|
||||
case "dut": return "Dutch";
|
||||
case "nld": return "Dutch";
|
||||
case "dum": return "Dutch, Middle (ca. 1050-1350)";
|
||||
case "dyu": return "Dyula";
|
||||
case "dzo": return "Dzongkha";
|
||||
case "efi": return "Efik";
|
||||
case "egy": return "Egyptian (Ancient)";
|
||||
case "eka": return "Ekajuk";
|
||||
case "elx": return "Elamite";
|
||||
case "eng": return "English";
|
||||
case "enm": return "English, Middle (1100-1500)";
|
||||
case "ang": return "English, Old (ca.450-1100)";
|
||||
case "epo": return "Esperanto";
|
||||
case "est": return "Estonian";
|
||||
case "ewe": return "Ewe";
|
||||
case "ewo": return "Ewondo";
|
||||
case "fan": return "Fang";
|
||||
case "fat": return "Fanti";
|
||||
case "fao": return "Faroese";
|
||||
case "fij": return "Fijian";
|
||||
case "fin": return "Finnish";
|
||||
case "fiu": return "Finno-Ugrian (Other)";
|
||||
case "fon": return "Fon";
|
||||
case "fre": return "French";
|
||||
case "fra": return "French";
|
||||
case "frm": return "French, Middle (ca.1400-1600)";
|
||||
case "fro": return "French, Old (842-ca.1400)";
|
||||
case "fry": return "Frisian";
|
||||
case "fur": return "Friulian";
|
||||
case "ful": return "Fulah";
|
||||
case "gaa": return "Ga";
|
||||
case "glg": return "Gallegan";
|
||||
case "lug": return "Ganda";
|
||||
case "gay": return "Gayo";
|
||||
case "gba": return "Gbaya";
|
||||
case "gez": return "Geez";
|
||||
case "geo": return "Georgian";
|
||||
case "kat": return "Georgian";
|
||||
case "ger": return "German";
|
||||
case "deu": return "German";
|
||||
case "nds": return "Saxon";
|
||||
case "gmh": return "German, Middle High (ca.1050-1500)";
|
||||
case "goh": return "German, Old High (ca.750-1050)";
|
||||
case "gem": return "Germanic (Other)";
|
||||
case "gil": return "Gilbertese";
|
||||
case "gon": return "Gondi";
|
||||
case "gor": return "Gorontalo";
|
||||
case "got": return "Gothic";
|
||||
case "grb": return "Grebo";
|
||||
case "grc": return "Greek, Ancient (to 1453)";
|
||||
case "gre": return "Greek";
|
||||
case "ell": return "Greek";
|
||||
case "grn": return "Guarani";
|
||||
case "guj": return "Gujarati";
|
||||
case "gwi": return "Gwich´in";
|
||||
case "hai": return "Haida";
|
||||
case "hau": return "Hausa";
|
||||
case "haw": return "Hawaiian";
|
||||
case "heb": return "Hebrew";
|
||||
case "her": return "Herero";
|
||||
case "hil": return "Hiligaynon";
|
||||
case "him": return "Himachali";
|
||||
case "hin": return "Hindi";
|
||||
case "hmo": return "Hiri Motu";
|
||||
case "hit": return "Hittite";
|
||||
case "hmn": return "Hmong";
|
||||
case "hun": return "Hungarian";
|
||||
case "hup": return "Hupa";
|
||||
case "iba": return "Iban";
|
||||
case "ice": return "Icelandic";
|
||||
case "isl": return "Icelandic";
|
||||
case "ibo": return "Igbo";
|
||||
case "ijo": return "Ijo";
|
||||
case "ilo": return "Iloko";
|
||||
case "inc": return "Indic (Other)";
|
||||
case "ine": return "Indo-European (Other)";
|
||||
case "ind": return "Indonesian";
|
||||
case "ina": return "Interlingua (International";
|
||||
case "ile": return "Interlingue";
|
||||
case "iku": return "Inuktitut";
|
||||
case "ipk": return "Inupiaq";
|
||||
case "ira": return "Iranian (Other)";
|
||||
case "gle": return "Irish";
|
||||
case "mga": return "Irish, Middle (900-1200)";
|
||||
case "sga": return "Irish, Old (to 900)";
|
||||
case "iro": return "Iroquoian languages";
|
||||
case "ita": return "Italian";
|
||||
case "jpn": return "Japanese";
|
||||
case "jav": return "Javanese";
|
||||
case "jrb": return "Judeo-Arabic";
|
||||
case "jpr": return "Judeo-Persian";
|
||||
case "kab": return "Kabyle";
|
||||
case "kac": return "Kachin";
|
||||
case "kal": return "Kalaallisut";
|
||||
case "kam": return "Kamba";
|
||||
case "kan": return "Kannada";
|
||||
case "kau": return "Kanuri";
|
||||
case "kaa": return "Kara-Kalpak";
|
||||
case "kar": return "Karen";
|
||||
case "kas": return "Kashmiri";
|
||||
case "kaw": return "Kawi";
|
||||
case "kaz": return "Kazakh";
|
||||
case "kha": return "Khasi";
|
||||
case "khm": return "Khmer";
|
||||
case "khi": return "Khoisan (Other)";
|
||||
case "kho": return "Khotanese";
|
||||
case "kik": return "Kikuyu";
|
||||
case "kmb": return "Kimbundu";
|
||||
case "kin": return "Kinyarwanda";
|
||||
case "kir": return "Kirghiz";
|
||||
case "kom": return "Komi";
|
||||
case "kon": return "Kongo";
|
||||
case "kok": return "Konkani";
|
||||
case "kor": return "Korean";
|
||||
case "kos": return "Kosraean";
|
||||
case "kpe": return "Kpelle";
|
||||
case "kro": return "Kru";
|
||||
case "kua": return "Kuanyama";
|
||||
case "kum": return "Kumyk";
|
||||
case "kur": return "Kurdish";
|
||||
case "kru": return "Kurukh";
|
||||
case "kut": return "Kutenai";
|
||||
case "lad": return "Ladino";
|
||||
case "lah": return "Lahnda";
|
||||
case "lam": return "Lamba";
|
||||
case "lao": return "Lao";
|
||||
case "lat": return "Latin";
|
||||
case "lav": return "Latvian";
|
||||
case "ltz": return "Letzeburgesch";
|
||||
case "lez": return "Lezghian";
|
||||
case "lin": return "Lingala";
|
||||
case "lit": return "Lithuanian";
|
||||
case "loz": return "Lozi";
|
||||
case "lub": return "Luba-Katanga";
|
||||
case "lua": return "Luba-Lulua";
|
||||
case "lui": return "Luiseno";
|
||||
case "lun": return "Lunda";
|
||||
case "luo": return "Luo (Kenya and Tanzania)";
|
||||
case "lus": return "Lushai";
|
||||
case "mac": return "Macedonian";
|
||||
case "mkd": return "Macedonian";
|
||||
case "mad": return "Madurese";
|
||||
case "mag": return "Magahi";
|
||||
case "mai": return "Maithili";
|
||||
case "mak": return "Makasar";
|
||||
case "mlg": return "Malagasy";
|
||||
case "may": return "Malay";
|
||||
case "msa": return "Malay";
|
||||
case "mal": return "Malayalam";
|
||||
case "mlt": return "Maltese";
|
||||
case "mnc": return "Manchu";
|
||||
case "mdr": return "Mandar";
|
||||
case "man": return "Mandingo";
|
||||
case "mni": return "Manipuri";
|
||||
case "mno": return "Manobo languages";
|
||||
case "glv": return "Manx";
|
||||
case "mao": return "Maori";
|
||||
case "mri": return "Maori";
|
||||
case "mar": return "Marathi";
|
||||
case "chm": return "Mari";
|
||||
case "mah": return "Marshall";
|
||||
case "mwr": return "Marwari";
|
||||
case "mas": return "Masai";
|
||||
case "myn": return "Mayan languages";
|
||||
case "men": return "Mende";
|
||||
case "mic": return "Micmac";
|
||||
case "min": return "Minangkabau";
|
||||
case "mis": return "Miscellaneous languages";
|
||||
case "moh": return "Mohawk";
|
||||
case "mol": return "Moldavian";
|
||||
case "mkh": return "Mon-Khmer (Other)";
|
||||
case "lol": return "Mongo";
|
||||
case "mon": return "Mongolian";
|
||||
case "mos": return "Mossi";
|
||||
case "mul": return "Multiple languages";
|
||||
case "mun": return "Munda languages";
|
||||
case "nah": return "Nahuatl";
|
||||
case "nau": return "Nauru";
|
||||
case "nav": return "Navajo";
|
||||
case "nde": return "Ndebele, North";
|
||||
case "nbl": return "Ndebele, South";
|
||||
case "ndo": return "Ndonga";
|
||||
case "nep": return "Nepali";
|
||||
case "new": return "Newari";
|
||||
case "nia": return "Nias";
|
||||
case "nic": return "Niger-Kordofanian (Other)";
|
||||
case "ssa": return "Nilo-Saharan (Other)";
|
||||
case "niu": return "Niuean";
|
||||
case "non": return "Norse, Old";
|
||||
case "nai": return "North American Indian (Other)";
|
||||
case "sme": return "Northern Sami";
|
||||
case "nor": return "Norwegian";
|
||||
case "nob": return "Norwegian Bokmål";
|
||||
case "nno": return "Norwegian Nynorsk";
|
||||
case "nub": return "Nubian languages";
|
||||
case "nym": return "Nyamwezi";
|
||||
case "nya": return "Nyanja";
|
||||
case "nyn": return "Nyankole";
|
||||
case "nyo": return "Nyoro";
|
||||
case "nzi": return "Nzima";
|
||||
case "oci": return "Occitan";
|
||||
case "oji": return "Ojibwa";
|
||||
case "ori": return "Oriya";
|
||||
case "orm": return "Oromo";
|
||||
case "osa": return "Osage";
|
||||
case "oss": return "Ossetian";
|
||||
case "oto": return "Otomian languages";
|
||||
case "pal": return "Pahlavi";
|
||||
case "pau": return "Palauan";
|
||||
case "pli": return "Pali";
|
||||
case "pam": return "Pampanga";
|
||||
case "pag": return "Pangasinan";
|
||||
case "pan": return "Panjabi";
|
||||
case "pap": return "Papiamento";
|
||||
case "paa": return "Papuan (Other)";
|
||||
case "per": return "Persian";
|
||||
case "fas": return "Persian";
|
||||
case "peo": return "Persian, Old (ca.600-400 B.C.)";
|
||||
case "phi": return "Philippine (Other)";
|
||||
case "phn": return "Phoenician";
|
||||
case "pon": return "Pohnpeian";
|
||||
case "pol": return "Polish";
|
||||
case "por": return "Portuguese";
|
||||
case "pra": return "Prakrit languages";
|
||||
case "pro": return "Provençal";
|
||||
case "pus": return "Pushto";
|
||||
case "que": return "Quechua";
|
||||
case "roh": return "Raeto-Romance";
|
||||
case "raj": return "Rajasthani";
|
||||
case "rap": return "Rapanui";
|
||||
case "rar": return "Rarotongan";
|
||||
case "roa": return "Romance (Other)";
|
||||
case "rum": return "Romanian";
|
||||
case "ron": return "Romanian";
|
||||
case "rom": return "Romany";
|
||||
case "run": return "Rundi";
|
||||
case "rus": return "Russian";
|
||||
case "sal": return "Salishan languages";
|
||||
case "sam": return "Samaritan Aramaic";
|
||||
case "smi": return "Sami languages (Other)";
|
||||
case "smo": return "Samoan";
|
||||
case "sad": return "Sandawe";
|
||||
case "sag": return "Sango";
|
||||
case "san": return "Sanskrit";
|
||||
case "sat": return "Santali";
|
||||
case "srd": return "Sardinian";
|
||||
case "sas": return "Sasak";
|
||||
case "sco": return "Scots";
|
||||
case "gla": return "Gaelic";
|
||||
case "sel": return "Selkup";
|
||||
case "sem": return "Semitic (Other)";
|
||||
case "scc": return "Serbian";
|
||||
case "srp": return "Serbian";
|
||||
case "srr": return "Serer";
|
||||
case "shn": return "Shan";
|
||||
case "sna": return "Shona";
|
||||
case "sid": return "Sidamo";
|
||||
case "sgn": return "Sign languages";
|
||||
case "bla": return "Siksika";
|
||||
case "snd": return "Sindhi";
|
||||
case "sin": return "Sinhalese";
|
||||
case "sit": return "Sino-Tibetan (Other)";
|
||||
case "sio": return "Siouan languages";
|
||||
case "den": return "Slave (Athapascan)";
|
||||
case "sla": return "Slavic (Other)";
|
||||
case "slo": return "Slovak";
|
||||
case "slk": return "Slovak";
|
||||
case "slv": return "Slovenian";
|
||||
case "sog": return "Sogdian";
|
||||
case "som": return "Somali";
|
||||
case "son": return "Songhai";
|
||||
case "snk": return "Soninke";
|
||||
case "wen": return "Sorbian languages";
|
||||
case "nso": return "Sotho, Northern";
|
||||
case "sot": return "Sotho, Southern";
|
||||
case "sai": return "South American Indian (Other)";
|
||||
case "spa": return "Spanish";
|
||||
case "suk": return "Sukuma";
|
||||
case "sux": return "Sumerian";
|
||||
case "sun": return "Sundanese";
|
||||
case "sus": return "Susu";
|
||||
case "swa": return "Swahili";
|
||||
case "ssw": return "Swati";
|
||||
case "swe": return "Swedish";
|
||||
case "syr": return "Syriac";
|
||||
case "tgl": return "Tagalog";
|
||||
case "tah": return "Tahitian";
|
||||
case "tai": return "Tai (Other)";
|
||||
case "tgk": return "Tajik";
|
||||
case "tmh": return "Tamashek";
|
||||
case "tam": return "Tamil";
|
||||
case "tat": return "Tatar";
|
||||
case "tel": return "Telugu";
|
||||
case "ter": return "Tereno";
|
||||
case "tet": return "Tetum";
|
||||
case "tha": return "Thai";
|
||||
case "tib": return "Tibetan";
|
||||
case "bod": return "Tibetan";
|
||||
case "tig": return "Tigre";
|
||||
case "tir": return "Tigrinya";
|
||||
case "tem": return "Timne";
|
||||
case "tiv": return "Tiv";
|
||||
case "tli": return "Tlingit";
|
||||
case "tpi": return "Tok Pisin";
|
||||
case "tkl": return "Tokelau";
|
||||
case "tog": return "Tonga (Nyasa)";
|
||||
case "ton": return "Tonga (Tonga Islands)";
|
||||
case "tsi": return "Tsimshian";
|
||||
case "tso": return "Tsonga";
|
||||
case "tsn": return "Tswana";
|
||||
case "tum": return "Tumbuka";
|
||||
case "tur": return "Turkish";
|
||||
case "ota": return "Turkish, Ottoman (1500-1928)";
|
||||
case "tuk": return "Turkmen";
|
||||
case "tvl": return "Tuvalu";
|
||||
case "tyv": return "Tuvinian";
|
||||
case "twi": return "Twi";
|
||||
case "uga": return "Ugaritic";
|
||||
case "uig": return "Uighur";
|
||||
case "ukr": return "Ukrainian";
|
||||
case "umb": return "Umbundu";
|
||||
case "und": return "Undetermined";
|
||||
case "urd": return "Urdu";
|
||||
case "uzb": return "Uzbek";
|
||||
case "vai": return "Vai";
|
||||
case "ven": return "Venda";
|
||||
case "vie": return "Vietnamese";
|
||||
case "vol": return "Volapük";
|
||||
case "vot": return "Votic";
|
||||
case "wak": return "Wakashan languages";
|
||||
case "wal": return "Walamo";
|
||||
case "war": return "Waray";
|
||||
case "was": return "Washo";
|
||||
case "wel": return "Welsh";
|
||||
case "cym": return "Welsh";
|
||||
case "wol": return "Wolof";
|
||||
case "xho": return "Xhosa";
|
||||
case "sah": return "Yakut";
|
||||
case "yao": return "Yao";
|
||||
case "yap": return "Yapese";
|
||||
case "yid": return "Yiddish";
|
||||
case "yor": return "Yoruba";
|
||||
case "ypk": return "Yupik languages";
|
||||
case "znd": return "Zande";
|
||||
case "zap": return "Zapotec";
|
||||
case "zen": return "Zenaga";
|
||||
case "zha": return "Zhuang";
|
||||
case "zul": return "Zulu";
|
||||
case "zun": return "Zuni";
|
||||
|
||||
default: return code;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("BDInfo")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Jellyfin Project")]
|
||||
[assembly: AssemblyProduct("Jellyfin Server")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016 CinemaSquid. Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
|
||||
// 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
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
@@ -1,5 +0,0 @@
|
||||
The source is taken from the BDRom folder of this project:
|
||||
|
||||
http://www.cinemasquid.com/blu-ray/tools/bdinfo
|
||||
|
||||
BDInfoSettings was taken from the FormSettings class, and changed so that the settings all return defaults.
|
||||
@@ -1,309 +0,0 @@
|
||||
//============================================================================
|
||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||
// Copyright © 2010 Cinema Squid
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//=============================================================================
|
||||
|
||||
#undef DEBUG
|
||||
using System.IO;
|
||||
|
||||
namespace BDInfo
|
||||
{
|
||||
public abstract class TSCodecAC3
|
||||
{
|
||||
private static byte[] eac3_blocks = new byte[] { 1, 2, 3, 6 };
|
||||
|
||||
public static void Scan(
|
||||
TSAudioStream stream,
|
||||
TSStreamBuffer buffer,
|
||||
ref string tag)
|
||||
{
|
||||
if (stream.IsInitialized) return;
|
||||
|
||||
byte[] sync = buffer.ReadBytes(2);
|
||||
if (sync == null ||
|
||||
sync[0] != 0x0B ||
|
||||
sync[1] != 0x77)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int sr_code = 0;
|
||||
int frame_size = 0;
|
||||
int frame_size_code = 0;
|
||||
int channel_mode = 0;
|
||||
int lfe_on = 0;
|
||||
int dial_norm = 0;
|
||||
int num_blocks = 0;
|
||||
|
||||
byte[] hdr = buffer.ReadBytes(4);
|
||||
int bsid = (hdr[3] & 0xF8) >> 3;
|
||||
buffer.Seek(-4, SeekOrigin.Current);
|
||||
if (bsid <= 10)
|
||||
{
|
||||
byte[] crc = buffer.ReadBytes(2);
|
||||
sr_code = buffer.ReadBits(2);
|
||||
frame_size_code = buffer.ReadBits(6);
|
||||
bsid = buffer.ReadBits(5);
|
||||
int bsmod = buffer.ReadBits(3);
|
||||
|
||||
channel_mode = buffer.ReadBits(3);
|
||||
int cmixlev = 0;
|
||||
if (((channel_mode & 0x1) > 0) && (channel_mode != 0x1))
|
||||
{
|
||||
cmixlev = buffer.ReadBits(2);
|
||||
}
|
||||
int surmixlev = 0;
|
||||
if ((channel_mode & 0x4) > 0)
|
||||
{
|
||||
surmixlev = buffer.ReadBits(2);
|
||||
}
|
||||
int dsurmod = 0;
|
||||
if (channel_mode == 0x2)
|
||||
{
|
||||
dsurmod = buffer.ReadBits(2);
|
||||
if (dsurmod == 0x2)
|
||||
{
|
||||
stream.AudioMode = TSAudioMode.Surround;
|
||||
}
|
||||
}
|
||||
lfe_on = buffer.ReadBits(1);
|
||||
dial_norm = buffer.ReadBits(5);
|
||||
int compr = 0;
|
||||
if (1 == buffer.ReadBits(1))
|
||||
{
|
||||
compr = buffer.ReadBits(8);
|
||||
}
|
||||
int langcod = 0;
|
||||
if (1 == buffer.ReadBits(1))
|
||||
{
|
||||
langcod = buffer.ReadBits(8);
|
||||
}
|
||||
int mixlevel = 0;
|
||||
int roomtyp = 0;
|
||||
if (1 == buffer.ReadBits(1))
|
||||
{
|
||||
mixlevel = buffer.ReadBits(5);
|
||||
roomtyp = buffer.ReadBits(2);
|
||||
}
|
||||
if (channel_mode == 0)
|
||||
{
|
||||
int dialnorm2 = buffer.ReadBits(5);
|
||||
int compr2 = 0;
|
||||
if (1 == buffer.ReadBits(1))
|
||||
{
|
||||
compr2 = buffer.ReadBits(8);
|
||||
}
|
||||
int langcod2 = 0;
|
||||
if (1 == buffer.ReadBits(1))
|
||||
{
|
||||
langcod2 = buffer.ReadBits(8);
|
||||
}
|
||||
int mixlevel2 = 0;
|
||||
int roomtyp2 = 0;
|
||||
if (1 == buffer.ReadBits(1))
|
||||
{
|
||||
mixlevel2 = buffer.ReadBits(5);
|
||||
roomtyp2 = buffer.ReadBits(2);
|
||||
}
|
||||
}
|
||||
int copyrightb = buffer.ReadBits(1);
|
||||
int origbs = buffer.ReadBits(1);
|
||||
if (bsid == 6)
|
||||
{
|
||||
if (1 == buffer.ReadBits(1))
|
||||
{
|
||||
int dmixmod = buffer.ReadBits(2);
|
||||
int ltrtcmixlev = buffer.ReadBits(3);
|
||||
int ltrtsurmixlev = buffer.ReadBits(3);
|
||||
int lorocmixlev = buffer.ReadBits(3);
|
||||
int lorosurmixlev = buffer.ReadBits(3);
|
||||
}
|
||||
if (1 == buffer.ReadBits(1))
|
||||
{
|
||||
int dsurexmod = buffer.ReadBits(2);
|
||||
int dheadphonmod = buffer.ReadBits(2);
|
||||
if (dheadphonmod == 0x2)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
int adconvtyp = buffer.ReadBits(1);
|
||||
int xbsi2 = buffer.ReadBits(8);
|
||||
int encinfo = buffer.ReadBits(1);
|
||||
if (dsurexmod == 2)
|
||||
{
|
||||
stream.AudioMode = TSAudioMode.Extended;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int frame_type = buffer.ReadBits(2);
|
||||
int substreamid = buffer.ReadBits(3);
|
||||
frame_size = (buffer.ReadBits(11) + 1) << 1;
|
||||
|
||||
sr_code = buffer.ReadBits(2);
|
||||
if (sr_code == 3)
|
||||
{
|
||||
sr_code = buffer.ReadBits(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
num_blocks = buffer.ReadBits(2);
|
||||
}
|
||||
channel_mode = buffer.ReadBits(3);
|
||||
lfe_on = buffer.ReadBits(1);
|
||||
}
|
||||
|
||||
switch (channel_mode)
|
||||
{
|
||||
case 0: // 1+1
|
||||
stream.ChannelCount = 2;
|
||||
if (stream.AudioMode == TSAudioMode.Unknown)
|
||||
{
|
||||
stream.AudioMode = TSAudioMode.DualMono;
|
||||
}
|
||||
break;
|
||||
case 1: // 1/0
|
||||
stream.ChannelCount = 1;
|
||||
break;
|
||||
case 2: // 2/0
|
||||
stream.ChannelCount = 2;
|
||||
if (stream.AudioMode == TSAudioMode.Unknown)
|
||||
{
|
||||
stream.AudioMode = TSAudioMode.Stereo;
|
||||
}
|
||||
break;
|
||||
case 3: // 3/0
|
||||
stream.ChannelCount = 3;
|
||||
break;
|
||||
case 4: // 2/1
|
||||
stream.ChannelCount = 3;
|
||||
break;
|
||||
case 5: // 3/1
|
||||
stream.ChannelCount = 4;
|
||||
break;
|
||||
case 6: // 2/2
|
||||
stream.ChannelCount = 4;
|
||||
break;
|
||||
case 7: // 3/2
|
||||
stream.ChannelCount = 5;
|
||||
break;
|
||||
default:
|
||||
stream.ChannelCount = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (sr_code)
|
||||
{
|
||||
case 0:
|
||||
stream.SampleRate = 48000;
|
||||
break;
|
||||
case 1:
|
||||
stream.SampleRate = 44100;
|
||||
break;
|
||||
case 2:
|
||||
stream.SampleRate = 32000;
|
||||
break;
|
||||
default:
|
||||
stream.SampleRate = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (bsid <= 10)
|
||||
{
|
||||
switch (frame_size_code >> 1)
|
||||
{
|
||||
case 18:
|
||||
stream.BitRate = 640000;
|
||||
break;
|
||||
case 17:
|
||||
stream.BitRate = 576000;
|
||||
break;
|
||||
case 16:
|
||||
stream.BitRate = 512000;
|
||||
break;
|
||||
case 15:
|
||||
stream.BitRate = 448000;
|
||||
break;
|
||||
case 14:
|
||||
stream.BitRate = 384000;
|
||||
break;
|
||||
case 13:
|
||||
stream.BitRate = 320000;
|
||||
break;
|
||||
case 12:
|
||||
stream.BitRate = 256000;
|
||||
break;
|
||||
case 11:
|
||||
stream.BitRate = 224000;
|
||||
break;
|
||||
case 10:
|
||||
stream.BitRate = 192000;
|
||||
break;
|
||||
case 9:
|
||||
stream.BitRate = 160000;
|
||||
break;
|
||||
case 8:
|
||||
stream.BitRate = 128000;
|
||||
break;
|
||||
case 7:
|
||||
stream.BitRate = 112000;
|
||||
break;
|
||||
case 6:
|
||||
stream.BitRate = 96000;
|
||||
break;
|
||||
case 5:
|
||||
stream.BitRate = 80000;
|
||||
break;
|
||||
case 4:
|
||||
stream.BitRate = 64000;
|
||||
break;
|
||||
case 3:
|
||||
stream.BitRate = 56000;
|
||||
break;
|
||||
case 2:
|
||||
stream.BitRate = 48000;
|
||||
break;
|
||||
case 1:
|
||||
stream.BitRate = 40000;
|
||||
break;
|
||||
case 0:
|
||||
stream.BitRate = 32000;
|
||||
break;
|
||||
default:
|
||||
stream.BitRate = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.BitRate = (long)
|
||||
(4.0 * frame_size * stream.SampleRate / (num_blocks * 256));
|
||||
}
|
||||
|
||||
stream.LFE = lfe_on;
|
||||
if (stream.StreamType != TSStreamType.AC3_PLUS_AUDIO &&
|
||||
stream.StreamType != TSStreamType.AC3_PLUS_SECONDARY_AUDIO)
|
||||
{
|
||||
stream.DialNorm = dial_norm - 31;
|
||||
}
|
||||
stream.IsVBR = false;
|
||||
stream.IsInitialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
//============================================================================
|
||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||
// Copyright © 2010 Cinema Squid
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//=============================================================================
|
||||
|
||||
|
||||
namespace BDInfo
|
||||
{
|
||||
public abstract class TSCodecAVC
|
||||
{
|
||||
public static void Scan(
|
||||
TSVideoStream stream,
|
||||
TSStreamBuffer buffer,
|
||||
ref string tag)
|
||||
{
|
||||
uint parse = 0;
|
||||
byte accessUnitDelimiterParse = 0;
|
||||
byte sequenceParameterSetParse = 0;
|
||||
string profile = null;
|
||||
string level = null;
|
||||
byte constraintSet0Flag = 0;
|
||||
byte constraintSet1Flag = 0;
|
||||
byte constraintSet2Flag = 0;
|
||||
byte constraintSet3Flag = 0;
|
||||
|
||||
for (int i = 0; i < buffer.Length; i++)
|
||||
{
|
||||
parse = (parse << 8) + buffer.ReadByte();
|
||||
|
||||
if (parse == 0x00000109)
|
||||
{
|
||||
accessUnitDelimiterParse = 1;
|
||||
}
|
||||
else if (accessUnitDelimiterParse > 0)
|
||||
{
|
||||
--accessUnitDelimiterParse;
|
||||
if (accessUnitDelimiterParse == 0)
|
||||
{
|
||||
switch ((parse & 0xFF) >> 5)
|
||||
{
|
||||
case 0: // I
|
||||
case 3: // SI
|
||||
case 5: // I, SI
|
||||
tag = "I";
|
||||
break;
|
||||
|
||||
case 1: // I, P
|
||||
case 4: // SI, SP
|
||||
case 6: // I, SI, P, SP
|
||||
tag = "P";
|
||||
break;
|
||||
|
||||
case 2: // I, P, B
|
||||
case 7: // I, SI, P, SP, B
|
||||
tag = "B";
|
||||
break;
|
||||
}
|
||||
if (stream.IsInitialized) return;
|
||||
}
|
||||
}
|
||||
else if (parse == 0x00000127 || parse == 0x00000167)
|
||||
{
|
||||
sequenceParameterSetParse = 3;
|
||||
}
|
||||
else if (sequenceParameterSetParse > 0)
|
||||
{
|
||||
--sequenceParameterSetParse;
|
||||
switch (sequenceParameterSetParse)
|
||||
{
|
||||
case 2:
|
||||
switch (parse & 0xFF)
|
||||
{
|
||||
case 66:
|
||||
profile = "Baseline Profile";
|
||||
break;
|
||||
case 77:
|
||||
profile = "Main Profile";
|
||||
break;
|
||||
case 88:
|
||||
profile = "Extended Profile";
|
||||
break;
|
||||
case 100:
|
||||
profile = "High Profile";
|
||||
break;
|
||||
case 110:
|
||||
profile = "High 10 Profile";
|
||||
break;
|
||||
case 122:
|
||||
profile = "High 4:2:2 Profile";
|
||||
break;
|
||||
case 144:
|
||||
profile = "High 4:4:4 Profile";
|
||||
break;
|
||||
default:
|
||||
profile = "Unknown Profile";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
constraintSet0Flag = (byte)
|
||||
((parse & 0x80) >> 7);
|
||||
constraintSet1Flag = (byte)
|
||||
((parse & 0x40) >> 6);
|
||||
constraintSet2Flag = (byte)
|
||||
((parse & 0x20) >> 5);
|
||||
constraintSet3Flag = (byte)
|
||||
((parse & 0x10) >> 4);
|
||||
break;
|
||||
|
||||
case 0:
|
||||
byte b = (byte)(parse & 0xFF);
|
||||
if (b == 11 && constraintSet3Flag == 1)
|
||||
{
|
||||
level = "1b";
|
||||
}
|
||||
else
|
||||
{
|
||||
level = string.Format(
|
||||
"{0:D}.{1:D}",
|
||||
b / 10, (b - ((b / 10) * 10)));
|
||||
}
|
||||
stream.EncodingProfile = string.Format(
|
||||
"{0} {1}", profile, level);
|
||||
stream.IsVBR = true;
|
||||
stream.IsInitialized = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
//============================================================================
|
||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||
// Copyright © 2010 Cinema Squid
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//=============================================================================
|
||||
|
||||
|
||||
namespace BDInfo
|
||||
{
|
||||
public abstract class TSCodecDTS
|
||||
{
|
||||
private static int[] dca_sample_rates =
|
||||
{
|
||||
0, 8000, 16000, 32000, 0, 0, 11025, 22050, 44100, 0, 0,
|
||||
12000, 24000, 48000, 96000, 192000
|
||||
};
|
||||
|
||||
private static int[] dca_bit_rates =
|
||||
{
|
||||
32000, 56000, 64000, 96000, 112000, 128000,
|
||||
192000, 224000, 256000, 320000, 384000,
|
||||
448000, 512000, 576000, 640000, 768000,
|
||||
896000, 1024000, 1152000, 1280000, 1344000,
|
||||
1408000, 1411200, 1472000, 1509000, 1920000,
|
||||
2048000, 3072000, 3840000, 1/*open*/, 2/*variable*/, 3/*lossless*/
|
||||
};
|
||||
|
||||
private static int[] dca_channels =
|
||||
{
|
||||
1, 2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 6, 6, 7, 8, 8
|
||||
};
|
||||
|
||||
private static int[] dca_bits_per_sample =
|
||||
{
|
||||
16, 16, 20, 20, 0, 24, 24
|
||||
};
|
||||
|
||||
public static void Scan(
|
||||
TSAudioStream stream,
|
||||
TSStreamBuffer buffer,
|
||||
long bitrate,
|
||||
ref string tag)
|
||||
{
|
||||
if (stream.IsInitialized) return;
|
||||
|
||||
bool syncFound = false;
|
||||
uint sync = 0;
|
||||
for (int i = 0; i < buffer.Length; i++)
|
||||
{
|
||||
sync = (sync << 8) + buffer.ReadByte();
|
||||
if (sync == 0x7FFE8001)
|
||||
{
|
||||
syncFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!syncFound) return;
|
||||
|
||||
int frame_type = buffer.ReadBits(1);
|
||||
int samples_deficit = buffer.ReadBits(5);
|
||||
int crc_present = buffer.ReadBits(1);
|
||||
int sample_blocks = buffer.ReadBits(7);
|
||||
int frame_size = buffer.ReadBits(14);
|
||||
if (frame_size < 95)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int amode = buffer.ReadBits(6);
|
||||
int sample_rate = buffer.ReadBits(4);
|
||||
if (sample_rate < 0 || sample_rate >= dca_sample_rates.Length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int bit_rate = buffer.ReadBits(5);
|
||||
if (bit_rate < 0 || bit_rate >= dca_bit_rates.Length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int downmix = buffer.ReadBits(1);
|
||||
int dynrange = buffer.ReadBits(1);
|
||||
int timestamp = buffer.ReadBits(1);
|
||||
int aux_data = buffer.ReadBits(1);
|
||||
int hdcd = buffer.ReadBits(1);
|
||||
int ext_descr = buffer.ReadBits(3);
|
||||
int ext_coding = buffer.ReadBits(1);
|
||||
int aspf = buffer.ReadBits(1);
|
||||
int lfe = buffer.ReadBits(2);
|
||||
int predictor_history = buffer.ReadBits(1);
|
||||
if (crc_present == 1)
|
||||
{
|
||||
int crc = buffer.ReadBits(16);
|
||||
}
|
||||
int multirate_inter = buffer.ReadBits(1);
|
||||
int version = buffer.ReadBits(4);
|
||||
int copy_history = buffer.ReadBits(2);
|
||||
int source_pcm_res = buffer.ReadBits(3);
|
||||
int front_sum = buffer.ReadBits(1);
|
||||
int surround_sum = buffer.ReadBits(1);
|
||||
int dialog_norm = buffer.ReadBits(4);
|
||||
if (source_pcm_res < 0 || source_pcm_res >= dca_bits_per_sample.Length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int subframes = buffer.ReadBits(4);
|
||||
int total_channels = buffer.ReadBits(3) + 1 + ext_coding;
|
||||
|
||||
stream.SampleRate = dca_sample_rates[sample_rate];
|
||||
stream.ChannelCount = total_channels;
|
||||
stream.LFE = (lfe > 0 ? 1 : 0);
|
||||
stream.BitDepth = dca_bits_per_sample[source_pcm_res];
|
||||
stream.DialNorm = -dialog_norm;
|
||||
if ((source_pcm_res & 0x1) == 0x1)
|
||||
{
|
||||
stream.AudioMode = TSAudioMode.Extended;
|
||||
}
|
||||
|
||||
stream.BitRate = (uint)dca_bit_rates[bit_rate];
|
||||
switch (stream.BitRate)
|
||||
{
|
||||
case 1:
|
||||
if (bitrate > 0)
|
||||
{
|
||||
stream.BitRate = bitrate;
|
||||
stream.IsVBR = false;
|
||||
stream.IsInitialized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.BitRate = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
stream.IsVBR = true;
|
||||
stream.IsInitialized = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
stream.IsVBR = false;
|
||||
stream.IsInitialized = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,246 +0,0 @@
|
||||
//============================================================================
|
||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||
// Copyright © 2010 Cinema Squid
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//=============================================================================
|
||||
|
||||
|
||||
namespace BDInfo
|
||||
{
|
||||
public abstract class TSCodecDTSHD
|
||||
{
|
||||
private static int[] SampleRates = new int[]
|
||||
{ 0x1F40, 0x3E80, 0x7D00, 0x0FA00, 0x1F400, 0x5622, 0x0AC44, 0x15888, 0x2B110, 0x56220, 0x2EE0, 0x5DC0, 0x0BB80, 0x17700, 0x2EE00, 0x5DC00 };
|
||||
|
||||
public static void Scan(
|
||||
TSAudioStream stream,
|
||||
TSStreamBuffer buffer,
|
||||
long bitrate,
|
||||
ref string tag)
|
||||
{
|
||||
if (stream.IsInitialized &&
|
||||
(stream.StreamType == TSStreamType.DTS_HD_SECONDARY_AUDIO ||
|
||||
(stream.CoreStream != null &&
|
||||
stream.CoreStream.IsInitialized))) return;
|
||||
|
||||
bool syncFound = false;
|
||||
uint sync = 0;
|
||||
for (int i = 0; i < buffer.Length; i++)
|
||||
{
|
||||
sync = (sync << 8) + buffer.ReadByte();
|
||||
if (sync == 0x64582025)
|
||||
{
|
||||
syncFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!syncFound)
|
||||
{
|
||||
tag = "CORE";
|
||||
if (stream.CoreStream == null)
|
||||
{
|
||||
stream.CoreStream = new TSAudioStream();
|
||||
stream.CoreStream.StreamType = TSStreamType.DTS_AUDIO;
|
||||
}
|
||||
if (!stream.CoreStream.IsInitialized)
|
||||
{
|
||||
buffer.BeginRead();
|
||||
TSCodecDTS.Scan(stream.CoreStream, buffer, bitrate, ref tag);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
tag = "HD";
|
||||
int temp1 = buffer.ReadBits(8);
|
||||
int nuSubStreamIndex = buffer.ReadBits(2);
|
||||
int nuExtSSHeaderSize = 0;
|
||||
int nuExtSSFSize = 0;
|
||||
int bBlownUpHeader = buffer.ReadBits(1);
|
||||
if (1 == bBlownUpHeader)
|
||||
{
|
||||
nuExtSSHeaderSize = buffer.ReadBits(12) + 1;
|
||||
nuExtSSFSize = buffer.ReadBits(20) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
nuExtSSHeaderSize = buffer.ReadBits(8) + 1;
|
||||
nuExtSSFSize = buffer.ReadBits(16) + 1;
|
||||
}
|
||||
int nuNumAudioPresent = 1;
|
||||
int nuNumAssets = 1;
|
||||
int bStaticFieldsPresent = buffer.ReadBits(1);
|
||||
if (1 == bStaticFieldsPresent)
|
||||
{
|
||||
int nuRefClockCode = buffer.ReadBits(2);
|
||||
int nuExSSFrameDurationCode = buffer.ReadBits(3) + 1;
|
||||
long nuTimeStamp = 0;
|
||||
if (1 == buffer.ReadBits(1))
|
||||
{
|
||||
nuTimeStamp = (buffer.ReadBits(18) << 18) + buffer.ReadBits(18);
|
||||
}
|
||||
nuNumAudioPresent = buffer.ReadBits(3) + 1;
|
||||
nuNumAssets = buffer.ReadBits(3) + 1;
|
||||
int[] nuActiveExSSMask = new int[nuNumAudioPresent];
|
||||
for (int i = 0; i < nuNumAudioPresent; i++)
|
||||
{
|
||||
nuActiveExSSMask[i] = buffer.ReadBits(nuSubStreamIndex + 1); //?
|
||||
}
|
||||
for (int i = 0; i < nuNumAudioPresent; i++)
|
||||
{
|
||||
for (int j = 0; j < nuSubStreamIndex + 1; j++)
|
||||
{
|
||||
if (((j + 1) % 2) == 1)
|
||||
{
|
||||
int mask = buffer.ReadBits(8);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (1 == buffer.ReadBits(1))
|
||||
{
|
||||
int nuMixMetadataAdjLevel = buffer.ReadBits(2);
|
||||
int nuBits4MixOutMask = buffer.ReadBits(2) * 4 + 4;
|
||||
int nuNumMixOutConfigs = buffer.ReadBits(2) + 1;
|
||||
int[] nuMixOutChMask = new int[nuNumMixOutConfigs];
|
||||
for (int i = 0; i < nuNumMixOutConfigs; i++)
|
||||
{
|
||||
nuMixOutChMask[i] = buffer.ReadBits(nuBits4MixOutMask);
|
||||
}
|
||||
}
|
||||
}
|
||||
int[] AssetSizes = new int[nuNumAssets];
|
||||
for (int i = 0; i < nuNumAssets; i++)
|
||||
{
|
||||
if (1 == bBlownUpHeader)
|
||||
{
|
||||
AssetSizes[i] = buffer.ReadBits(20) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
AssetSizes[i] = buffer.ReadBits(16) + 1;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < nuNumAssets; i++)
|
||||
{
|
||||
long bufferPosition = buffer.Position;
|
||||
int nuAssetDescriptorFSIZE = buffer.ReadBits(9) + 1;
|
||||
int DescriptorDataForAssetIndex = buffer.ReadBits(3);
|
||||
if (1 == bStaticFieldsPresent)
|
||||
{
|
||||
int AssetTypeDescrPresent = buffer.ReadBits(1);
|
||||
if (1 == AssetTypeDescrPresent)
|
||||
{
|
||||
int AssetTypeDescriptor = buffer.ReadBits(4);
|
||||
}
|
||||
int LanguageDescrPresent = buffer.ReadBits(1);
|
||||
if (1 == LanguageDescrPresent)
|
||||
{
|
||||
int LanguageDescriptor = buffer.ReadBits(24);
|
||||
}
|
||||
int bInfoTextPresent = buffer.ReadBits(1);
|
||||
if (1 == bInfoTextPresent)
|
||||
{
|
||||
int nuInfoTextByteSize = buffer.ReadBits(10) + 1;
|
||||
int[] InfoText = new int[nuInfoTextByteSize];
|
||||
for (int j = 0; j < nuInfoTextByteSize; j++)
|
||||
{
|
||||
InfoText[j] = buffer.ReadBits(8);
|
||||
}
|
||||
}
|
||||
int nuBitResolution = buffer.ReadBits(5) + 1;
|
||||
int nuMaxSampleRate = buffer.ReadBits(4);
|
||||
int nuTotalNumChs = buffer.ReadBits(8) + 1;
|
||||
int bOne2OneMapChannels2Speakers = buffer.ReadBits(1);
|
||||
int nuSpkrActivityMask = 0;
|
||||
if (1 == bOne2OneMapChannels2Speakers)
|
||||
{
|
||||
int bEmbeddedStereoFlag = 0;
|
||||
if (nuTotalNumChs > 2)
|
||||
{
|
||||
bEmbeddedStereoFlag = buffer.ReadBits(1);
|
||||
}
|
||||
int bEmbeddedSixChFlag = 0;
|
||||
if (nuTotalNumChs > 6)
|
||||
{
|
||||
bEmbeddedSixChFlag = buffer.ReadBits(1);
|
||||
}
|
||||
int bSpkrMaskEnabled = buffer.ReadBits(1);
|
||||
int nuNumBits4SAMask = 0;
|
||||
if (1 == bSpkrMaskEnabled)
|
||||
{
|
||||
nuNumBits4SAMask = buffer.ReadBits(2);
|
||||
nuNumBits4SAMask = nuNumBits4SAMask * 4 + 4;
|
||||
nuSpkrActivityMask = buffer.ReadBits(nuNumBits4SAMask);
|
||||
}
|
||||
// TODO...
|
||||
}
|
||||
stream.SampleRate = SampleRates[nuMaxSampleRate];
|
||||
stream.BitDepth = nuBitResolution;
|
||||
|
||||
stream.LFE = 0;
|
||||
if ((nuSpkrActivityMask & 0x8) == 0x8)
|
||||
{
|
||||
++stream.LFE;
|
||||
}
|
||||
if ((nuSpkrActivityMask & 0x1000) == 0x1000)
|
||||
{
|
||||
++stream.LFE;
|
||||
}
|
||||
stream.ChannelCount = nuTotalNumChs - stream.LFE;
|
||||
}
|
||||
if (nuNumAssets > 1)
|
||||
{
|
||||
// TODO...
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
if (stream.CoreStream != null)
|
||||
{
|
||||
var coreStream = (TSAudioStream)stream.CoreStream;
|
||||
if (coreStream.AudioMode == TSAudioMode.Extended &&
|
||||
stream.ChannelCount == 5)
|
||||
{
|
||||
stream.AudioMode = TSAudioMode.Extended;
|
||||
}
|
||||
/*
|
||||
if (coreStream.DialNorm != 0)
|
||||
{
|
||||
stream.DialNorm = coreStream.DialNorm;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
if (stream.StreamType == TSStreamType.DTS_HD_MASTER_AUDIO)
|
||||
{
|
||||
stream.IsVBR = true;
|
||||
stream.IsInitialized = true;
|
||||
}
|
||||
else if (bitrate > 0)
|
||||
{
|
||||
stream.IsVBR = false;
|
||||
stream.BitRate = bitrate;
|
||||
if (stream.CoreStream != null)
|
||||
{
|
||||
stream.BitRate += stream.CoreStream.BitRate;
|
||||
stream.IsInitialized = true;
|
||||
}
|
||||
stream.IsInitialized = (stream.BitRate > 0 ? true : false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
//============================================================================
|
||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||
// Copyright © 2010 Cinema Squid
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//=============================================================================
|
||||
|
||||
|
||||
namespace BDInfo
|
||||
{
|
||||
public abstract class TSCodecLPCM
|
||||
{
|
||||
public static void Scan(
|
||||
TSAudioStream stream,
|
||||
TSStreamBuffer buffer,
|
||||
ref string tag)
|
||||
{
|
||||
if (stream.IsInitialized) return;
|
||||
|
||||
byte[] header = buffer.ReadBytes(4);
|
||||
int flags = (header[2] << 8) + header[3];
|
||||
|
||||
switch ((flags & 0xF000) >> 12)
|
||||
{
|
||||
case 1: // 1/0/0
|
||||
stream.ChannelCount = 1;
|
||||
stream.LFE = 0;
|
||||
break;
|
||||
case 3: // 2/0/0
|
||||
stream.ChannelCount = 2;
|
||||
stream.LFE = 0;
|
||||
break;
|
||||
case 4: // 3/0/0
|
||||
stream.ChannelCount = 3;
|
||||
stream.LFE = 0;
|
||||
break;
|
||||
case 5: // 2/1/0
|
||||
stream.ChannelCount = 3;
|
||||
stream.LFE = 0;
|
||||
break;
|
||||
case 6: // 3/1/0
|
||||
stream.ChannelCount = 4;
|
||||
stream.LFE = 0;
|
||||
break;
|
||||
case 7: // 2/2/0
|
||||
stream.ChannelCount = 4;
|
||||
stream.LFE = 0;
|
||||
break;
|
||||
case 8: // 3/2/0
|
||||
stream.ChannelCount = 5;
|
||||
stream.LFE = 0;
|
||||
break;
|
||||
case 9: // 3/2/1
|
||||
stream.ChannelCount = 5;
|
||||
stream.LFE = 1;
|
||||
break;
|
||||
case 10: // 3/4/0
|
||||
stream.ChannelCount = 7;
|
||||
stream.LFE = 0;
|
||||
break;
|
||||
case 11: // 3/4/1
|
||||
stream.ChannelCount = 7;
|
||||
stream.LFE = 1;
|
||||
break;
|
||||
default:
|
||||
stream.ChannelCount = 0;
|
||||
stream.LFE = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
switch ((flags & 0xC0) >> 6)
|
||||
{
|
||||
case 1:
|
||||
stream.BitDepth = 16;
|
||||
break;
|
||||
case 2:
|
||||
stream.BitDepth = 20;
|
||||
break;
|
||||
case 3:
|
||||
stream.BitDepth = 24;
|
||||
break;
|
||||
default:
|
||||
stream.BitDepth = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
switch ((flags & 0xF00) >> 8)
|
||||
{
|
||||
case 1:
|
||||
stream.SampleRate = 48000;
|
||||
break;
|
||||
case 4:
|
||||
stream.SampleRate = 96000;
|
||||
break;
|
||||
case 5:
|
||||
stream.SampleRate = 192000;
|
||||
break;
|
||||
default:
|
||||
stream.SampleRate = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
stream.BitRate = (uint)
|
||||
(stream.SampleRate * stream.BitDepth *
|
||||
(stream.ChannelCount + stream.LFE));
|
||||
|
||||
stream.IsVBR = false;
|
||||
stream.IsInitialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,208 +0,0 @@
|
||||
//============================================================================
|
||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||
// Copyright © 2010 Cinema Squid
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//=============================================================================
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
|
||||
namespace BDInfo
|
||||
{
|
||||
public abstract class TSCodecMPEG2
|
||||
{
|
||||
public static void Scan(
|
||||
TSVideoStream stream,
|
||||
TSStreamBuffer buffer,
|
||||
ref string tag)
|
||||
{
|
||||
int parse = 0;
|
||||
int pictureParse = 0;
|
||||
int sequenceHeaderParse = 0;
|
||||
int extensionParse = 0;
|
||||
int sequenceExtensionParse = 0;
|
||||
|
||||
for (int i = 0; i < buffer.Length; i++)
|
||||
{
|
||||
parse = (parse << 8) + buffer.ReadByte();
|
||||
|
||||
if (parse == 0x00000100)
|
||||
{
|
||||
pictureParse = 2;
|
||||
}
|
||||
else if (parse == 0x000001B3)
|
||||
{
|
||||
sequenceHeaderParse = 7;
|
||||
}
|
||||
else if (sequenceHeaderParse > 0)
|
||||
{
|
||||
--sequenceHeaderParse;
|
||||
switch (sequenceHeaderParse)
|
||||
{
|
||||
#if DEBUG
|
||||
case 6:
|
||||
break;
|
||||
|
||||
case 5:
|
||||
break;
|
||||
|
||||
case 4:
|
||||
stream.Width =
|
||||
(int)((parse & 0xFFF000) >> 12);
|
||||
stream.Height =
|
||||
(int)(parse & 0xFFF);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
stream.AspectRatio =
|
||||
(TSAspectRatio)((parse & 0xF0) >> 4);
|
||||
|
||||
switch ((parse & 0xF0) >> 4)
|
||||
{
|
||||
case 0: // Forbidden
|
||||
break;
|
||||
case 1: // Square
|
||||
break;
|
||||
case 2: // 4:3
|
||||
break;
|
||||
case 3: // 16:9
|
||||
break;
|
||||
case 4: // 2.21:1
|
||||
break;
|
||||
default: // Reserved
|
||||
break;
|
||||
}
|
||||
|
||||
switch (parse & 0xF)
|
||||
{
|
||||
case 0: // Forbidden
|
||||
break;
|
||||
case 1: // 23.976
|
||||
stream.FrameRateEnumerator = 24000;
|
||||
stream.FrameRateDenominator = 1001;
|
||||
break;
|
||||
case 2: // 24
|
||||
stream.FrameRateEnumerator = 24000;
|
||||
stream.FrameRateDenominator = 1000;
|
||||
break;
|
||||
case 3: // 25
|
||||
stream.FrameRateEnumerator = 25000;
|
||||
stream.FrameRateDenominator = 1000;
|
||||
break;
|
||||
case 4: // 29.97
|
||||
stream.FrameRateEnumerator = 30000;
|
||||
stream.FrameRateDenominator = 1001;
|
||||
break;
|
||||
case 5: // 30
|
||||
stream.FrameRateEnumerator = 30000;
|
||||
stream.FrameRateDenominator = 1000;
|
||||
break;
|
||||
case 6: // 50
|
||||
stream.FrameRateEnumerator = 50000;
|
||||
stream.FrameRateDenominator = 1000;
|
||||
break;
|
||||
case 7: // 59.94
|
||||
stream.FrameRateEnumerator = 60000;
|
||||
stream.FrameRateDenominator = 1001;
|
||||
break;
|
||||
case 8: // 60
|
||||
stream.FrameRateEnumerator = 60000;
|
||||
stream.FrameRateDenominator = 1000;
|
||||
break;
|
||||
default: // Reserved
|
||||
stream.FrameRateEnumerator = 0;
|
||||
stream.FrameRateDenominator = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
break;
|
||||
|
||||
case 1:
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 0:
|
||||
#if DEBUG
|
||||
stream.BitRate =
|
||||
(((parse & 0xFFFFC0) >> 6) * 200);
|
||||
#endif
|
||||
stream.IsVBR = true;
|
||||
stream.IsInitialized = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (pictureParse > 0)
|
||||
{
|
||||
--pictureParse;
|
||||
if (pictureParse == 0)
|
||||
{
|
||||
switch ((parse & 0x38) >> 3)
|
||||
{
|
||||
case 1:
|
||||
tag = "I";
|
||||
break;
|
||||
case 2:
|
||||
tag = "P";
|
||||
break;
|
||||
case 3:
|
||||
tag = "B";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (stream.IsInitialized) return;
|
||||
}
|
||||
}
|
||||
else if (parse == 0x000001B5)
|
||||
{
|
||||
extensionParse = 1;
|
||||
}
|
||||
else if (extensionParse > 0)
|
||||
{
|
||||
--extensionParse;
|
||||
if (extensionParse == 0)
|
||||
{
|
||||
if ((parse & 0xF0) == 0x10)
|
||||
{
|
||||
sequenceExtensionParse = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (sequenceExtensionParse > 0)
|
||||
{
|
||||
--sequenceExtensionParse;
|
||||
#if DEBUG
|
||||
if (sequenceExtensionParse == 0)
|
||||
{
|
||||
uint sequenceExtension =
|
||||
((parse & 0x8) >> 3);
|
||||
if (sequenceExtension == 0)
|
||||
{
|
||||
stream.IsInterlaced = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.IsInterlaced = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
//============================================================================
|
||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||
// Copyright © 2010 Cinema Squid
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//=============================================================================
|
||||
|
||||
|
||||
namespace BDInfo
|
||||
{
|
||||
// TODO: Do something more interesting here...
|
||||
|
||||
public abstract class TSCodecMVC
|
||||
{
|
||||
public static void Scan(
|
||||
TSVideoStream stream,
|
||||
TSStreamBuffer buffer,
|
||||
ref string tag)
|
||||
{
|
||||
stream.IsVBR = true;
|
||||
stream.IsInitialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
//============================================================================
|
||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||
// Copyright © 2010 Cinema Squid
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//=============================================================================
|
||||
|
||||
|
||||
namespace BDInfo
|
||||
{
|
||||
public abstract class TSCodecTrueHD
|
||||
{
|
||||
public static void Scan(
|
||||
TSAudioStream stream,
|
||||
TSStreamBuffer buffer,
|
||||
ref string tag)
|
||||
{
|
||||
if (stream.IsInitialized &&
|
||||
stream.CoreStream != null &&
|
||||
stream.CoreStream.IsInitialized) return;
|
||||
|
||||
bool syncFound = false;
|
||||
uint sync = 0;
|
||||
for (int i = 0; i < buffer.Length; i++)
|
||||
{
|
||||
sync = (sync << 8) + buffer.ReadByte();
|
||||
if (sync == 0xF8726FBA)
|
||||
{
|
||||
syncFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!syncFound)
|
||||
{
|
||||
tag = "CORE";
|
||||
if (stream.CoreStream == null)
|
||||
{
|
||||
stream.CoreStream = new TSAudioStream();
|
||||
stream.CoreStream.StreamType = TSStreamType.AC3_AUDIO;
|
||||
}
|
||||
if (!stream.CoreStream.IsInitialized)
|
||||
{
|
||||
buffer.BeginRead();
|
||||
TSCodecAC3.Scan(stream.CoreStream, buffer, ref tag);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
tag = "HD";
|
||||
int ratebits = buffer.ReadBits(4);
|
||||
if (ratebits != 0xF)
|
||||
{
|
||||
stream.SampleRate =
|
||||
(((ratebits & 8) > 0 ? 44100 : 48000) << (ratebits & 7));
|
||||
}
|
||||
int temp1 = buffer.ReadBits(8);
|
||||
int channels_thd_stream1 = buffer.ReadBits(5);
|
||||
int temp2 = buffer.ReadBits(2);
|
||||
|
||||
stream.ChannelCount = 0;
|
||||
stream.LFE = 0;
|
||||
int c_LFE2 = buffer.ReadBits(1);
|
||||
if (c_LFE2 == 1)
|
||||
{
|
||||
stream.LFE += 1;
|
||||
}
|
||||
int c_Cvh = buffer.ReadBits(1);
|
||||
if (c_Cvh == 1)
|
||||
{
|
||||
stream.ChannelCount += 1;
|
||||
}
|
||||
int c_LRw = buffer.ReadBits(1);
|
||||
if (c_LRw == 1)
|
||||
{
|
||||
stream.ChannelCount += 2;
|
||||
}
|
||||
int c_LRsd = buffer.ReadBits(1);
|
||||
if (c_LRsd == 1)
|
||||
{
|
||||
stream.ChannelCount += 2;
|
||||
}
|
||||
int c_Ts = buffer.ReadBits(1);
|
||||
if (c_Ts == 1)
|
||||
{
|
||||
stream.ChannelCount += 1;
|
||||
}
|
||||
int c_Cs = buffer.ReadBits(1);
|
||||
if (c_Cs == 1)
|
||||
{
|
||||
stream.ChannelCount += 1;
|
||||
}
|
||||
int c_LRrs = buffer.ReadBits(1);
|
||||
if (c_LRrs == 1)
|
||||
{
|
||||
stream.ChannelCount += 2;
|
||||
}
|
||||
int c_LRc = buffer.ReadBits(1);
|
||||
if (c_LRc == 1)
|
||||
{
|
||||
stream.ChannelCount += 2;
|
||||
}
|
||||
int c_LRvh = buffer.ReadBits(1);
|
||||
if (c_LRvh == 1)
|
||||
{
|
||||
stream.ChannelCount += 2;
|
||||
}
|
||||
int c_LRs = buffer.ReadBits(1);
|
||||
if (c_LRs == 1)
|
||||
{
|
||||
stream.ChannelCount += 2;
|
||||
}
|
||||
int c_LFE = buffer.ReadBits(1);
|
||||
if (c_LFE == 1)
|
||||
{
|
||||
stream.LFE += 1;
|
||||
}
|
||||
int c_C = buffer.ReadBits(1);
|
||||
if (c_C == 1)
|
||||
{
|
||||
stream.ChannelCount += 1;
|
||||
}
|
||||
int c_LR = buffer.ReadBits(1);
|
||||
if (c_LR == 1)
|
||||
{
|
||||
stream.ChannelCount += 2;
|
||||
}
|
||||
|
||||
int access_unit_size = 40 << (ratebits & 7);
|
||||
int access_unit_size_pow2 = 64 << (ratebits & 7);
|
||||
|
||||
int a1 = buffer.ReadBits(16);
|
||||
int a2 = buffer.ReadBits(16);
|
||||
int a3 = buffer.ReadBits(16);
|
||||
|
||||
int is_vbr = buffer.ReadBits(1);
|
||||
int peak_bitrate = buffer.ReadBits(15);
|
||||
peak_bitrate = (peak_bitrate * stream.SampleRate) >> 4;
|
||||
|
||||
double peak_bitdepth =
|
||||
(double)peak_bitrate /
|
||||
(stream.ChannelCount + stream.LFE) /
|
||||
stream.SampleRate;
|
||||
if (peak_bitdepth > 14)
|
||||
{
|
||||
stream.BitDepth = 24;
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.BitDepth = 16;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
System.Diagnostics.Debug.WriteLine(string.Format(
|
||||
"{0}\t{1}\t{2:F2}",
|
||||
stream.PID, peak_bitrate, peak_bitdepth));
|
||||
#endif
|
||||
/*
|
||||
// TODO: Get THD dialnorm from metadata
|
||||
if (stream.CoreStream != null)
|
||||
{
|
||||
TSAudioStream coreStream = (TSAudioStream)stream.CoreStream;
|
||||
if (coreStream.DialNorm != 0)
|
||||
{
|
||||
stream.DialNorm = coreStream.DialNorm;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
stream.IsVBR = true;
|
||||
stream.IsInitialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
//============================================================================
|
||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||
// Copyright © 2010 Cinema Squid
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//=============================================================================
|
||||
|
||||
|
||||
namespace BDInfo
|
||||
{
|
||||
public abstract class TSCodecVC1
|
||||
{
|
||||
public static void Scan(
|
||||
TSVideoStream stream,
|
||||
TSStreamBuffer buffer,
|
||||
ref string tag)
|
||||
{
|
||||
int parse = 0;
|
||||
byte frameHeaderParse = 0;
|
||||
byte sequenceHeaderParse = 0;
|
||||
bool isInterlaced = false;
|
||||
|
||||
for (int i = 0; i < buffer.Length; i++)
|
||||
{
|
||||
parse = (parse << 8) + buffer.ReadByte();
|
||||
|
||||
if (parse == 0x0000010D)
|
||||
{
|
||||
frameHeaderParse = 4;
|
||||
}
|
||||
else if (frameHeaderParse > 0)
|
||||
{
|
||||
--frameHeaderParse;
|
||||
if (frameHeaderParse == 0)
|
||||
{
|
||||
uint pictureType = 0;
|
||||
if (isInterlaced)
|
||||
{
|
||||
if ((parse & 0x80000000) == 0)
|
||||
{
|
||||
pictureType =
|
||||
(uint)((parse & 0x78000000) >> 13);
|
||||
}
|
||||
else
|
||||
{
|
||||
pictureType =
|
||||
(uint)((parse & 0x3c000000) >> 12);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pictureType =
|
||||
(uint)((parse & 0xf0000000) >> 14);
|
||||
}
|
||||
|
||||
if ((pictureType & 0x20000) == 0)
|
||||
{
|
||||
tag = "P";
|
||||
}
|
||||
else if ((pictureType & 0x10000) == 0)
|
||||
{
|
||||
tag = "B";
|
||||
}
|
||||
else if ((pictureType & 0x8000) == 0)
|
||||
{
|
||||
tag = "I";
|
||||
}
|
||||
else if ((pictureType & 0x4000) == 0)
|
||||
{
|
||||
tag = "BI";
|
||||
}
|
||||
else
|
||||
{
|
||||
tag = null;
|
||||
}
|
||||
if (stream.IsInitialized) return;
|
||||
}
|
||||
}
|
||||
else if (parse == 0x0000010F)
|
||||
{
|
||||
sequenceHeaderParse = 6;
|
||||
}
|
||||
else if (sequenceHeaderParse > 0)
|
||||
{
|
||||
--sequenceHeaderParse;
|
||||
switch (sequenceHeaderParse)
|
||||
{
|
||||
case 5:
|
||||
int profileLevel = ((parse & 0x38) >> 3);
|
||||
if (((parse & 0xC0) >> 6) == 3)
|
||||
{
|
||||
stream.EncodingProfile = string.Format(
|
||||
"Advanced Profile {0}", profileLevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.EncodingProfile = string.Format(
|
||||
"Main Profile {0}", profileLevel);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0:
|
||||
if (((parse & 0x40) >> 6) > 0)
|
||||
{
|
||||
isInterlaced = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
isInterlaced = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
stream.IsVBR = true;
|
||||
stream.IsInitialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
//============================================================================
|
||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||
// Copyright © 2010 Cinema Squid
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//=============================================================================
|
||||
|
||||
using MediaBrowser.Model.IO;
|
||||
|
||||
// TODO: Do more interesting things here...
|
||||
|
||||
namespace BDInfo
|
||||
{
|
||||
public class TSInterleavedFile
|
||||
{
|
||||
public FileSystemMetadata FileInfo = null;
|
||||
public string Name = null;
|
||||
|
||||
public TSInterleavedFile(FileSystemMetadata fileInfo)
|
||||
{
|
||||
FileInfo = fileInfo;
|
||||
Name = fileInfo.Name.ToUpper();
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,780 +0,0 @@
|
||||
//============================================================================
|
||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||
// Copyright © 2010 Cinema Squid
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//=============================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BDInfo
|
||||
{
|
||||
public enum TSStreamType : byte
|
||||
{
|
||||
Unknown = 0,
|
||||
MPEG1_VIDEO = 0x01,
|
||||
MPEG2_VIDEO = 0x02,
|
||||
AVC_VIDEO = 0x1b,
|
||||
MVC_VIDEO = 0x20,
|
||||
VC1_VIDEO = 0xea,
|
||||
MPEG1_AUDIO = 0x03,
|
||||
MPEG2_AUDIO = 0x04,
|
||||
LPCM_AUDIO = 0x80,
|
||||
AC3_AUDIO = 0x81,
|
||||
AC3_PLUS_AUDIO = 0x84,
|
||||
AC3_PLUS_SECONDARY_AUDIO = 0xA1,
|
||||
AC3_TRUE_HD_AUDIO = 0x83,
|
||||
DTS_AUDIO = 0x82,
|
||||
DTS_HD_AUDIO = 0x85,
|
||||
DTS_HD_SECONDARY_AUDIO = 0xA2,
|
||||
DTS_HD_MASTER_AUDIO = 0x86,
|
||||
PRESENTATION_GRAPHICS = 0x90,
|
||||
INTERACTIVE_GRAPHICS = 0x91,
|
||||
SUBTITLE = 0x92
|
||||
}
|
||||
|
||||
public enum TSVideoFormat : byte
|
||||
{
|
||||
Unknown = 0,
|
||||
VIDEOFORMAT_480i = 1,
|
||||
VIDEOFORMAT_576i = 2,
|
||||
VIDEOFORMAT_480p = 3,
|
||||
VIDEOFORMAT_1080i = 4,
|
||||
VIDEOFORMAT_720p = 5,
|
||||
VIDEOFORMAT_1080p = 6,
|
||||
VIDEOFORMAT_576p = 7,
|
||||
}
|
||||
|
||||
public enum TSFrameRate : byte
|
||||
{
|
||||
Unknown = 0,
|
||||
FRAMERATE_23_976 = 1,
|
||||
FRAMERATE_24 = 2,
|
||||
FRAMERATE_25 = 3,
|
||||
FRAMERATE_29_97 = 4,
|
||||
FRAMERATE_50 = 6,
|
||||
FRAMERATE_59_94 = 7
|
||||
}
|
||||
|
||||
public enum TSChannelLayout : byte
|
||||
{
|
||||
Unknown = 0,
|
||||
CHANNELLAYOUT_MONO = 1,
|
||||
CHANNELLAYOUT_STEREO = 3,
|
||||
CHANNELLAYOUT_MULTI = 6,
|
||||
CHANNELLAYOUT_COMBO = 12
|
||||
}
|
||||
|
||||
public enum TSSampleRate : byte
|
||||
{
|
||||
Unknown = 0,
|
||||
SAMPLERATE_48 = 1,
|
||||
SAMPLERATE_96 = 4,
|
||||
SAMPLERATE_192 = 5,
|
||||
SAMPLERATE_48_192 = 12,
|
||||
SAMPLERATE_48_96 = 14
|
||||
}
|
||||
|
||||
public enum TSAspectRatio
|
||||
{
|
||||
Unknown = 0,
|
||||
ASPECT_4_3 = 2,
|
||||
ASPECT_16_9 = 3,
|
||||
ASPECT_2_21 = 4
|
||||
}
|
||||
|
||||
public class TSDescriptor
|
||||
{
|
||||
public byte Name;
|
||||
public byte[] Value;
|
||||
|
||||
public TSDescriptor(byte name, byte length)
|
||||
{
|
||||
Name = name;
|
||||
Value = new byte[length];
|
||||
}
|
||||
|
||||
public TSDescriptor Clone()
|
||||
{
|
||||
var descriptor =
|
||||
new TSDescriptor(Name, (byte)Value.Length);
|
||||
Value.CopyTo(descriptor.Value, 0);
|
||||
return descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class TSStream
|
||||
{
|
||||
public TSStream()
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0} ({1})", CodecShortName, PID);
|
||||
}
|
||||
|
||||
public ushort PID;
|
||||
public TSStreamType StreamType;
|
||||
public List<TSDescriptor> Descriptors = null;
|
||||
public long BitRate = 0;
|
||||
public long ActiveBitRate = 0;
|
||||
public bool IsVBR = false;
|
||||
public bool IsInitialized = false;
|
||||
public string LanguageName;
|
||||
public bool IsHidden = false;
|
||||
|
||||
public ulong PayloadBytes = 0;
|
||||
public ulong PacketCount = 0;
|
||||
public double PacketSeconds = 0;
|
||||
public int AngleIndex = 0;
|
||||
|
||||
public ulong PacketSize => PacketCount * 192;
|
||||
|
||||
private string _LanguageCode;
|
||||
public string LanguageCode
|
||||
{
|
||||
get => _LanguageCode;
|
||||
set
|
||||
{
|
||||
_LanguageCode = value;
|
||||
LanguageName = LanguageCodes.GetName(value);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsVideoStream
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (StreamType)
|
||||
{
|
||||
case TSStreamType.MPEG1_VIDEO:
|
||||
case TSStreamType.MPEG2_VIDEO:
|
||||
case TSStreamType.AVC_VIDEO:
|
||||
case TSStreamType.MVC_VIDEO:
|
||||
case TSStreamType.VC1_VIDEO:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsAudioStream
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (StreamType)
|
||||
{
|
||||
case TSStreamType.MPEG1_AUDIO:
|
||||
case TSStreamType.MPEG2_AUDIO:
|
||||
case TSStreamType.LPCM_AUDIO:
|
||||
case TSStreamType.AC3_AUDIO:
|
||||
case TSStreamType.AC3_PLUS_AUDIO:
|
||||
case TSStreamType.AC3_PLUS_SECONDARY_AUDIO:
|
||||
case TSStreamType.AC3_TRUE_HD_AUDIO:
|
||||
case TSStreamType.DTS_AUDIO:
|
||||
case TSStreamType.DTS_HD_AUDIO:
|
||||
case TSStreamType.DTS_HD_SECONDARY_AUDIO:
|
||||
case TSStreamType.DTS_HD_MASTER_AUDIO:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsGraphicsStream
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (StreamType)
|
||||
{
|
||||
case TSStreamType.PRESENTATION_GRAPHICS:
|
||||
case TSStreamType.INTERACTIVE_GRAPHICS:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsTextStream
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (StreamType)
|
||||
{
|
||||
case TSStreamType.SUBTITLE:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string CodecName
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (StreamType)
|
||||
{
|
||||
case TSStreamType.MPEG1_VIDEO:
|
||||
return "MPEG-1 Video";
|
||||
case TSStreamType.MPEG2_VIDEO:
|
||||
return "MPEG-2 Video";
|
||||
case TSStreamType.AVC_VIDEO:
|
||||
return "MPEG-4 AVC Video";
|
||||
case TSStreamType.MVC_VIDEO:
|
||||
return "MPEG-4 MVC Video";
|
||||
case TSStreamType.VC1_VIDEO:
|
||||
return "VC-1 Video";
|
||||
case TSStreamType.MPEG1_AUDIO:
|
||||
return "MP1 Audio";
|
||||
case TSStreamType.MPEG2_AUDIO:
|
||||
return "MP2 Audio";
|
||||
case TSStreamType.LPCM_AUDIO:
|
||||
return "LPCM Audio";
|
||||
case TSStreamType.AC3_AUDIO:
|
||||
if (((TSAudioStream)this).AudioMode == TSAudioMode.Extended)
|
||||
return "Dolby Digital EX Audio";
|
||||
else
|
||||
return "Dolby Digital Audio";
|
||||
case TSStreamType.AC3_PLUS_AUDIO:
|
||||
case TSStreamType.AC3_PLUS_SECONDARY_AUDIO:
|
||||
return "Dolby Digital Plus Audio";
|
||||
case TSStreamType.AC3_TRUE_HD_AUDIO:
|
||||
return "Dolby TrueHD Audio";
|
||||
case TSStreamType.DTS_AUDIO:
|
||||
if (((TSAudioStream)this).AudioMode == TSAudioMode.Extended)
|
||||
return "DTS-ES Audio";
|
||||
else
|
||||
return "DTS Audio";
|
||||
case TSStreamType.DTS_HD_AUDIO:
|
||||
return "DTS-HD High-Res Audio";
|
||||
case TSStreamType.DTS_HD_SECONDARY_AUDIO:
|
||||
return "DTS Express";
|
||||
case TSStreamType.DTS_HD_MASTER_AUDIO:
|
||||
return "DTS-HD Master Audio";
|
||||
case TSStreamType.PRESENTATION_GRAPHICS:
|
||||
return "Presentation Graphics";
|
||||
case TSStreamType.INTERACTIVE_GRAPHICS:
|
||||
return "Interactive Graphics";
|
||||
case TSStreamType.SUBTITLE:
|
||||
return "Subtitle";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string CodecAltName
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (StreamType)
|
||||
{
|
||||
case TSStreamType.MPEG1_VIDEO:
|
||||
return "MPEG-1";
|
||||
case TSStreamType.MPEG2_VIDEO:
|
||||
return "MPEG-2";
|
||||
case TSStreamType.AVC_VIDEO:
|
||||
return "AVC";
|
||||
case TSStreamType.MVC_VIDEO:
|
||||
return "MVC";
|
||||
case TSStreamType.VC1_VIDEO:
|
||||
return "VC-1";
|
||||
case TSStreamType.MPEG1_AUDIO:
|
||||
return "MP1";
|
||||
case TSStreamType.MPEG2_AUDIO:
|
||||
return "MP2";
|
||||
case TSStreamType.LPCM_AUDIO:
|
||||
return "LPCM";
|
||||
case TSStreamType.AC3_AUDIO:
|
||||
return "DD AC3";
|
||||
case TSStreamType.AC3_PLUS_AUDIO:
|
||||
case TSStreamType.AC3_PLUS_SECONDARY_AUDIO:
|
||||
return "DD AC3+";
|
||||
case TSStreamType.AC3_TRUE_HD_AUDIO:
|
||||
return "Dolby TrueHD";
|
||||
case TSStreamType.DTS_AUDIO:
|
||||
return "DTS";
|
||||
case TSStreamType.DTS_HD_AUDIO:
|
||||
return "DTS-HD Hi-Res";
|
||||
case TSStreamType.DTS_HD_SECONDARY_AUDIO:
|
||||
return "DTS Express";
|
||||
case TSStreamType.DTS_HD_MASTER_AUDIO:
|
||||
return "DTS-HD Master";
|
||||
case TSStreamType.PRESENTATION_GRAPHICS:
|
||||
return "PGS";
|
||||
case TSStreamType.INTERACTIVE_GRAPHICS:
|
||||
return "IGS";
|
||||
case TSStreamType.SUBTITLE:
|
||||
return "SUB";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string CodecShortName
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (StreamType)
|
||||
{
|
||||
case TSStreamType.MPEG1_VIDEO:
|
||||
return "MPEG-1";
|
||||
case TSStreamType.MPEG2_VIDEO:
|
||||
return "MPEG-2";
|
||||
case TSStreamType.AVC_VIDEO:
|
||||
return "AVC";
|
||||
case TSStreamType.MVC_VIDEO:
|
||||
return "MVC";
|
||||
case TSStreamType.VC1_VIDEO:
|
||||
return "VC-1";
|
||||
case TSStreamType.MPEG1_AUDIO:
|
||||
return "MP1";
|
||||
case TSStreamType.MPEG2_AUDIO:
|
||||
return "MP2";
|
||||
case TSStreamType.LPCM_AUDIO:
|
||||
return "LPCM";
|
||||
case TSStreamType.AC3_AUDIO:
|
||||
if (((TSAudioStream)this).AudioMode == TSAudioMode.Extended)
|
||||
return "AC3-EX";
|
||||
else
|
||||
return "AC3";
|
||||
case TSStreamType.AC3_PLUS_AUDIO:
|
||||
case TSStreamType.AC3_PLUS_SECONDARY_AUDIO:
|
||||
return "AC3+";
|
||||
case TSStreamType.AC3_TRUE_HD_AUDIO:
|
||||
return "TrueHD";
|
||||
case TSStreamType.DTS_AUDIO:
|
||||
if (((TSAudioStream)this).AudioMode == TSAudioMode.Extended)
|
||||
return "DTS-ES";
|
||||
else
|
||||
return "DTS";
|
||||
case TSStreamType.DTS_HD_AUDIO:
|
||||
return "DTS-HD HR";
|
||||
case TSStreamType.DTS_HD_SECONDARY_AUDIO:
|
||||
return "DTS Express";
|
||||
case TSStreamType.DTS_HD_MASTER_AUDIO:
|
||||
return "DTS-HD MA";
|
||||
case TSStreamType.PRESENTATION_GRAPHICS:
|
||||
return "PGS";
|
||||
case TSStreamType.INTERACTIVE_GRAPHICS:
|
||||
return "IGS";
|
||||
case TSStreamType.SUBTITLE:
|
||||
return "SUB";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual string Description => "";
|
||||
|
||||
public abstract TSStream Clone();
|
||||
|
||||
protected void CopyTo(TSStream stream)
|
||||
{
|
||||
stream.PID = PID;
|
||||
stream.StreamType = StreamType;
|
||||
stream.IsVBR = IsVBR;
|
||||
stream.BitRate = BitRate;
|
||||
stream.IsInitialized = IsInitialized;
|
||||
stream.LanguageCode = _LanguageCode;
|
||||
if (Descriptors != null)
|
||||
{
|
||||
stream.Descriptors = new List<TSDescriptor>();
|
||||
foreach (var descriptor in Descriptors)
|
||||
{
|
||||
stream.Descriptors.Add(descriptor.Clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TSVideoStream : TSStream
|
||||
{
|
||||
public TSVideoStream()
|
||||
{
|
||||
}
|
||||
|
||||
public int Width;
|
||||
public int Height;
|
||||
public bool IsInterlaced;
|
||||
public int FrameRateEnumerator;
|
||||
public int FrameRateDenominator;
|
||||
public TSAspectRatio AspectRatio;
|
||||
public string EncodingProfile;
|
||||
|
||||
private TSVideoFormat _VideoFormat;
|
||||
public TSVideoFormat VideoFormat
|
||||
{
|
||||
get => _VideoFormat;
|
||||
set
|
||||
{
|
||||
_VideoFormat = value;
|
||||
switch (value)
|
||||
{
|
||||
case TSVideoFormat.VIDEOFORMAT_480i:
|
||||
Height = 480;
|
||||
IsInterlaced = true;
|
||||
break;
|
||||
case TSVideoFormat.VIDEOFORMAT_480p:
|
||||
Height = 480;
|
||||
IsInterlaced = false;
|
||||
break;
|
||||
case TSVideoFormat.VIDEOFORMAT_576i:
|
||||
Height = 576;
|
||||
IsInterlaced = true;
|
||||
break;
|
||||
case TSVideoFormat.VIDEOFORMAT_576p:
|
||||
Height = 576;
|
||||
IsInterlaced = false;
|
||||
break;
|
||||
case TSVideoFormat.VIDEOFORMAT_720p:
|
||||
Height = 720;
|
||||
IsInterlaced = false;
|
||||
break;
|
||||
case TSVideoFormat.VIDEOFORMAT_1080i:
|
||||
Height = 1080;
|
||||
IsInterlaced = true;
|
||||
break;
|
||||
case TSVideoFormat.VIDEOFORMAT_1080p:
|
||||
Height = 1080;
|
||||
IsInterlaced = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TSFrameRate _FrameRate;
|
||||
public TSFrameRate FrameRate
|
||||
{
|
||||
get => _FrameRate;
|
||||
set
|
||||
{
|
||||
_FrameRate = value;
|
||||
switch (value)
|
||||
{
|
||||
case TSFrameRate.FRAMERATE_23_976:
|
||||
FrameRateEnumerator = 24000;
|
||||
FrameRateDenominator = 1001;
|
||||
break;
|
||||
case TSFrameRate.FRAMERATE_24:
|
||||
FrameRateEnumerator = 24000;
|
||||
FrameRateDenominator = 1000;
|
||||
break;
|
||||
case TSFrameRate.FRAMERATE_25:
|
||||
FrameRateEnumerator = 25000;
|
||||
FrameRateDenominator = 1000;
|
||||
break;
|
||||
case TSFrameRate.FRAMERATE_29_97:
|
||||
FrameRateEnumerator = 30000;
|
||||
FrameRateDenominator = 1001;
|
||||
break;
|
||||
case TSFrameRate.FRAMERATE_50:
|
||||
FrameRateEnumerator = 50000;
|
||||
FrameRateDenominator = 1000;
|
||||
break;
|
||||
case TSFrameRate.FRAMERATE_59_94:
|
||||
FrameRateEnumerator = 60000;
|
||||
FrameRateDenominator = 1001;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
string description = "";
|
||||
|
||||
if (Height > 0)
|
||||
{
|
||||
description += string.Format("{0:D}{1} / ",
|
||||
Height,
|
||||
IsInterlaced ? "i" : "p");
|
||||
}
|
||||
if (FrameRateEnumerator > 0 &&
|
||||
FrameRateDenominator > 0)
|
||||
{
|
||||
if (FrameRateEnumerator % FrameRateDenominator == 0)
|
||||
{
|
||||
description += string.Format("{0:D} fps / ",
|
||||
FrameRateEnumerator / FrameRateDenominator);
|
||||
}
|
||||
else
|
||||
{
|
||||
description += string.Format("{0:F3} fps / ",
|
||||
(double)FrameRateEnumerator / FrameRateDenominator);
|
||||
}
|
||||
|
||||
}
|
||||
if (AspectRatio == TSAspectRatio.ASPECT_4_3)
|
||||
{
|
||||
description += "4:3 / ";
|
||||
}
|
||||
else if (AspectRatio == TSAspectRatio.ASPECT_16_9)
|
||||
{
|
||||
description += "16:9 / ";
|
||||
}
|
||||
if (EncodingProfile != null)
|
||||
{
|
||||
description += EncodingProfile + " / ";
|
||||
}
|
||||
if (description.EndsWith(" / "))
|
||||
{
|
||||
description = description.Substring(0, description.Length - 3);
|
||||
}
|
||||
return description;
|
||||
}
|
||||
}
|
||||
|
||||
public override TSStream Clone()
|
||||
{
|
||||
var stream = new TSVideoStream();
|
||||
CopyTo(stream);
|
||||
|
||||
stream.VideoFormat = _VideoFormat;
|
||||
stream.FrameRate = _FrameRate;
|
||||
stream.Width = Width;
|
||||
stream.Height = Height;
|
||||
stream.IsInterlaced = IsInterlaced;
|
||||
stream.FrameRateEnumerator = FrameRateEnumerator;
|
||||
stream.FrameRateDenominator = FrameRateDenominator;
|
||||
stream.AspectRatio = AspectRatio;
|
||||
stream.EncodingProfile = EncodingProfile;
|
||||
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
||||
public enum TSAudioMode
|
||||
{
|
||||
Unknown,
|
||||
DualMono,
|
||||
Stereo,
|
||||
Surround,
|
||||
Extended
|
||||
}
|
||||
|
||||
public class TSAudioStream : TSStream
|
||||
{
|
||||
public TSAudioStream()
|
||||
{
|
||||
}
|
||||
|
||||
public int SampleRate;
|
||||
public int ChannelCount;
|
||||
public int BitDepth;
|
||||
public int LFE;
|
||||
public int DialNorm;
|
||||
public TSAudioMode AudioMode;
|
||||
public TSAudioStream CoreStream;
|
||||
public TSChannelLayout ChannelLayout;
|
||||
|
||||
public static int ConvertSampleRate(
|
||||
TSSampleRate sampleRate)
|
||||
{
|
||||
switch (sampleRate)
|
||||
{
|
||||
case TSSampleRate.SAMPLERATE_48:
|
||||
return 48000;
|
||||
|
||||
case TSSampleRate.SAMPLERATE_96:
|
||||
case TSSampleRate.SAMPLERATE_48_96:
|
||||
return 96000;
|
||||
|
||||
case TSSampleRate.SAMPLERATE_192:
|
||||
case TSSampleRate.SAMPLERATE_48_192:
|
||||
return 192000;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public string ChannelDescription
|
||||
{
|
||||
get
|
||||
{
|
||||
if (ChannelLayout == TSChannelLayout.CHANNELLAYOUT_MONO &&
|
||||
ChannelCount == 2)
|
||||
{
|
||||
}
|
||||
|
||||
string description = "";
|
||||
if (ChannelCount > 0)
|
||||
{
|
||||
description += string.Format(
|
||||
"{0:D}.{1:D}",
|
||||
ChannelCount, LFE);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (ChannelLayout)
|
||||
{
|
||||
case TSChannelLayout.CHANNELLAYOUT_MONO:
|
||||
description += "1.0";
|
||||
break;
|
||||
case TSChannelLayout.CHANNELLAYOUT_STEREO:
|
||||
description += "2.0";
|
||||
break;
|
||||
case TSChannelLayout.CHANNELLAYOUT_MULTI:
|
||||
description += "5.1";
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (AudioMode == TSAudioMode.Extended)
|
||||
{
|
||||
if (StreamType == TSStreamType.AC3_AUDIO)
|
||||
{
|
||||
description += "-EX";
|
||||
}
|
||||
if (StreamType == TSStreamType.DTS_AUDIO ||
|
||||
StreamType == TSStreamType.DTS_HD_AUDIO ||
|
||||
StreamType == TSStreamType.DTS_HD_MASTER_AUDIO)
|
||||
{
|
||||
description += "-ES";
|
||||
}
|
||||
}
|
||||
return description;
|
||||
}
|
||||
}
|
||||
|
||||
public override string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
string description = ChannelDescription;
|
||||
|
||||
if (SampleRate > 0)
|
||||
{
|
||||
description += string.Format(
|
||||
" / {0:D} kHz", SampleRate / 1000);
|
||||
}
|
||||
if (BitRate > 0)
|
||||
{
|
||||
description += string.Format(
|
||||
" / {0:D} kbps", (uint)Math.Round((double)BitRate / 1000));
|
||||
}
|
||||
if (BitDepth > 0)
|
||||
{
|
||||
description += string.Format(
|
||||
" / {0:D}-bit", BitDepth);
|
||||
}
|
||||
if (DialNorm != 0)
|
||||
{
|
||||
description += string.Format(
|
||||
" / DN {0}dB", DialNorm);
|
||||
}
|
||||
if (ChannelCount == 2)
|
||||
{
|
||||
switch (AudioMode)
|
||||
{
|
||||
case TSAudioMode.DualMono:
|
||||
description += " / Dual Mono";
|
||||
break;
|
||||
|
||||
case TSAudioMode.Surround:
|
||||
description += " / Dolby Surround";
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (description.EndsWith(" / "))
|
||||
{
|
||||
description = description.Substring(0, description.Length - 3);
|
||||
}
|
||||
if (CoreStream != null)
|
||||
{
|
||||
string codec = "";
|
||||
switch (CoreStream.StreamType)
|
||||
{
|
||||
case TSStreamType.AC3_AUDIO:
|
||||
codec = "AC3 Embedded";
|
||||
break;
|
||||
case TSStreamType.DTS_AUDIO:
|
||||
codec = "DTS Core";
|
||||
break;
|
||||
}
|
||||
description += string.Format(
|
||||
" ({0}: {1})",
|
||||
codec,
|
||||
CoreStream.Description);
|
||||
}
|
||||
return description;
|
||||
}
|
||||
}
|
||||
|
||||
public override TSStream Clone()
|
||||
{
|
||||
var stream = new TSAudioStream();
|
||||
CopyTo(stream);
|
||||
|
||||
stream.SampleRate = SampleRate;
|
||||
stream.ChannelLayout = ChannelLayout;
|
||||
stream.ChannelCount = ChannelCount;
|
||||
stream.BitDepth = BitDepth;
|
||||
stream.LFE = LFE;
|
||||
stream.DialNorm = DialNorm;
|
||||
stream.AudioMode = AudioMode;
|
||||
if (CoreStream != null)
|
||||
{
|
||||
stream.CoreStream = (TSAudioStream)CoreStream.Clone();
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
||||
public class TSGraphicsStream : TSStream
|
||||
{
|
||||
public TSGraphicsStream()
|
||||
{
|
||||
IsVBR = true;
|
||||
IsInitialized = true;
|
||||
}
|
||||
|
||||
public override TSStream Clone()
|
||||
{
|
||||
var stream = new TSGraphicsStream();
|
||||
CopyTo(stream);
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
||||
public class TSTextStream : TSStream
|
||||
{
|
||||
public TSTextStream()
|
||||
{
|
||||
IsVBR = true;
|
||||
IsInitialized = true;
|
||||
}
|
||||
|
||||
public override TSStream Clone()
|
||||
{
|
||||
var stream = new TSTextStream();
|
||||
CopyTo(stream);
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
//============================================================================
|
||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||
// Copyright © 2010 Cinema Squid
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//=============================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
|
||||
namespace BDInfo
|
||||
{
|
||||
public class TSStreamBuffer
|
||||
{
|
||||
private MemoryStream Stream = new MemoryStream();
|
||||
private int SkipBits = 0;
|
||||
private byte[] Buffer;
|
||||
private int BufferLength = 0;
|
||||
public int TransferLength = 0;
|
||||
|
||||
public TSStreamBuffer()
|
||||
{
|
||||
Buffer = new byte[4096];
|
||||
Stream = new MemoryStream(Buffer);
|
||||
}
|
||||
|
||||
public long Length => (long)BufferLength;
|
||||
|
||||
public long Position => Stream.Position;
|
||||
|
||||
public void Add(
|
||||
byte[] buffer,
|
||||
int offset,
|
||||
int length)
|
||||
{
|
||||
TransferLength += length;
|
||||
|
||||
if (BufferLength + length >= Buffer.Length)
|
||||
{
|
||||
length = Buffer.Length - BufferLength;
|
||||
}
|
||||
if (length > 0)
|
||||
{
|
||||
Array.Copy(buffer, offset, Buffer, BufferLength, length);
|
||||
BufferLength += length;
|
||||
}
|
||||
}
|
||||
|
||||
public void Seek(
|
||||
long offset,
|
||||
SeekOrigin loc)
|
||||
{
|
||||
Stream.Seek(offset, loc);
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
BufferLength = 0;
|
||||
TransferLength = 0;
|
||||
}
|
||||
|
||||
public void BeginRead()
|
||||
{
|
||||
SkipBits = 0;
|
||||
Stream.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
public void EndRead()
|
||||
{
|
||||
}
|
||||
|
||||
public byte[] ReadBytes(int bytes)
|
||||
{
|
||||
if (Stream.Position + bytes >= BufferLength)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] value = new byte[bytes];
|
||||
Stream.Read(value, 0, bytes);
|
||||
return value;
|
||||
}
|
||||
|
||||
public byte ReadByte()
|
||||
{
|
||||
return (byte)Stream.ReadByte();
|
||||
}
|
||||
|
||||
public int ReadBits(int bits)
|
||||
{
|
||||
long pos = Stream.Position;
|
||||
|
||||
int shift = 24;
|
||||
int data = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (pos + i >= BufferLength) break;
|
||||
data += (Stream.ReadByte() << shift);
|
||||
shift -= 8;
|
||||
}
|
||||
var vector = new BitVector32(data);
|
||||
|
||||
int value = 0;
|
||||
for (int i = SkipBits; i < SkipBits + bits; i++)
|
||||
{
|
||||
value <<= 1;
|
||||
value += (vector[1 << (32 - i - 1)] ? 1 : 0);
|
||||
}
|
||||
|
||||
SkipBits += bits;
|
||||
Stream.Seek(pos + (SkipBits >> 3), SeekOrigin.Begin);
|
||||
SkipBits = SkipBits % 8;
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
//============================================================================
|
||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||
// Copyright © 2010 Cinema Squid
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//=============================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BDInfo
|
||||
{
|
||||
public class TSStreamClip
|
||||
{
|
||||
public int AngleIndex = 0;
|
||||
public string Name;
|
||||
public double TimeIn;
|
||||
public double TimeOut;
|
||||
public double RelativeTimeIn;
|
||||
public double RelativeTimeOut;
|
||||
public double Length;
|
||||
|
||||
public ulong FileSize = 0;
|
||||
public ulong InterleavedFileSize = 0;
|
||||
public ulong PayloadBytes = 0;
|
||||
public ulong PacketCount = 0;
|
||||
public double PacketSeconds = 0;
|
||||
|
||||
public List<double> Chapters = new List<double>();
|
||||
|
||||
public TSStreamFile StreamFile = null;
|
||||
public TSStreamClipFile StreamClipFile = null;
|
||||
|
||||
public TSStreamClip(
|
||||
TSStreamFile streamFile,
|
||||
TSStreamClipFile streamClipFile)
|
||||
{
|
||||
if (streamFile != null)
|
||||
{
|
||||
Name = streamFile.Name;
|
||||
StreamFile = streamFile;
|
||||
FileSize = (ulong)StreamFile.FileInfo.Length;
|
||||
if (StreamFile.InterleavedFile != null)
|
||||
{
|
||||
InterleavedFileSize = (ulong)StreamFile.InterleavedFile.FileInfo.Length;
|
||||
}
|
||||
}
|
||||
StreamClipFile = streamClipFile;
|
||||
}
|
||||
|
||||
public string DisplayName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (StreamFile != null &&
|
||||
StreamFile.InterleavedFile != null &&
|
||||
BDInfoSettings.EnableSSIF)
|
||||
{
|
||||
return StreamFile.InterleavedFile.Name;
|
||||
}
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
|
||||
public ulong PacketSize => PacketCount * 192;
|
||||
|
||||
public ulong PacketBitRate
|
||||
{
|
||||
get
|
||||
{
|
||||
if (PacketSeconds > 0)
|
||||
{
|
||||
return (ulong)Math.Round(((PacketSize * 8.0) / PacketSeconds));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsCompatible(TSStreamClip clip)
|
||||
{
|
||||
foreach (var stream1 in StreamFile.Streams.Values)
|
||||
{
|
||||
if (clip.StreamFile.Streams.ContainsKey(stream1.PID))
|
||||
{
|
||||
var stream2 = clip.StreamFile.Streams[stream1.PID];
|
||||
if (stream1.StreamType != stream2.StreamType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,244 +0,0 @@
|
||||
//============================================================================
|
||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
||||
// Copyright © 2010 Cinema Squid
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//=============================================================================
|
||||
|
||||
#undef DEBUG
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using MediaBrowser.Model.IO;
|
||||
|
||||
namespace BDInfo
|
||||
{
|
||||
public class TSStreamClipFile
|
||||
{
|
||||
public FileSystemMetadata FileInfo = null;
|
||||
public string FileType = null;
|
||||
public bool IsValid = false;
|
||||
public string Name = null;
|
||||
|
||||
public Dictionary<ushort, TSStream> Streams =
|
||||
new Dictionary<ushort, TSStream>();
|
||||
|
||||
public TSStreamClipFile(FileSystemMetadata fileInfo)
|
||||
{
|
||||
FileInfo = fileInfo;
|
||||
Name = fileInfo.Name.ToUpper();
|
||||
}
|
||||
|
||||
public void Scan()
|
||||
{
|
||||
Stream fileStream = null;
|
||||
BinaryReader fileReader = null;
|
||||
|
||||
try
|
||||
{
|
||||
#if DEBUG
|
||||
Debug.WriteLine(string.Format(
|
||||
"Scanning {0}...", Name));
|
||||
#endif
|
||||
Streams.Clear();
|
||||
|
||||
fileStream = File.OpenRead(FileInfo.FullName);
|
||||
fileReader = new BinaryReader(fileStream);
|
||||
|
||||
byte[] data = new byte[fileStream.Length];
|
||||
fileReader.Read(data, 0, data.Length);
|
||||
|
||||
byte[] fileType = new byte[8];
|
||||
Array.Copy(data, 0, fileType, 0, fileType.Length);
|
||||
|
||||
FileType = Encoding.ASCII.GetString(fileType, 0, fileType.Length);
|
||||
if (FileType != "HDMV0100" &&
|
||||
FileType != "HDMV0200")
|
||||
{
|
||||
throw new Exception(string.Format(
|
||||
"Clip info file {0} has an unknown file type {1}.",
|
||||
FileInfo.Name, FileType));
|
||||
}
|
||||
#if DEBUG
|
||||
Debug.WriteLine(string.Format(
|
||||
"\tFileType: {0}", FileType));
|
||||
#endif
|
||||
int clipIndex =
|
||||
((int)data[12] << 24) +
|
||||
((int)data[13] << 16) +
|
||||
((int)data[14] << 8) +
|
||||
((int)data[15]);
|
||||
|
||||
int clipLength =
|
||||
((int)data[clipIndex] << 24) +
|
||||
((int)data[clipIndex + 1] << 16) +
|
||||
((int)data[clipIndex + 2] << 8) +
|
||||
((int)data[clipIndex + 3]);
|
||||
|
||||
byte[] clipData = new byte[clipLength];
|
||||
Array.Copy(data, clipIndex + 4, clipData, 0, clipData.Length);
|
||||
|
||||
int streamCount = clipData[8];
|
||||
#if DEBUG
|
||||
Debug.WriteLine(string.Format(
|
||||
"\tStreamCount: {0}", streamCount));
|
||||
#endif
|
||||
int streamOffset = 10;
|
||||
for (int streamIndex = 0;
|
||||
streamIndex < streamCount;
|
||||
streamIndex++)
|
||||
{
|
||||
TSStream stream = null;
|
||||
|
||||
ushort PID = (ushort)
|
||||
((clipData[streamOffset] << 8) +
|
||||
clipData[streamOffset + 1]);
|
||||
|
||||
streamOffset += 2;
|
||||
|
||||
var streamType = (TSStreamType)
|
||||
clipData[streamOffset + 1];
|
||||
switch (streamType)
|
||||
{
|
||||
case TSStreamType.MVC_VIDEO:
|
||||
// TODO
|
||||
break;
|
||||
|
||||
case TSStreamType.AVC_VIDEO:
|
||||
case TSStreamType.MPEG1_VIDEO:
|
||||
case TSStreamType.MPEG2_VIDEO:
|
||||
case TSStreamType.VC1_VIDEO:
|
||||
{
|
||||
var videoFormat = (TSVideoFormat)
|
||||
(clipData[streamOffset + 2] >> 4);
|
||||
var frameRate = (TSFrameRate)
|
||||
(clipData[streamOffset + 2] & 0xF);
|
||||
var aspectRatio = (TSAspectRatio)
|
||||
(clipData[streamOffset + 3] >> 4);
|
||||
|
||||
stream = new TSVideoStream();
|
||||
((TSVideoStream)stream).VideoFormat = videoFormat;
|
||||
((TSVideoStream)stream).AspectRatio = aspectRatio;
|
||||
((TSVideoStream)stream).FrameRate = frameRate;
|
||||
#if DEBUG
|
||||
Debug.WriteLine(string.Format(
|
||||
"\t{0} {1} {2} {3} {4}",
|
||||
PID,
|
||||
streamType,
|
||||
videoFormat,
|
||||
frameRate,
|
||||
aspectRatio));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case TSStreamType.AC3_AUDIO:
|
||||
case TSStreamType.AC3_PLUS_AUDIO:
|
||||
case TSStreamType.AC3_PLUS_SECONDARY_AUDIO:
|
||||
case TSStreamType.AC3_TRUE_HD_AUDIO:
|
||||
case TSStreamType.DTS_AUDIO:
|
||||
case TSStreamType.DTS_HD_AUDIO:
|
||||
case TSStreamType.DTS_HD_MASTER_AUDIO:
|
||||
case TSStreamType.DTS_HD_SECONDARY_AUDIO:
|
||||
case TSStreamType.LPCM_AUDIO:
|
||||
case TSStreamType.MPEG1_AUDIO:
|
||||
case TSStreamType.MPEG2_AUDIO:
|
||||
{
|
||||
byte[] languageBytes = new byte[3];
|
||||
Array.Copy(clipData, streamOffset + 3,
|
||||
languageBytes, 0, languageBytes.Length);
|
||||
string languageCode = Encoding.ASCII.GetString(languageBytes, 0, languageBytes.Length);
|
||||
|
||||
var channelLayout = (TSChannelLayout)
|
||||
(clipData[streamOffset + 2] >> 4);
|
||||
var sampleRate = (TSSampleRate)
|
||||
(clipData[streamOffset + 2] & 0xF);
|
||||
|
||||
stream = new TSAudioStream();
|
||||
((TSAudioStream)stream).LanguageCode = languageCode;
|
||||
((TSAudioStream)stream).ChannelLayout = channelLayout;
|
||||
((TSAudioStream)stream).SampleRate = TSAudioStream.ConvertSampleRate(sampleRate);
|
||||
((TSAudioStream)stream).LanguageCode = languageCode;
|
||||
#if DEBUG
|
||||
Debug.WriteLine(string.Format(
|
||||
"\t{0} {1} {2} {3} {4}",
|
||||
PID,
|
||||
streamType,
|
||||
languageCode,
|
||||
channelLayout,
|
||||
sampleRate));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case TSStreamType.INTERACTIVE_GRAPHICS:
|
||||
case TSStreamType.PRESENTATION_GRAPHICS:
|
||||
{
|
||||
byte[] languageBytes = new byte[3];
|
||||
Array.Copy(clipData, streamOffset + 2,
|
||||
languageBytes, 0, languageBytes.Length);
|
||||
string languageCode = Encoding.ASCII.GetString(languageBytes, 0, languageBytes.Length);
|
||||
|
||||
stream = new TSGraphicsStream();
|
||||
stream.LanguageCode = languageCode;
|
||||
#if DEBUG
|
||||
Debug.WriteLine(string.Format(
|
||||
"\t{0} {1} {2}",
|
||||
PID,
|
||||
streamType,
|
||||
languageCode));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case TSStreamType.SUBTITLE:
|
||||
{
|
||||
byte[] languageBytes = new byte[3];
|
||||
Array.Copy(clipData, streamOffset + 3,
|
||||
languageBytes, 0, languageBytes.Length);
|
||||
string languageCode = Encoding.ASCII.GetString(languageBytes, 0, languageBytes.Length);
|
||||
#if DEBUG
|
||||
Debug.WriteLine(string.Format(
|
||||
"\t{0} {1} {2}",
|
||||
PID,
|
||||
streamType,
|
||||
languageCode));
|
||||
#endif
|
||||
stream = new TSTextStream();
|
||||
stream.LanguageCode = languageCode;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (stream != null)
|
||||
{
|
||||
stream.PID = PID;
|
||||
stream.StreamType = streamType;
|
||||
Streams.Add(PID, stream);
|
||||
}
|
||||
|
||||
streamOffset += clipData[streamOffset] + 1;
|
||||
}
|
||||
IsValid = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (fileReader != null) fileReader.Dispose();
|
||||
if (fileStream != null) fileStream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
145
CONTRIBUTORS.md
145
CONTRIBUTORS.md
@@ -1,35 +1,132 @@
|
||||
# Jellyfin Contributors
|
||||
|
||||
- [JoshuaBoniface](https://github.com/joshuaboniface)
|
||||
- [nvllsvm](https://github.com/nvllsvm)
|
||||
- [JustAMan](https://github.com/JustAMan)
|
||||
- [dcrdev](https://github.com/dcrdev)
|
||||
- [EraYaN](https://github.com/EraYaN)
|
||||
- [flemse](https://github.com/flemse)
|
||||
- [97carmine](https://github.com/97carmine)
|
||||
- [Abbe98](https://github.com/Abbe98)
|
||||
- [agrenott](https://github.com/agrenott)
|
||||
- [AndreCarvalho](https://github.com/AndreCarvalho)
|
||||
- [anthonylavado](https://github.com/anthonylavado)
|
||||
- [Artiume](https://github.com/Artiume)
|
||||
- [AThomsen](https://github.com/AThomsen)
|
||||
- [bilde2910](https://github.com/bilde2910)
|
||||
- [bfayers](https://github.com/bfayers)
|
||||
- [Bond_009](https://github.com/Bond-009)
|
||||
- [AnthonyLavado](https://github.com/anthonylavado)
|
||||
- [sparky8251](https://github.com/sparky8251)
|
||||
- [LeoVerto](https://github.com/LeoVerto)
|
||||
- [grafixeyehero](https://github.com/grafixeyehero)
|
||||
- [BnMcG](https://github.com/BnMcG)
|
||||
- [Bond-009](https://github.com/Bond-009)
|
||||
- [brianjmurrell](https://github.com/brianjmurrell)
|
||||
- [bugfixin](https://github.com/bugfixin)
|
||||
- [chaosinnovator](https://github.com/chaosinnovator)
|
||||
- [ckcr4lyf](https://github.com/ckcr4lyf)
|
||||
- [crankdoofus](https://github.com/crankdoofus)
|
||||
- [crobibero](https://github.com/crobibero)
|
||||
- [cromefire](https://github.com/cromefire)
|
||||
- [cryptobank](https://github.com/cryptobank)
|
||||
- [cvium](https://github.com/cvium)
|
||||
- [wtayl0r](https://github.com/wtayl0r)
|
||||
- [TtheCreator](https://github.com/Tthecreator)
|
||||
- [dannymichel](https://github.com/dannymichel)
|
||||
- [DaveChild](https://github.com/DaveChild)
|
||||
- [dcrdev](https://github.com/dcrdev)
|
||||
- [dhartung](https://github.com/dhartung)
|
||||
- [dinki](https://github.com/dinki)
|
||||
- [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)
|
||||
- [dlahoti](https://github.com/dlahoti)
|
||||
- [dmitrylyzo](https://github.com/dmitrylyzo)
|
||||
- [DMouse10462](https://github.com/DMouse10462)
|
||||
- [DrPandemic](https://github.com/DrPandemic)
|
||||
- [EraYaN](https://github.com/EraYaN)
|
||||
- [escabe](https://github.com/escabe)
|
||||
- [excelite](https://github.com/excelite)
|
||||
- [fasheng](https://github.com/fasheng)
|
||||
- [ploughpuff](https://github.com/ploughpuff)
|
||||
- [pjeanjean](https://github.com/pjeanjean)
|
||||
- [DrPandemic](https://github.com/drpandemic)
|
||||
- [joern-h](https://github.com/joern-h)
|
||||
- [Khinenw](https://github.com/HelloWorld017)
|
||||
- [ferferga](https://github.com/ferferga)
|
||||
- [fhriley](https://github.com/fhriley)
|
||||
- [flemse](https://github.com/flemse)
|
||||
- [Froghut](https://github.com/Froghut)
|
||||
- [fruhnow](https://github.com/fruhnow)
|
||||
- [geilername](https://github.com/geilername)
|
||||
- [gnattu](https://github.com/gnattu)
|
||||
- [grafixeyehero](https://github.com/grafixeyehero)
|
||||
- [h1nk](https://github.com/h1nk)
|
||||
- [hawken93](https://github.com/hawken93)
|
||||
- [HelloWorld017](https://github.com/HelloWorld017)
|
||||
- [jftuga](https://github.com/jftuga)
|
||||
- [joern-h](https://github.com/joern-h)
|
||||
- [joshuaboniface](https://github.com/joshuaboniface)
|
||||
- [JustAMan](https://github.com/JustAMan)
|
||||
- [justinfenn](https://github.com/justinfenn)
|
||||
- [KerryRJ](https://github.com/KerryRJ)
|
||||
- [Larvitar](https://github.com/Larvitar)
|
||||
- [LeoVerto](https://github.com/LeoVerto)
|
||||
- [Liggy](https://github.com/Liggy)
|
||||
- [LogicalPhallacy](https://github.com/LogicalPhallacy)
|
||||
- [loli10K](https://github.com/loli10K)
|
||||
- [lostmypillow](https://github.com/lostmypillow)
|
||||
- [Lynxy](https://github.com/Lynxy)
|
||||
- [ManfredRichthofen](https://github.com/ManfredRichthofen)
|
||||
- [Marenz](https://github.com/Marenz)
|
||||
- [marius-luca-87](https://github.com/marius-luca-87)
|
||||
- [mark-monteiro](https://github.com/mark-monteiro)
|
||||
- [Matt07211](https://github.com/Matt07211)
|
||||
- [mcarlton00](https://github.com/mcarlton00)
|
||||
- [mitchfizz05](https://github.com/mitchfizz05)
|
||||
- [MrTimscampi](https://github.com/MrTimscampi)
|
||||
- [n8225](https://github.com/n8225)
|
||||
- [Narfinger](https://github.com/Narfinger)
|
||||
- [NathanPickard](https://github.com/NathanPickard)
|
||||
- [neilsb](https://github.com/neilsb)
|
||||
- [nevado](https://github.com/nevado)
|
||||
- [Nickbert7](https://github.com/Nickbert7)
|
||||
- [nvllsvm](https://github.com/nvllsvm)
|
||||
- [nyanmisaka](https://github.com/nyanmisaka)
|
||||
- [oddstr13](https://github.com/oddstr13)
|
||||
- [petermcneil](https://github.com/petermcneil)
|
||||
- [Phlogi](https://github.com/Phlogi)
|
||||
- [pjeanjean](https://github.com/pjeanjean)
|
||||
- [ploughpuff](https://github.com/ploughpuff)
|
||||
- [pR0Ps](https://github.com/pR0Ps)
|
||||
- [PrplHaz4](https://github.com/PrplHaz4)
|
||||
- [RazeLighter777](https://github.com/RazeLighter777)
|
||||
- [redSpoutnik](https://github.com/redSpoutnik)
|
||||
- [ringmatter](https://github.com/ringmatter)
|
||||
- [ryan-hartzell](https://github.com/ryan-hartzell)
|
||||
- [s0urcelab](https://github.com/s0urcelab)
|
||||
- [sachk](https://github.com/sachk)
|
||||
- [sammyrc34](https://github.com/sammyrc34)
|
||||
- [samuel9554](https://github.com/samuel9554)
|
||||
- [scheidleon](https://github.com/scheidleon)
|
||||
- [sebPomme](https://github.com/sebPomme)
|
||||
- [SenorSmartyPants](https://github.com/SenorSmartyPants)
|
||||
- [shemanaev](https://github.com/shemanaev)
|
||||
- [skaro13](https://github.com/skaro13)
|
||||
- [sl1288](https://github.com/sl1288)
|
||||
- [sorinyo2004](https://github.com/sorinyo2004)
|
||||
- [sparky8251](https://github.com/sparky8251)
|
||||
- [stanionascu](https://github.com/stanionascu)
|
||||
- [stevehayles](https://github.com/stevehayles)
|
||||
- [SuperSandro2000](https://github.com/SuperSandro2000)
|
||||
- [tbraeutigam](https://github.com/tbraeutigam)
|
||||
- [teacupx](https://github.com/teacupx)
|
||||
- [Terror-Gene](https://github.com/Terror-Gene)
|
||||
- [ThatNerdyPikachu](https://github.com/ThatNerdyPikachu)
|
||||
- [ThibaultNocchi](https://github.com/ThibaultNocchi)
|
||||
- [thornbill](https://github.com/thornbill)
|
||||
- [ThreeFive-O](https://github.com/ThreeFive-O)
|
||||
- [TrisMcC](https://github.com/TrisMcC)
|
||||
- [trumblejoe](https://github.com/trumblejoe)
|
||||
- [TtheCreator](https://github.com/TtheCreator)
|
||||
- [twinkybot](https://github.com/twinkybot)
|
||||
- [Ullmie02](https://github.com/Ullmie02)
|
||||
- [Unhelpful](https://github.com/Unhelpful)
|
||||
- [viaregio](https://github.com/viaregio)
|
||||
- [vitorsemeano](https://github.com/vitorsemeano)
|
||||
- [voodoos](https://github.com/voodoos)
|
||||
- [whooo](https://github.com/whooo)
|
||||
- [WiiPlayer2](https://github.com/WiiPlayer2)
|
||||
- [WillWill56](https://github.com/WillWill56)
|
||||
- [wtayl0r](https://github.com/wtayl0r)
|
||||
- [Wuerfelbecher](https://github.com/Wuerfelbecher)
|
||||
- [Wunax](https://github.com/Wunax)
|
||||
- [WWWesten](https://github.com/WWWesten)
|
||||
- [WX9yMOXWId](https://github.com/WX9yMOXWId)
|
||||
- [xosdy](https://github.com/xosdy)
|
||||
- [XVicarious](https://github.com/XVicarious)
|
||||
- [YouKnowBlom](https://github.com/YouKnowBlom)
|
||||
|
||||
# Emby Contributors
|
||||
|
||||
|
||||
52
Dockerfile
52
Dockerfile
@@ -1,42 +1,64 @@
|
||||
ARG DOTNET_VERSION=2.2
|
||||
ARG DOTNET_VERSION=3.1
|
||||
ARG FFMPEG_VERSION=latest
|
||||
|
||||
FROM node:alpine as web-builder
|
||||
ARG JELLYFIN_WEB_VERSION=v10.4.0
|
||||
RUN apk add curl \
|
||||
10.5.1
|
||||
RUN apk add curl git \
|
||||
&& curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
|
||||
&& cd jellyfin-web-* \
|
||||
&& yarn install \
|
||||
&& yarn build \
|
||||
&& mv dist /dist
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/core/sdk:${DOTNET_VERSION} as builder
|
||||
FROM mcr.microsoft.com/dotnet/core/sdk:${DOTNET_VERSION}-buster as builder
|
||||
WORKDIR /repo
|
||||
COPY . .
|
||||
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||
RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-x64 "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
|
||||
# because of changes in docker and systemd we need to not build in parallel at the moment
|
||||
# see https://success.docker.com/article/how-to-reserve-resource-temporarily-unavailable-errors-due-to-tasksmax-setting
|
||||
RUN dotnet publish Jellyfin.Server --disable-parallel --configuration Release --output="/jellyfin" --self-contained --runtime linux-x64 "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
|
||||
|
||||
FROM jellyfin/ffmpeg:${FFMPEG_VERSION} as ffmpeg
|
||||
FROM debian:buster-slim
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/core/runtime:${DOTNET_VERSION}
|
||||
COPY --from=ffmpeg / /
|
||||
# https://askubuntu.com/questions/972516/debian-frontend-environment-variable
|
||||
ARG DEBIAN_FRONTEND="noninteractive"
|
||||
# http://stackoverflow.com/questions/48162574/ddg#49462622
|
||||
ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn
|
||||
# https://github.com/NVIDIA/nvidia-docker/wiki/Installation-(Native-GPU-Support)
|
||||
ENV NVIDIA_DRIVER_CAPABILITIES="compute,video,utility"
|
||||
|
||||
COPY --from=ffmpeg /opt/ffmpeg /opt/ffmpeg
|
||||
COPY --from=builder /jellyfin /jellyfin
|
||||
COPY --from=web-builder /dist /jellyfin/jellyfin-web
|
||||
# Install dependencies:
|
||||
# libfontconfig1: needed for Skia
|
||||
# libgomp1: needed for ffmpeg
|
||||
# libva-drm2: needed for ffmpeg
|
||||
# mesa-va-drivers: needed for VAAPI
|
||||
RUN apt-get update \
|
||||
&& apt-get install --no-install-recommends --no-install-suggests -y \
|
||||
libfontconfig1 mesa-va-drivers \
|
||||
&& apt-get clean autoclean \
|
||||
&& apt-get autoremove \
|
||||
libfontconfig1 \
|
||||
libgomp1 \
|
||||
libva-drm2 \
|
||||
mesa-va-drivers \
|
||||
openssl \
|
||||
ca-certificates \
|
||||
vainfo \
|
||||
i965-va-driver \
|
||||
&& apt-get clean autoclean -y\
|
||||
&& apt-get autoremove -y\
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& mkdir -p /cache /config /media \
|
||||
&& chmod 777 /cache /config /media
|
||||
&& chmod 777 /cache /config /media \
|
||||
&& ln -s /opt/ffmpeg/bin/ffmpeg /usr/local/bin \
|
||||
&& ln -s /opt/ffmpeg/bin/ffprobe /usr/local/bin
|
||||
|
||||
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
|
||||
|
||||
EXPOSE 8096
|
||||
VOLUME /cache /config /media
|
||||
ENTRYPOINT dotnet /jellyfin/jellyfin.dll \
|
||||
--datadir /config \
|
||||
--cachedir /cache \
|
||||
--ffmpeg /usr/local/bin/ffmpeg
|
||||
ENTRYPOINT ["./jellyfin/jellyfin", \
|
||||
"--datadir", "/config", \
|
||||
"--cachedir", "/cache", \
|
||||
"--ffmpeg", "/usr/local/bin/ffmpeg"]
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
# DESIGNED FOR BUILDING ON AMD64 ONLY
|
||||
#####################################
|
||||
# Requires binfm_misc registration
|
||||
# https://github.com/multiarch/qemu-user-static#binfmt_misc-register
|
||||
ARG DOTNET_VERSION=3.0
|
||||
ARG DOTNET_VERSION=3.1
|
||||
|
||||
|
||||
FROM node:alpine as web-builder
|
||||
ARG JELLYFIN_WEB_VERSION=v10.4.0
|
||||
RUN apk add curl \
|
||||
10.5.1
|
||||
RUN apk add curl git \
|
||||
&& curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
|
||||
&& cd jellyfin-web-* \
|
||||
&& yarn install \
|
||||
@@ -17,8 +19,6 @@ 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
|
||||
@@ -26,19 +26,47 @@ RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin"
|
||||
|
||||
|
||||
FROM multiarch/qemu-user-static:x86_64-arm as qemu
|
||||
FROM mcr.microsoft.com/dotnet/core/runtime:${DOTNET_VERSION}-stretch-slim-arm32v7
|
||||
FROM arm32v7/debian:buster-slim
|
||||
|
||||
# https://askubuntu.com/questions/972516/debian-frontend-environment-variable
|
||||
ARG DEBIAN_FRONTEND="noninteractive"
|
||||
# http://stackoverflow.com/questions/48162574/ddg#49462622
|
||||
ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn
|
||||
# https://github.com/NVIDIA/nvidia-docker/wiki/Installation-(Native-GPU-Support)
|
||||
ENV NVIDIA_DRIVER_CAPABILITIES="compute,video,utility"
|
||||
|
||||
COPY --from=qemu /usr/bin/qemu-arm-static /usr/bin
|
||||
RUN apt-get update \
|
||||
&& apt-get install --no-install-recommends --no-install-suggests -y ffmpeg \
|
||||
&& apt-get install --no-install-recommends --no-install-suggests -y ca-certificates gnupg curl && \
|
||||
curl -ks https://repo.jellyfin.org/debian/jellyfin_team.gpg.key | apt-key add - && \
|
||||
curl -s https://keyserver.ubuntu.com/pks/lookup?op=get\&search=0x6587ffd6536b8826e88a62547876ae518cbcf2f2 | apt-key add - && \
|
||||
echo 'deb [arch=armhf] https://repo.jellyfin.org/debian buster main' > /etc/apt/sources.list.d/jellyfin.list && \
|
||||
echo "deb http://ppa.launchpad.net/ubuntu-raspi2/ppa/ubuntu bionic main">> /etc/apt/sources.list.d/raspbins.list && \
|
||||
apt-get update && \
|
||||
apt-get install --no-install-recommends --no-install-suggests -y \
|
||||
jellyfin-ffmpeg \
|
||||
libssl-dev \
|
||||
libfontconfig1 \
|
||||
libfreetype6 \
|
||||
libomxil-bellagio0 \
|
||||
libomxil-bellagio-bin \
|
||||
libraspberrypi0 \
|
||||
vainfo \
|
||||
libva2 \
|
||||
&& apt-get remove curl gnupg -y \
|
||||
&& apt-get clean autoclean -y \
|
||||
&& apt-get autoremove -y \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& mkdir -p /cache /config /media \
|
||||
&& chmod 777 /cache /config /media
|
||||
COPY --from=builder /jellyfin /jellyfin
|
||||
COPY --from=web-builder /dist /jellyfin/jellyfin-web
|
||||
|
||||
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
|
||||
|
||||
EXPOSE 8096
|
||||
VOLUME /cache /config /media
|
||||
ENTRYPOINT dotnet /jellyfin/jellyfin.dll \
|
||||
--datadir /config \
|
||||
--cachedir /cache \
|
||||
--ffmpeg /usr/bin/ffmpeg
|
||||
ENTRYPOINT ["./jellyfin/jellyfin", \
|
||||
"--datadir", "/config", \
|
||||
"--cachedir", "/cache", \
|
||||
"--ffmpeg", "/usr/lib/jellyfin-ffmpeg"]
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
# DESIGNED FOR BUILDING ON AMD64 ONLY
|
||||
#####################################
|
||||
# Requires binfm_misc registration
|
||||
# https://github.com/multiarch/qemu-user-static#binfmt_misc-register
|
||||
ARG DOTNET_VERSION=3.0
|
||||
ARG DOTNET_VERSION=3.1
|
||||
|
||||
|
||||
FROM node:alpine as web-builder
|
||||
ARG JELLYFIN_WEB_VERSION=v10.4.0
|
||||
RUN apk add curl \
|
||||
10.5.1
|
||||
RUN apk add curl git \
|
||||
&& curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
|
||||
&& cd jellyfin-web-* \
|
||||
&& yarn install \
|
||||
@@ -17,28 +19,43 @@ 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 dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm64 "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
|
||||
|
||||
|
||||
FROM multiarch/qemu-user-static:x86_64-aarch64 as qemu
|
||||
FROM mcr.microsoft.com/dotnet/core/runtime:${DOTNET_VERSION}-stretch-slim-arm64v8
|
||||
FROM arm64v8/debian:buster-slim
|
||||
|
||||
# https://askubuntu.com/questions/972516/debian-frontend-environment-variable
|
||||
ARG DEBIAN_FRONTEND="noninteractive"
|
||||
# http://stackoverflow.com/questions/48162574/ddg#49462622
|
||||
ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn
|
||||
# https://github.com/NVIDIA/nvidia-docker/wiki/Installation-(Native-GPU-Support)
|
||||
ENV NVIDIA_DRIVER_CAPABILITIES="compute,video,utility"
|
||||
|
||||
COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin
|
||||
RUN apt-get update \
|
||||
&& apt-get install --no-install-recommends --no-install-suggests -y ffmpeg \
|
||||
RUN apt-get update && apt-get install --no-install-recommends --no-install-suggests -y \
|
||||
ffmpeg \
|
||||
libssl-dev \
|
||||
ca-certificates \
|
||||
libfontconfig1 \
|
||||
libfreetype6 \
|
||||
libomxil-bellagio0 \
|
||||
libomxil-bellagio-bin \
|
||||
&& apt-get clean autoclean -y \
|
||||
&& apt-get autoremove -y \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& mkdir -p /cache /config /media \
|
||||
&& chmod 777 /cache /config /media
|
||||
COPY --from=builder /jellyfin /jellyfin
|
||||
COPY --from=web-builder /dist /jellyfin/jellyfin-web
|
||||
|
||||
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
|
||||
|
||||
EXPOSE 8096
|
||||
VOLUME /cache /config /media
|
||||
ENTRYPOINT dotnet /jellyfin/jellyfin.dll \
|
||||
--datadir /config \
|
||||
--cachedir /cache \
|
||||
--ffmpeg /usr/bin/ffmpeg
|
||||
ENTRYPOINT ["./jellyfin/jellyfin", \
|
||||
"--datadir", "/config", \
|
||||
"--cachedir", "/cache", \
|
||||
"--ffmpeg", "/usr/bin/ffmpeg"]
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace DvdLib.Ifo
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var vmgFs = _fileSystem.GetFileStream(vmgPath.FullName, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read))
|
||||
using (var vmgFs = new FileStream(vmgPath.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
using (var vmgRead = new BigEndianBinaryReader(vmgFs))
|
||||
{
|
||||
@@ -95,7 +95,7 @@ namespace DvdLib.Ifo
|
||||
{
|
||||
VTSPaths[vtsNum] = vtsPath;
|
||||
|
||||
using (var vtsFs = _fileSystem.GetFileStream(vtsPath, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read))
|
||||
using (var vtsFs = new FileStream(vtsPath, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
using (var vtsRead = new BigEndianBinaryReader(vtsFs))
|
||||
{
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Emby.Dlna.Main;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Model.Services;
|
||||
@@ -108,12 +110,13 @@ namespace Emby.Dlna.Api
|
||||
|
||||
public class DlnaServerService : IService, IRequiresRequest
|
||||
{
|
||||
private readonly IDlnaManager _dlnaManager;
|
||||
|
||||
private const string XMLContentType = "text/xml; charset=UTF-8";
|
||||
|
||||
private readonly IDlnaManager _dlnaManager;
|
||||
private readonly IHttpResultFactory _resultFactory;
|
||||
private readonly IServerConfigurationManager _configurationManager;
|
||||
|
||||
public IRequest Request { get; set; }
|
||||
private IHttpResultFactory _resultFactory;
|
||||
|
||||
private IContentDirectory ContentDirectory => DlnaEntryPoint.Current.ContentDirectory;
|
||||
|
||||
@@ -121,10 +124,14 @@ namespace Emby.Dlna.Api
|
||||
|
||||
private IMediaReceiverRegistrar MediaReceiverRegistrar => DlnaEntryPoint.Current.MediaReceiverRegistrar;
|
||||
|
||||
public DlnaServerService(IDlnaManager dlnaManager, IHttpResultFactory httpResultFactory)
|
||||
public DlnaServerService(
|
||||
IDlnaManager dlnaManager,
|
||||
IHttpResultFactory httpResultFactory,
|
||||
IServerConfigurationManager configurationManager)
|
||||
{
|
||||
_dlnaManager = dlnaManager;
|
||||
_resultFactory = httpResultFactory;
|
||||
_configurationManager = configurationManager;
|
||||
}
|
||||
|
||||
private string GetHeader(string name)
|
||||
@@ -166,32 +173,32 @@ namespace Emby.Dlna.Api
|
||||
return _resultFactory.GetResult(Request, xml, XMLContentType);
|
||||
}
|
||||
|
||||
public object Post(ProcessMediaReceiverRegistrarControlRequest request)
|
||||
public async Task<object> Post(ProcessMediaReceiverRegistrarControlRequest request)
|
||||
{
|
||||
var response = PostAsync(request.RequestStream, MediaReceiverRegistrar);
|
||||
var response = await PostAsync(request.RequestStream, MediaReceiverRegistrar).ConfigureAwait(false);
|
||||
|
||||
return _resultFactory.GetResult(Request, response.Xml, XMLContentType);
|
||||
}
|
||||
|
||||
public object Post(ProcessContentDirectoryControlRequest request)
|
||||
public async Task<object> Post(ProcessContentDirectoryControlRequest request)
|
||||
{
|
||||
var response = PostAsync(request.RequestStream, ContentDirectory);
|
||||
var response = await PostAsync(request.RequestStream, ContentDirectory).ConfigureAwait(false);
|
||||
|
||||
return _resultFactory.GetResult(Request, response.Xml, XMLContentType);
|
||||
}
|
||||
|
||||
public object Post(ProcessConnectionManagerControlRequest request)
|
||||
public async Task<object> Post(ProcessConnectionManagerControlRequest request)
|
||||
{
|
||||
var response = PostAsync(request.RequestStream, ConnectionManager);
|
||||
var response = await PostAsync(request.RequestStream, ConnectionManager).ConfigureAwait(false);
|
||||
|
||||
return _resultFactory.GetResult(Request, response.Xml, XMLContentType);
|
||||
}
|
||||
|
||||
private ControlResponse PostAsync(Stream requestStream, IUpnpService service)
|
||||
private Task<ControlResponse> PostAsync(Stream requestStream, IUpnpService service)
|
||||
{
|
||||
var id = GetPathValue(2);
|
||||
var id = GetPathValue(2).ToString();
|
||||
|
||||
return service.ProcessControlRequest(new ControlRequest
|
||||
return service.ProcessControlRequestAsync(new ControlRequest
|
||||
{
|
||||
Headers = Request.Headers,
|
||||
InputXml = requestStream,
|
||||
@@ -200,38 +207,99 @@ namespace Emby.Dlna.Api
|
||||
});
|
||||
}
|
||||
|
||||
protected string GetPathValue(int index)
|
||||
// Copied from MediaBrowser.Api/BaseApiService.cs
|
||||
// TODO: Remove code duplication
|
||||
/// <summary>
|
||||
/// Gets the path segment at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the path segment.</param>
|
||||
/// <returns>The path segment at the specified index.</returns>
|
||||
/// <exception cref="IndexOutOfRangeException" >Path doesn't contain enough segments.</exception>
|
||||
/// <exception cref="InvalidDataException" >Path doesn't start with the base url.</exception>
|
||||
protected internal ReadOnlySpan<char> GetPathValue(int index)
|
||||
{
|
||||
var pathInfo = Parse(Request.PathInfo);
|
||||
var first = pathInfo[0];
|
||||
static void ThrowIndexOutOfRangeException()
|
||||
=> throw new IndexOutOfRangeException("Path doesn't contain enough segments.");
|
||||
|
||||
// backwards compatibility
|
||||
// TODO: Work out what this is doing.
|
||||
if (string.Equals(first, "mediabrowser", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(first, "emby", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(first, "jellyfin", StringComparison.OrdinalIgnoreCase))
|
||||
static void ThrowInvalidDataException()
|
||||
=> throw new InvalidDataException("Path doesn't start with the base url.");
|
||||
|
||||
ReadOnlySpan<char> path = Request.PathInfo;
|
||||
|
||||
// Remove the protocol part from the url
|
||||
int pos = path.LastIndexOf("://");
|
||||
if (pos != -1)
|
||||
{
|
||||
index++;
|
||||
path = path.Slice(pos + 3);
|
||||
}
|
||||
|
||||
return pathInfo[index];
|
||||
}
|
||||
|
||||
private List<string> Parse(string pathUri)
|
||||
{
|
||||
var actionParts = pathUri.Split(new[] { "://" }, StringSplitOptions.None);
|
||||
|
||||
var pathInfo = actionParts[actionParts.Length - 1];
|
||||
|
||||
var optionsPos = pathInfo.LastIndexOf('?');
|
||||
if (optionsPos != -1)
|
||||
// Remove the query string
|
||||
pos = path.LastIndexOf('?');
|
||||
if (pos != -1)
|
||||
{
|
||||
pathInfo = pathInfo.Substring(0, optionsPos);
|
||||
path = path.Slice(0, pos);
|
||||
}
|
||||
|
||||
var args = pathInfo.Split('/');
|
||||
// Remove the domain
|
||||
pos = path.IndexOf('/');
|
||||
if (pos != -1)
|
||||
{
|
||||
path = path.Slice(pos);
|
||||
}
|
||||
|
||||
return args.Skip(1).ToList();
|
||||
// Remove base url
|
||||
string baseUrl = _configurationManager.Configuration.BaseUrl;
|
||||
int baseUrlLen = baseUrl.Length;
|
||||
if (baseUrlLen != 0)
|
||||
{
|
||||
if (path.StartsWith(baseUrl, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
path = path.Slice(baseUrlLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The path doesn't start with the base url,
|
||||
// how did we get here?
|
||||
ThrowInvalidDataException();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove leading /
|
||||
path = path.Slice(1);
|
||||
|
||||
// Backwards compatibility
|
||||
const string Emby = "emby/";
|
||||
if (path.StartsWith(Emby, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
path = path.Slice(Emby.Length);
|
||||
}
|
||||
|
||||
const string MediaBrowser = "mediabrowser/";
|
||||
if (path.StartsWith(MediaBrowser, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
path = path.Slice(MediaBrowser.Length);
|
||||
}
|
||||
|
||||
// Skip segments until we are at the right index
|
||||
for (int i = 0; i < index; i++)
|
||||
{
|
||||
pos = path.IndexOf('/');
|
||||
if (pos == -1)
|
||||
{
|
||||
ThrowIndexOutOfRangeException();
|
||||
}
|
||||
|
||||
path = path.Slice(pos + 1);
|
||||
}
|
||||
|
||||
// Remove the rest
|
||||
pos = path.IndexOf('/');
|
||||
if (pos != -1)
|
||||
{
|
||||
path = path.Slice(0, pos);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
public object Get(GetIcon request)
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System.Linq;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Net;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
namespace Emby.Dlna.Common
|
||||
{
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System.Globalization;
|
||||
|
||||
namespace Emby.Dlna.Common
|
||||
{
|
||||
@@ -13,9 +17,14 @@ namespace Emby.Dlna.Common
|
||||
|
||||
public string Depth { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0}x{1}", Height, Width);
|
||||
return string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"{0}x{1}",
|
||||
Height,
|
||||
Width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
namespace Emby.Dlna.Common
|
||||
{
|
||||
@@ -13,9 +15,8 @@ namespace Emby.Dlna.Common
|
||||
|
||||
public string EventSubUrl { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0}", ServiceId);
|
||||
}
|
||||
=> ServiceId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Emby.Dlna.Common
|
||||
{
|
||||
public class ServiceAction
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public List<Argument> ArgumentList { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
|
||||
public ServiceAction()
|
||||
{
|
||||
ArgumentList = new List<Argument>();
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public List<Argument> ArgumentList { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System;
|
||||
|
||||
namespace Emby.Dlna.Common
|
||||
{
|
||||
public class StateVariable
|
||||
{
|
||||
public StateVariable()
|
||||
{
|
||||
AllowedValues = Array.Empty<string>();
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string DataType { get; set; }
|
||||
@@ -12,14 +20,8 @@ namespace Emby.Dlna.Common
|
||||
|
||||
public string[] AllowedValues { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
|
||||
public StateVariable()
|
||||
{
|
||||
AllowedValues = Array.Empty<string>();
|
||||
}
|
||||
=> Name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
namespace Emby.Dlna.Configuration
|
||||
{
|
||||
public class DlnaOptions
|
||||
{
|
||||
public bool EnablePlayTo { get; set; }
|
||||
public bool EnableServer { get; set; }
|
||||
public bool EnableDebugLog { get; set; }
|
||||
public bool BlastAliveMessages { get; set; }
|
||||
public bool SendOnlyMatchedHost { get; set; }
|
||||
public int ClientDiscoveryIntervalSeconds { get; set; }
|
||||
public int BlastAliveMessageIntervalSeconds { get; set; }
|
||||
public string DefaultUserId { get; set; }
|
||||
|
||||
public DlnaOptions()
|
||||
{
|
||||
EnablePlayTo = true;
|
||||
@@ -21,5 +14,21 @@ namespace Emby.Dlna.Configuration
|
||||
ClientDiscoveryIntervalSeconds = 60;
|
||||
BlastAliveMessageIntervalSeconds = 1800;
|
||||
}
|
||||
|
||||
public bool EnablePlayTo { get; set; }
|
||||
|
||||
public bool EnableServer { get; set; }
|
||||
|
||||
public bool EnableDebugLog { get; set; }
|
||||
|
||||
public bool BlastAliveMessages { get; set; }
|
||||
|
||||
public bool SendOnlyMatchedHost { get; set; }
|
||||
|
||||
public int ClientDiscoveryIntervalSeconds { get; set; }
|
||||
|
||||
public int BlastAliveMessageIntervalSeconds { get; set; }
|
||||
|
||||
public string DefaultUserId { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Emby.Dlna.Configuration;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Emby.Dlna.Service;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
@@ -20,17 +24,19 @@ namespace Emby.Dlna.ConnectionManager
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string GetServiceXml()
|
||||
{
|
||||
return new ConnectionManagerXmlBuilder().GetXml();
|
||||
}
|
||||
|
||||
public ControlResponse ProcessControlRequest(ControlRequest request)
|
||||
/// <inheritdoc />
|
||||
public Task<ControlResponse> ProcessControlRequestAsync(ControlRequest request)
|
||||
{
|
||||
var profile = _dlna.GetProfile(request.Headers) ??
|
||||
_dlna.GetDefaultProfile();
|
||||
|
||||
return new ControlHandler(_config, _logger, profile).ProcessControlRequest(request);
|
||||
return new ControlHandler(_config, _logger, profile).ProcessControlRequestAsync(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Emby.Dlna.Common;
|
||||
using Emby.Dlna.Service;
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
using Emby.Dlna.Service;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
@@ -12,29 +16,28 @@ namespace Emby.Dlna.ConnectionManager
|
||||
{
|
||||
private readonly DeviceProfile _profile;
|
||||
|
||||
protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams)
|
||||
{
|
||||
if (string.Equals(methodName, "GetProtocolInfo", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return HandleGetProtocolInfo();
|
||||
}
|
||||
|
||||
throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
|
||||
}
|
||||
|
||||
private IEnumerable<KeyValuePair<string, string>> HandleGetProtocolInfo()
|
||||
{
|
||||
return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ "Source", _profile.ProtocolInfo },
|
||||
{ "Sink", "" }
|
||||
};
|
||||
}
|
||||
|
||||
public ControlHandler(IServerConfigurationManager config, ILogger logger, DeviceProfile profile)
|
||||
: base(config, logger)
|
||||
{
|
||||
_profile = profile;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void WriteResult(string methodName, IDictionary<string, string> methodParams, XmlWriter xmlWriter)
|
||||
{
|
||||
if (string.Equals(methodName, "GetProtocolInfo", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
HandleGetProtocolInfo(xmlWriter);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
|
||||
}
|
||||
|
||||
private void HandleGetProtocolInfo(XmlWriter xmlWriter)
|
||||
{
|
||||
xmlWriter.WriteElementString("Source", _profile.ProtocolInfo);
|
||||
xmlWriter.WriteElementString("Sink", string.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Emby.Dlna.Common;
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Emby.Dlna.Service;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
@@ -67,12 +70,14 @@ namespace Emby.Dlna.ContentDirectory
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string GetServiceXml()
|
||||
{
|
||||
return new ContentDirectoryXmlBuilder().GetXml();
|
||||
}
|
||||
|
||||
public ControlResponse ProcessControlRequest(ControlRequest request)
|
||||
/// <inheritdoc />
|
||||
public Task<ControlResponse> ProcessControlRequestAsync(ControlRequest request)
|
||||
{
|
||||
var profile = _dlna.GetProfile(request.Headers) ??
|
||||
_dlna.GetDefaultProfile();
|
||||
@@ -97,14 +102,14 @@ namespace Emby.Dlna.ContentDirectory
|
||||
_userViewManager,
|
||||
_mediaEncoder,
|
||||
_tvSeriesManager)
|
||||
.ProcessControlRequest(request);
|
||||
.ProcessControlRequestAsync(request);
|
||||
}
|
||||
|
||||
private User GetUser(DeviceProfile profile)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(profile.UserId))
|
||||
{
|
||||
var user = _userManager.GetUserById(profile.UserId);
|
||||
var user = _userManager.GetUserById(Guid.Parse(profile.UserId));
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
@@ -116,7 +121,7 @@ namespace Emby.Dlna.ContentDirectory
|
||||
|
||||
if (!string.IsNullOrEmpty(userId))
|
||||
{
|
||||
var user = _userManager.GetUserById(userId);
|
||||
var user = _userManager.GetUserById(Guid.Parse(userId));
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Emby.Dlna.Common;
|
||||
using Emby.Dlna.Service;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
@@ -44,7 +47,6 @@ namespace Emby.Dlna.ContentDirectory
|
||||
private const string NS_UPNP = "urn:schemas-upnp-org:metadata-1-0/upnp/";
|
||||
|
||||
private readonly int _systemUpdateId;
|
||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||
|
||||
private readonly DidlBuilder _didlBuilder;
|
||||
|
||||
@@ -58,7 +60,8 @@ namespace Emby.Dlna.ContentDirectory
|
||||
string accessToken,
|
||||
IImageProcessor imageProcessor,
|
||||
IUserDataManager userDataManager,
|
||||
User user, int systemUpdateId,
|
||||
User user,
|
||||
int systemUpdateId,
|
||||
IServerConfigurationManager config,
|
||||
ILocalizationManager localization,
|
||||
IMediaSourceManager mediaSourceManager,
|
||||
@@ -76,117 +79,132 @@ namespace Emby.Dlna.ContentDirectory
|
||||
_profile = profile;
|
||||
_config = config;
|
||||
|
||||
_didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, _logger, 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)
|
||||
/// <inheritdoc />
|
||||
protected override void WriteResult(string methodName, IDictionary<string, string> methodParams, XmlWriter xmlWriter)
|
||||
{
|
||||
var deviceId = "test";
|
||||
|
||||
var user = _user;
|
||||
const string DeviceId = "test";
|
||||
|
||||
if (string.Equals(methodName, "GetSearchCapabilities", StringComparison.OrdinalIgnoreCase))
|
||||
return HandleGetSearchCapabilities();
|
||||
{
|
||||
HandleGetSearchCapabilities(xmlWriter);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(methodName, "GetSortCapabilities", StringComparison.OrdinalIgnoreCase))
|
||||
return HandleGetSortCapabilities();
|
||||
{
|
||||
HandleGetSortCapabilities(xmlWriter);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(methodName, "GetSortExtensionCapabilities", StringComparison.OrdinalIgnoreCase))
|
||||
return HandleGetSortExtensionCapabilities();
|
||||
{
|
||||
HandleGetSortExtensionCapabilities(xmlWriter);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(methodName, "GetSystemUpdateID", StringComparison.OrdinalIgnoreCase))
|
||||
return HandleGetSystemUpdateID();
|
||||
{
|
||||
HandleGetSystemUpdateID(xmlWriter);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(methodName, "Browse", StringComparison.OrdinalIgnoreCase))
|
||||
return HandleBrowse(methodParams, user, deviceId);
|
||||
{
|
||||
HandleBrowse(xmlWriter, methodParams, DeviceId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(methodName, "X_GetFeatureList", StringComparison.OrdinalIgnoreCase))
|
||||
return HandleXGetFeatureList();
|
||||
{
|
||||
HandleXGetFeatureList(xmlWriter);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(methodName, "GetFeatureList", StringComparison.OrdinalIgnoreCase))
|
||||
return HandleGetFeatureList();
|
||||
{
|
||||
HandleGetFeatureList(xmlWriter);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(methodName, "X_SetBookmark", StringComparison.OrdinalIgnoreCase))
|
||||
return HandleXSetBookmark(methodParams, user);
|
||||
{
|
||||
HandleXSetBookmark(methodParams);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(methodName, "Search", StringComparison.OrdinalIgnoreCase))
|
||||
return HandleSearch(methodParams, user, deviceId);
|
||||
{
|
||||
HandleSearch(xmlWriter, methodParams, DeviceId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(methodName, "X_BrowseByLetter", StringComparison.OrdinalIgnoreCase))
|
||||
return HandleX_BrowseByLetter(methodParams, user, deviceId);
|
||||
{
|
||||
HandleXBrowseByLetter(xmlWriter, methodParams, DeviceId);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
|
||||
}
|
||||
|
||||
private IEnumerable<KeyValuePair<string, string>> HandleXSetBookmark(IDictionary<string, string> sparams, User user)
|
||||
private void HandleXSetBookmark(IDictionary<string, string> sparams)
|
||||
{
|
||||
var id = sparams["ObjectID"];
|
||||
|
||||
var serverItem = GetItemFromObjectId(id, user);
|
||||
var serverItem = GetItemFromObjectId(id, _user);
|
||||
|
||||
var item = serverItem.Item;
|
||||
|
||||
var newbookmark = int.Parse(sparams["PosSecond"], _usCulture);
|
||||
var newbookmark = int.Parse(sparams["PosSecond"], CultureInfo.InvariantCulture);
|
||||
|
||||
var userdata = _userDataManager.GetUserData(user, item);
|
||||
var userdata = _userDataManager.GetUserData(_user, item);
|
||||
|
||||
userdata.PlaybackPositionTicks = TimeSpan.FromSeconds(newbookmark).Ticks;
|
||||
|
||||
_userDataManager.SaveUserData(user, item, userdata, UserDataSaveReason.TogglePlayed,
|
||||
_userDataManager.SaveUserData(_user, item, userdata, UserDataSaveReason.TogglePlayed,
|
||||
CancellationToken.None);
|
||||
|
||||
return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private IEnumerable<KeyValuePair<string, string>> HandleGetSearchCapabilities()
|
||||
private void HandleGetSearchCapabilities(XmlWriter xmlWriter)
|
||||
{
|
||||
return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ "SearchCaps", "res@resolution,res@size,res@duration,dc:title,dc:creator,upnp:actor,upnp:artist,upnp:genre,upnp:album,dc:date,upnp:class,@id,@refID,@protocolInfo,upnp:author,dc:description,pv:avKeywords" }
|
||||
};
|
||||
xmlWriter.WriteElementString(
|
||||
"SearchCaps",
|
||||
"res@resolution,res@size,res@duration,dc:title,dc:creator,upnp:actor,upnp:artist,upnp:genre,upnp:album,dc:date,upnp:class,@id,@refID,@protocolInfo,upnp:author,dc:description,pv:avKeywords");
|
||||
}
|
||||
|
||||
private IEnumerable<KeyValuePair<string, string>> HandleGetSortCapabilities()
|
||||
private void HandleGetSortCapabilities(XmlWriter xmlWriter)
|
||||
{
|
||||
return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ "SortCaps", "res@duration,res@size,res@bitrate,dc:date,dc:title,dc:size,upnp:album,upnp:artist,upnp:albumArtist,upnp:episodeNumber,upnp:genre,upnp:originalTrackNumber,upnp:rating" }
|
||||
};
|
||||
xmlWriter.WriteElementString(
|
||||
"SortCaps",
|
||||
"res@duration,res@size,res@bitrate,dc:date,dc:title,dc:size,upnp:album,upnp:artist,upnp:albumArtist,upnp:episodeNumber,upnp:genre,upnp:originalTrackNumber,upnp:rating");
|
||||
}
|
||||
|
||||
private IEnumerable<KeyValuePair<string, string>> HandleGetSortExtensionCapabilities()
|
||||
private void HandleGetSortExtensionCapabilities(XmlWriter xmlWriter)
|
||||
{
|
||||
return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ "SortExtensionCaps", "res@duration,res@size,res@bitrate,dc:date,dc:title,dc:size,upnp:album,upnp:artist,upnp:albumArtist,upnp:episodeNumber,upnp:genre,upnp:originalTrackNumber,upnp:rating" }
|
||||
};
|
||||
xmlWriter.WriteElementString(
|
||||
"SortExtensionCaps",
|
||||
"res@duration,res@size,res@bitrate,dc:date,dc:title,dc:size,upnp:album,upnp:artist,upnp:albumArtist,upnp:episodeNumber,upnp:genre,upnp:originalTrackNumber,upnp:rating");
|
||||
}
|
||||
|
||||
private IEnumerable<KeyValuePair<string, string>> HandleGetSystemUpdateID()
|
||||
private void HandleGetSystemUpdateID(XmlWriter xmlWriter)
|
||||
{
|
||||
var headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
headers.Add("Id", _systemUpdateId.ToString(_usCulture));
|
||||
return headers;
|
||||
xmlWriter.WriteElementString("Id", _systemUpdateId.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
private IEnumerable<KeyValuePair<string, string>> HandleGetFeatureList()
|
||||
private void HandleGetFeatureList(XmlWriter xmlWriter)
|
||||
{
|
||||
return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ "FeatureList", GetFeatureListXml() }
|
||||
};
|
||||
xmlWriter.WriteElementString("FeatureList", WriteFeatureListXml());
|
||||
}
|
||||
|
||||
private IEnumerable<KeyValuePair<string, string>> HandleXGetFeatureList()
|
||||
{
|
||||
return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ "FeatureList", GetFeatureListXml() }
|
||||
};
|
||||
}
|
||||
private void HandleXGetFeatureList(XmlWriter xmlWriter)
|
||||
=> HandleGetFeatureList(xmlWriter);
|
||||
|
||||
private string GetFeatureListXml()
|
||||
private string WriteFeatureListXml()
|
||||
{
|
||||
// TODO: clean this up
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
@@ -213,7 +231,7 @@ namespace Emby.Dlna.ContentDirectory
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private IEnumerable<KeyValuePair<string, string>> HandleBrowse(IDictionary<string, string> sparams, User user, string deviceId)
|
||||
private void HandleBrowse(XmlWriter xmlWriter, IDictionary<string, string> sparams, string deviceId)
|
||||
{
|
||||
var id = sparams["ObjectID"];
|
||||
var flag = sparams["BrowseFlag"];
|
||||
@@ -237,101 +255,95 @@ namespace Emby.Dlna.ContentDirectory
|
||||
start = startVal;
|
||||
}
|
||||
|
||||
var settings = new XmlWriterSettings
|
||||
{
|
||||
Encoding = Encoding.UTF8,
|
||||
CloseOutput = false,
|
||||
OmitXmlDeclaration = true,
|
||||
ConformanceLevel = ConformanceLevel.Fragment
|
||||
};
|
||||
|
||||
StringWriter builder = new StringWriterWithEncoding(Encoding.UTF8);
|
||||
|
||||
int totalCount;
|
||||
|
||||
var dlnaOptions = _config.GetDlnaConfiguration();
|
||||
|
||||
using (var writer = XmlWriter.Create(builder, settings))
|
||||
using (StringWriter builder = new StringWriterWithEncoding(Encoding.UTF8))
|
||||
{
|
||||
//writer.WriteStartDocument();
|
||||
|
||||
writer.WriteStartElement(string.Empty, "DIDL-Lite", NS_DIDL);
|
||||
|
||||
writer.WriteAttributeString("xmlns", "dc", null, NS_DC);
|
||||
writer.WriteAttributeString("xmlns", "dlna", null, NS_DLNA);
|
||||
writer.WriteAttributeString("xmlns", "upnp", null, NS_UPNP);
|
||||
//didl.SetAttribute("xmlns:sec", NS_SEC);
|
||||
|
||||
DidlBuilder.WriteXmlRootAttributes(_profile, writer);
|
||||
|
||||
var serverItem = GetItemFromObjectId(id, user);
|
||||
var item = serverItem.Item;
|
||||
|
||||
if (string.Equals(flag, "BrowseMetadata"))
|
||||
var settings = new XmlWriterSettings()
|
||||
{
|
||||
totalCount = 1;
|
||||
Encoding = Encoding.UTF8,
|
||||
CloseOutput = false,
|
||||
OmitXmlDeclaration = true,
|
||||
ConformanceLevel = ConformanceLevel.Fragment
|
||||
};
|
||||
|
||||
if (item.IsDisplayedAsFolder || serverItem.StubType.HasValue)
|
||||
{
|
||||
var childrenResult = GetUserItems(item, serverItem.StubType, user, sortCriteria, start, requestedCount);
|
||||
|
||||
_didlBuilder.WriteFolderElement(writer, item, serverItem.StubType, null, childrenResult.TotalRecordCount, filter, id);
|
||||
}
|
||||
else
|
||||
{
|
||||
_didlBuilder.WriteItemElement(dlnaOptions, writer, item, user, null, null, deviceId, filter);
|
||||
}
|
||||
|
||||
provided++;
|
||||
}
|
||||
else
|
||||
using (var writer = XmlWriter.Create(builder, settings))
|
||||
{
|
||||
var childrenResult = GetUserItems(item, serverItem.StubType, user, sortCriteria, start, requestedCount);
|
||||
totalCount = childrenResult.TotalRecordCount;
|
||||
writer.WriteStartElement(string.Empty, "DIDL-Lite", NS_DIDL);
|
||||
|
||||
provided = childrenResult.Items.Count;
|
||||
writer.WriteAttributeString("xmlns", "dc", null, NS_DC);
|
||||
writer.WriteAttributeString("xmlns", "dlna", null, NS_DLNA);
|
||||
writer.WriteAttributeString("xmlns", "upnp", null, NS_UPNP);
|
||||
|
||||
foreach (var i in childrenResult.Items)
|
||||
DidlBuilder.WriteXmlRootAttributes(_profile, writer);
|
||||
|
||||
var serverItem = GetItemFromObjectId(id, _user);
|
||||
var item = serverItem.Item;
|
||||
|
||||
|
||||
if (string.Equals(flag, "BrowseMetadata", StringComparison.Ordinal))
|
||||
{
|
||||
var childItem = i.Item;
|
||||
var displayStubType = i.StubType;
|
||||
totalCount = 1;
|
||||
|
||||
if (childItem.IsDisplayedAsFolder || displayStubType.HasValue)
|
||||
if (item.IsDisplayedAsFolder || serverItem.StubType.HasValue)
|
||||
{
|
||||
var childCount = (GetUserItems(childItem, displayStubType, user, sortCriteria, null, 0))
|
||||
.TotalRecordCount;
|
||||
var childrenResult = GetUserItems(item, serverItem.StubType, _user, sortCriteria, start, requestedCount);
|
||||
|
||||
_didlBuilder.WriteFolderElement(writer, childItem, displayStubType, item, childCount, filter);
|
||||
_didlBuilder.WriteFolderElement(writer, item, serverItem.StubType, null, childrenResult.TotalRecordCount, filter, id);
|
||||
}
|
||||
else
|
||||
{
|
||||
_didlBuilder.WriteItemElement(dlnaOptions, writer, childItem, user, item, serverItem.StubType, deviceId, filter);
|
||||
var dlnaOptions = _config.GetDlnaConfiguration();
|
||||
_didlBuilder.WriteItemElement(dlnaOptions, writer, item, _user, null, null, deviceId, filter);
|
||||
}
|
||||
|
||||
provided++;
|
||||
}
|
||||
else
|
||||
{
|
||||
var childrenResult = GetUserItems(item, serverItem.StubType, _user, sortCriteria, start, requestedCount);
|
||||
totalCount = childrenResult.TotalRecordCount;
|
||||
|
||||
provided = childrenResult.Items.Count;
|
||||
|
||||
var dlnaOptions = _config.GetDlnaConfiguration();
|
||||
foreach (var i in childrenResult.Items)
|
||||
{
|
||||
var childItem = i.Item;
|
||||
var displayStubType = i.StubType;
|
||||
|
||||
if (childItem.IsDisplayedAsFolder || displayStubType.HasValue)
|
||||
{
|
||||
var childCount = GetUserItems(childItem, displayStubType, _user, sortCriteria, null, 0)
|
||||
.TotalRecordCount;
|
||||
|
||||
_didlBuilder.WriteFolderElement(writer, childItem, displayStubType, item, childCount, filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
_didlBuilder.WriteItemElement(dlnaOptions, writer, childItem, _user, item, serverItem.StubType, deviceId, filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writer.WriteFullEndElement();
|
||||
}
|
||||
|
||||
writer.WriteFullEndElement();
|
||||
//writer.WriteEndDocument();
|
||||
xmlWriter.WriteElementString("Result", builder.ToString());
|
||||
}
|
||||
|
||||
var resXML = builder.ToString();
|
||||
|
||||
return new[]
|
||||
{
|
||||
new KeyValuePair<string,string>("Result", resXML),
|
||||
new KeyValuePair<string,string>("NumberReturned", provided.ToString(_usCulture)),
|
||||
new KeyValuePair<string,string>("TotalMatches", totalCount.ToString(_usCulture)),
|
||||
new KeyValuePair<string,string>("UpdateID", _systemUpdateId.ToString(_usCulture))
|
||||
};
|
||||
xmlWriter.WriteElementString("NumberReturned", provided.ToString(CultureInfo.InvariantCulture));
|
||||
xmlWriter.WriteElementString("TotalMatches", totalCount.ToString(CultureInfo.InvariantCulture));
|
||||
xmlWriter.WriteElementString("UpdateID", _systemUpdateId.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
private IEnumerable<KeyValuePair<string, string>> HandleX_BrowseByLetter(IDictionary<string, string> sparams, User user, string deviceId)
|
||||
private void HandleXBrowseByLetter(XmlWriter xmlWriter, IDictionary<string, string> sparams, string deviceId)
|
||||
{
|
||||
// TODO: Implement this method
|
||||
return HandleSearch(sparams, user, deviceId);
|
||||
HandleSearch(xmlWriter, sparams, deviceId);
|
||||
}
|
||||
|
||||
private IEnumerable<KeyValuePair<string, string>> HandleSearch(IDictionary<string, string> sparams, User user, string deviceId)
|
||||
private void HandleSearch(XmlWriter xmlWriter, IDictionary<string, string> sparams, string deviceId)
|
||||
{
|
||||
var searchCriteria = new SearchCriteria(GetValueOrDefault(sparams, "SearchCriteria", ""));
|
||||
var sortCriteria = new SortCriteria(GetValueOrDefault(sparams, "SortCriteria", ""));
|
||||
@@ -354,99 +366,86 @@ namespace Emby.Dlna.ContentDirectory
|
||||
start = startVal;
|
||||
}
|
||||
|
||||
var settings = new XmlWriterSettings
|
||||
QueryResult<BaseItem> childrenResult;
|
||||
|
||||
using (StringWriter builder = new StringWriterWithEncoding(Encoding.UTF8))
|
||||
{
|
||||
Encoding = Encoding.UTF8,
|
||||
CloseOutput = false,
|
||||
OmitXmlDeclaration = true,
|
||||
ConformanceLevel = ConformanceLevel.Fragment
|
||||
};
|
||||
|
||||
StringWriter builder = new StringWriterWithEncoding(Encoding.UTF8);
|
||||
int totalCount = 0;
|
||||
int provided = 0;
|
||||
|
||||
using (var writer = XmlWriter.Create(builder, settings))
|
||||
{
|
||||
//writer.WriteStartDocument();
|
||||
|
||||
writer.WriteStartElement(string.Empty, "DIDL-Lite", NS_DIDL);
|
||||
|
||||
writer.WriteAttributeString("xmlns", "dc", null, NS_DC);
|
||||
writer.WriteAttributeString("xmlns", "dlna", null, NS_DLNA);
|
||||
writer.WriteAttributeString("xmlns", "upnp", null, NS_UPNP);
|
||||
//didl.SetAttribute("xmlns:sec", NS_SEC);
|
||||
|
||||
DidlBuilder.WriteXmlRootAttributes(_profile, writer);
|
||||
|
||||
var serverItem = GetItemFromObjectId(sparams["ContainerID"], user);
|
||||
|
||||
var item = serverItem.Item;
|
||||
|
||||
var childrenResult = (GetChildrenSorted(item, user, searchCriteria, sortCriteria, start, requestedCount));
|
||||
|
||||
totalCount = childrenResult.TotalRecordCount;
|
||||
|
||||
provided = childrenResult.Items.Count;
|
||||
|
||||
var dlnaOptions = _config.GetDlnaConfiguration();
|
||||
|
||||
foreach (var i in childrenResult.Items)
|
||||
var settings = new XmlWriterSettings()
|
||||
{
|
||||
if (i.IsDisplayedAsFolder)
|
||||
{
|
||||
var childCount = (GetChildrenSorted(i, user, searchCriteria, sortCriteria, null, 0))
|
||||
.TotalRecordCount;
|
||||
Encoding = Encoding.UTF8,
|
||||
CloseOutput = false,
|
||||
OmitXmlDeclaration = true,
|
||||
ConformanceLevel = ConformanceLevel.Fragment
|
||||
};
|
||||
|
||||
_didlBuilder.WriteFolderElement(writer, i, null, item, childCount, filter);
|
||||
}
|
||||
else
|
||||
using (var writer = XmlWriter.Create(builder, settings))
|
||||
{
|
||||
writer.WriteStartElement(string.Empty, "DIDL-Lite", NS_DIDL);
|
||||
|
||||
writer.WriteAttributeString("xmlns", "dc", null, NS_DC);
|
||||
writer.WriteAttributeString("xmlns", "dlna", null, NS_DLNA);
|
||||
writer.WriteAttributeString("xmlns", "upnp", null, NS_UPNP);
|
||||
|
||||
DidlBuilder.WriteXmlRootAttributes(_profile, writer);
|
||||
|
||||
var serverItem = GetItemFromObjectId(sparams["ContainerID"], _user);
|
||||
|
||||
var item = serverItem.Item;
|
||||
|
||||
childrenResult = GetChildrenSorted(item, _user, searchCriteria, sortCriteria, start, requestedCount);
|
||||
|
||||
var dlnaOptions = _config.GetDlnaConfiguration();
|
||||
|
||||
foreach (var i in childrenResult.Items)
|
||||
{
|
||||
_didlBuilder.WriteItemElement(dlnaOptions, writer, i, user, item, serverItem.StubType, deviceId, filter);
|
||||
if (i.IsDisplayedAsFolder)
|
||||
{
|
||||
var childCount = GetChildrenSorted(i, _user, searchCriteria, sortCriteria, null, 0)
|
||||
.TotalRecordCount;
|
||||
|
||||
_didlBuilder.WriteFolderElement(writer, i, null, item, childCount, filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
_didlBuilder.WriteItemElement(dlnaOptions, writer, i, _user, item, serverItem.StubType, deviceId, filter);
|
||||
}
|
||||
}
|
||||
|
||||
writer.WriteFullEndElement();
|
||||
}
|
||||
|
||||
writer.WriteFullEndElement();
|
||||
//writer.WriteEndDocument();
|
||||
xmlWriter.WriteElementString("Result", builder.ToString());
|
||||
}
|
||||
|
||||
var resXML = builder.ToString();
|
||||
|
||||
return new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new KeyValuePair<string,string>("Result", resXML),
|
||||
new KeyValuePair<string,string>("NumberReturned", provided.ToString(_usCulture)),
|
||||
new KeyValuePair<string,string>("TotalMatches", totalCount.ToString(_usCulture)),
|
||||
new KeyValuePair<string,string>("UpdateID", _systemUpdateId.ToString(_usCulture))
|
||||
};
|
||||
xmlWriter.WriteElementString("NumberReturned", childrenResult.Items.Count.ToString(CultureInfo.InvariantCulture));
|
||||
xmlWriter.WriteElementString("TotalMatches", childrenResult.TotalRecordCount.ToString(CultureInfo.InvariantCulture));
|
||||
xmlWriter.WriteElementString("UpdateID", _systemUpdateId.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
private QueryResult<BaseItem> GetChildrenSorted(BaseItem item, User user, SearchCriteria search, SortCriteria sort, int? startIndex, int? limit)
|
||||
{
|
||||
var folder = (Folder)item;
|
||||
|
||||
var sortOrders = new List<string>();
|
||||
if (!folder.IsPreSorted)
|
||||
{
|
||||
sortOrders.Add(ItemSortBy.SortName);
|
||||
}
|
||||
var sortOrders = folder.IsPreSorted
|
||||
? Array.Empty<(string, SortOrder)>()
|
||||
: new[] { (ItemSortBy.SortName, sort.SortOrder) };
|
||||
|
||||
var mediaTypes = new List<string>();
|
||||
string[] mediaTypes = Array.Empty<string>();
|
||||
bool? isFolder = null;
|
||||
|
||||
if (search.SearchType == SearchType.Audio)
|
||||
{
|
||||
mediaTypes.Add(MediaType.Audio);
|
||||
mediaTypes = new[] { MediaType.Audio };
|
||||
isFolder = false;
|
||||
}
|
||||
else if (search.SearchType == SearchType.Video)
|
||||
{
|
||||
mediaTypes.Add(MediaType.Video);
|
||||
mediaTypes = new[] { MediaType.Video };
|
||||
isFolder = false;
|
||||
}
|
||||
else if (search.SearchType == SearchType.Image)
|
||||
{
|
||||
mediaTypes.Add(MediaType.Photo);
|
||||
mediaTypes = new[] { MediaType.Photo };
|
||||
isFolder = false;
|
||||
}
|
||||
else if (search.SearchType == SearchType.Playlist)
|
||||
@@ -464,13 +463,13 @@ namespace Emby.Dlna.ContentDirectory
|
||||
{
|
||||
Limit = limit,
|
||||
StartIndex = startIndex,
|
||||
OrderBy = sortOrders.Select(i => new ValueTuple<string, SortOrder>(i, sort.SortOrder)).ToArray(),
|
||||
OrderBy = sortOrders,
|
||||
User = user,
|
||||
Recursive = true,
|
||||
IsMissing = false,
|
||||
ExcludeItemTypes = new[] { typeof(Book).Name },
|
||||
IsFolder = isFolder,
|
||||
MediaTypes = mediaTypes.ToArray(),
|
||||
MediaTypes = mediaTypes,
|
||||
DtoOptions = GetDtoOptions()
|
||||
});
|
||||
}
|
||||
@@ -771,11 +770,11 @@ namespace Emby.Dlna.ContentDirectory
|
||||
})
|
||||
.ToArray();
|
||||
|
||||
return new QueryResult<ServerItem>
|
||||
return ApplyPaging(new QueryResult<ServerItem>
|
||||
{
|
||||
Items = folders,
|
||||
TotalRecordCount = folders.Length
|
||||
};
|
||||
}, startIndex, limit);
|
||||
}
|
||||
|
||||
private QueryResult<ServerItem> GetTvFolders(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit)
|
||||
@@ -872,10 +871,10 @@ namespace Emby.Dlna.ContentDirectory
|
||||
query.Parent = parent;
|
||||
query.SetUser(user);
|
||||
|
||||
query.OrderBy = new ValueTuple<string, SortOrder>[]
|
||||
query.OrderBy = new[]
|
||||
{
|
||||
new ValueTuple<string, SortOrder> (ItemSortBy.DatePlayed, SortOrder.Descending),
|
||||
new ValueTuple<string, SortOrder> (ItemSortBy.SortName, SortOrder.Ascending)
|
||||
(ItemSortBy.DatePlayed, SortOrder.Descending),
|
||||
(ItemSortBy.SortName, SortOrder.Ascending)
|
||||
};
|
||||
|
||||
query.IsResumable = true;
|
||||
@@ -1121,7 +1120,7 @@ namespace Emby.Dlna.ContentDirectory
|
||||
|
||||
private QueryResult<ServerItem> GetMusicLatest(BaseItem parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.OrderBy = new ValueTuple<string, SortOrder>[] { };
|
||||
query.OrderBy = Array.Empty<(string, SortOrder)>();
|
||||
|
||||
var items = _userViewManager.GetLatestItems(new LatestItemsQuery
|
||||
{
|
||||
@@ -1138,7 +1137,7 @@ namespace Emby.Dlna.ContentDirectory
|
||||
|
||||
private QueryResult<ServerItem> GetNextUp(BaseItem parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.OrderBy = new ValueTuple<string, SortOrder>[] { };
|
||||
query.OrderBy = Array.Empty<(string, SortOrder)>();
|
||||
|
||||
var result = _tvSeriesManager.GetNextUp(new NextUpQuery
|
||||
{
|
||||
@@ -1153,7 +1152,7 @@ namespace Emby.Dlna.ContentDirectory
|
||||
|
||||
private QueryResult<ServerItem> GetTvLatest(BaseItem parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.OrderBy = new ValueTuple<string, SortOrder>[] { };
|
||||
query.OrderBy = Array.Empty<(string, SortOrder)>();
|
||||
|
||||
var items = _userViewManager.GetLatestItems(new LatestItemsQuery
|
||||
{
|
||||
@@ -1170,7 +1169,7 @@ namespace Emby.Dlna.ContentDirectory
|
||||
|
||||
private QueryResult<ServerItem> GetMovieLatest(BaseItem parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.OrderBy = new ValueTuple<string, SortOrder>[] { };
|
||||
query.OrderBy = Array.Empty<(string, SortOrder)>();
|
||||
|
||||
var items = _userViewManager.GetLatestItems(new LatestItemsQuery
|
||||
{
|
||||
@@ -1274,13 +1273,14 @@ namespace Emby.Dlna.ContentDirectory
|
||||
|
||||
private void SetSorting(InternalItemsQuery query, SortCriteria sort, bool isPreSorted)
|
||||
{
|
||||
var sortOrders = new List<string>();
|
||||
if (!isPreSorted)
|
||||
if (isPreSorted)
|
||||
{
|
||||
sortOrders.Add(ItemSortBy.SortName);
|
||||
query.OrderBy = Array.Empty<(string, SortOrder)>();
|
||||
}
|
||||
else
|
||||
{
|
||||
query.OrderBy = new[] { (ItemSortBy.SortName, sort.SortOrder) };
|
||||
}
|
||||
|
||||
query.OrderBy = sortOrders.Select(i => new ValueTuple<string, SortOrder>(i, sort.SortOrder)).ToArray();
|
||||
}
|
||||
|
||||
private QueryResult<ServerItem> ApplyPaging(QueryResult<ServerItem> result, int? startIndex, int? limit)
|
||||
@@ -1303,11 +1303,11 @@ namespace Emby.Dlna.ContentDirectory
|
||||
StubType? stubType = null;
|
||||
|
||||
// After using PlayTo, MediaMonkey sends a request to the server trying to get item info
|
||||
const string paramsSrch = "Params=";
|
||||
var paramsIndex = id.IndexOf(paramsSrch, StringComparison.OrdinalIgnoreCase);
|
||||
const string ParamsSrch = "Params=";
|
||||
var paramsIndex = id.IndexOf(ParamsSrch, StringComparison.OrdinalIgnoreCase);
|
||||
if (paramsIndex != -1)
|
||||
{
|
||||
id = id.Substring(paramsIndex + paramsSrch.Length);
|
||||
id = id.Substring(paramsIndex + ParamsSrch.Length);
|
||||
|
||||
var parts = id.Split(';');
|
||||
id = parts[23];
|
||||
@@ -1335,7 +1335,7 @@ namespace Emby.Dlna.ContentDirectory
|
||||
};
|
||||
}
|
||||
|
||||
_logger.LogError("Error parsing item Id: {id}. Returning user root folder.", id);
|
||||
Logger.LogError("Error parsing item Id: {id}. Returning user root folder.", id);
|
||||
|
||||
return new ServerItem(_libraryManager.GetUserRootFolder());
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Emby.Dlna.Common;
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System.IO;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Emby.Dlna
|
||||
{
|
||||
public class ControlResponse
|
||||
{
|
||||
public ControlResponse()
|
||||
{
|
||||
Headers = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
public IDictionary<string, string> Headers { get; set; }
|
||||
|
||||
public string Xml { get; set; }
|
||||
|
||||
public bool IsSuccessful { get; set; }
|
||||
|
||||
public ControlResponse()
|
||||
{
|
||||
Headers = new Dictionary<string, string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
@@ -18,7 +21,6 @@ using MediaBrowser.Controller.Playlists;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
using MediaBrowser.Model.Drawing;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.Net;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -632,7 +634,7 @@ namespace Emby.Dlna.Didl
|
||||
{
|
||||
if (item.PremiereDate.HasValue)
|
||||
{
|
||||
AddValue(writer, "dc", "date", item.PremiereDate.Value.ToString("o"), NS_DC);
|
||||
AddValue(writer, "dc", "date", item.PremiereDate.Value.ToString("o", CultureInfo.InvariantCulture), NS_DC);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
@@ -16,7 +19,7 @@ namespace Emby.Dlna.Didl
|
||||
|
||||
public Filter(string filter)
|
||||
{
|
||||
_all = StringHelper.EqualsIgnoreCase(filter, "*");
|
||||
_all = string.Equals(filter, "*", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
_fields = (filter ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
@@ -385,7 +388,7 @@ namespace Emby.Dlna
|
||||
{
|
||||
Directory.CreateDirectory(systemProfilesPath);
|
||||
|
||||
using (var fileStream = _fileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
|
||||
using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
|
||||
{
|
||||
await stream.CopyToAsync(fileStream);
|
||||
}
|
||||
|
||||
@@ -12,9 +12,22 @@
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release'" >true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Code Analyzers-->
|
||||
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
|
||||
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
|
||||
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Emby.Dlna
|
||||
{
|
||||
public class EventSubscriptionResponse
|
||||
{
|
||||
public string Content { get; set; }
|
||||
public string ContentType { get; set; }
|
||||
|
||||
public Dictionary<string, string> Headers { get; set; }
|
||||
|
||||
public EventSubscriptionResponse()
|
||||
{
|
||||
Headers = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
public string Content { get; set; }
|
||||
|
||||
public string ContentType { get; set; }
|
||||
|
||||
public Dictionary<string, string> Headers { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
@@ -29,25 +33,15 @@ namespace Emby.Dlna.Eventing
|
||||
{
|
||||
var subscription = GetSubscription(subscriptionId, false);
|
||||
|
||||
int timeoutSeconds;
|
||||
subscription.TimeoutSeconds = ParseTimeout(requestedTimeoutString) ?? 300;
|
||||
int timeoutSeconds = subscription.TimeoutSeconds;
|
||||
subscription.SubscriptionTime = DateTime.UtcNow;
|
||||
|
||||
// Remove logging for now because some devices are sending this very frequently
|
||||
// TODO re-enable with dlna debug logging setting
|
||||
//_logger.LogDebug("Renewing event subscription for {0} with timeout of {1} to {2}",
|
||||
// subscription.NotificationType,
|
||||
// timeout,
|
||||
// subscription.CallbackUrl);
|
||||
|
||||
if (subscription != null)
|
||||
{
|
||||
subscription.TimeoutSeconds = ParseTimeout(requestedTimeoutString) ?? 300;
|
||||
timeoutSeconds = subscription.TimeoutSeconds;
|
||||
subscription.SubscriptionTime = DateTime.UtcNow;
|
||||
}
|
||||
else
|
||||
{
|
||||
timeoutSeconds = 300;
|
||||
}
|
||||
_logger.LogDebug(
|
||||
"Renewing event subscription for {0} with timeout of {1} to {2}",
|
||||
subscription.NotificationType,
|
||||
timeoutSeconds,
|
||||
subscription.CallbackUrl);
|
||||
|
||||
return GetEventSubscriptionResponse(subscriptionId, requestedTimeoutString, timeoutSeconds);
|
||||
}
|
||||
@@ -57,12 +51,10 @@ namespace Emby.Dlna.Eventing
|
||||
var timeout = ParseTimeout(requestedTimeoutString) ?? 300;
|
||||
var id = "uuid:" + Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
|
||||
|
||||
// Remove logging for now because some devices are sending this very frequently
|
||||
// TODO re-enable with dlna debug logging setting
|
||||
//_logger.LogDebug("Creating event subscription for {0} with timeout of {1} to {2}",
|
||||
// notificationType,
|
||||
// timeout,
|
||||
// callbackUrl);
|
||||
_logger.LogDebug("Creating event subscription for {0} with timeout of {1} to {2}",
|
||||
notificationType,
|
||||
timeout,
|
||||
callbackUrl);
|
||||
|
||||
_subscriptions.TryAdd(id, new EventSubscription
|
||||
{
|
||||
@@ -176,7 +168,7 @@ namespace Emby.Dlna.Eventing
|
||||
|
||||
try
|
||||
{
|
||||
using (await _httpClient.SendAsync(options, "NOTIFY").ConfigureAwait(false))
|
||||
using (await _httpClient.SendAsync(options, new HttpMethod("NOTIFY")).ConfigureAwait(false))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System;
|
||||
|
||||
namespace Emby.Dlna.Eventing
|
||||
@@ -13,6 +16,8 @@ namespace Emby.Dlna.Eventing
|
||||
|
||||
public long TriggerCount { get; set; }
|
||||
|
||||
public bool IsExpired => SubscriptionTime.AddSeconds(TimeoutSeconds) >= DateTime.UtcNow;
|
||||
|
||||
public void IncrementTriggerCount()
|
||||
{
|
||||
if (TriggerCount == long.MaxValue)
|
||||
@@ -22,7 +27,5 @@ namespace Emby.Dlna.Eventing
|
||||
|
||||
TriggerCount++;
|
||||
}
|
||||
|
||||
public bool IsExpired => SubscriptionTime.AddSeconds(TimeoutSeconds) >= DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
namespace Emby.Dlna
|
||||
{
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
namespace Emby.Dlna
|
||||
{
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
namespace Emby.Dlna
|
||||
{
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
namespace Emby.Dlna
|
||||
{
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Emby.Dlna
|
||||
{
|
||||
public interface IUpnpService
|
||||
@@ -13,6 +18,6 @@ namespace Emby.Dlna
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>ControlResponse.</returns>
|
||||
ControlResponse ProcessControlRequest(ControlRequest request);
|
||||
Task<ControlResponse> ProcessControlRequestAsync(ControlRequest request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System;
|
||||
using System.Net.Sockets;
|
||||
using System.Globalization;
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
using Emby.Dlna.Service;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
@@ -9,35 +13,33 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
||||
{
|
||||
public class ControlHandler : BaseControlHandler
|
||||
{
|
||||
protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams)
|
||||
{
|
||||
if (string.Equals(methodName, "IsAuthorized", StringComparison.OrdinalIgnoreCase))
|
||||
return HandleIsAuthorized();
|
||||
if (string.Equals(methodName, "IsValidated", StringComparison.OrdinalIgnoreCase))
|
||||
return HandleIsValidated();
|
||||
|
||||
throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
|
||||
}
|
||||
|
||||
private static IEnumerable<KeyValuePair<string, string>> HandleIsAuthorized()
|
||||
{
|
||||
return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ "Result", "1" }
|
||||
};
|
||||
}
|
||||
|
||||
private static IEnumerable<KeyValuePair<string, string>> HandleIsValidated()
|
||||
{
|
||||
return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ "Result", "1" }
|
||||
};
|
||||
}
|
||||
|
||||
public ControlHandler(IServerConfigurationManager config, ILogger logger)
|
||||
: base(config, logger)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void WriteResult(string methodName, IDictionary<string, string> methodParams, XmlWriter xmlWriter)
|
||||
{
|
||||
if (string.Equals(methodName, "IsAuthorized", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
HandleIsAuthorized(xmlWriter);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(methodName, "IsValidated", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
HandleIsValidated(xmlWriter);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
|
||||
}
|
||||
|
||||
private static void HandleIsAuthorized(XmlWriter xmlWriter)
|
||||
=> xmlWriter.WriteElementString("Result", "1");
|
||||
|
||||
private static void HandleIsValidated(XmlWriter xmlWriter)
|
||||
=> xmlWriter.WriteElementString("Result", "1");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Emby.Dlna.Service;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
@@ -15,17 +19,19 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
||||
_config = config;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string GetServiceXml()
|
||||
{
|
||||
return new MediaReceiverRegistrarXmlBuilder().GetXml();
|
||||
}
|
||||
|
||||
public ControlResponse ProcessControlRequest(ControlRequest request)
|
||||
/// <inheritdoc />
|
||||
public Task<ControlResponse> ProcessControlRequestAsync(ControlRequest request)
|
||||
{
|
||||
return new ControlHandler(
|
||||
_config,
|
||||
Logger)
|
||||
.ProcessControlRequest(request);
|
||||
.ProcessControlRequestAsync(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Emby.Dlna.Common;
|
||||
using Emby.Dlna.Service;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Emby.Dlna.Common;
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
@@ -221,7 +224,7 @@ namespace Emby.Dlna.PlayTo
|
||||
_logger.LogDebug("Setting mute");
|
||||
var value = mute ? 1 : 0;
|
||||
|
||||
await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType, value))
|
||||
await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType, value))
|
||||
.ConfigureAwait(false);
|
||||
|
||||
IsMuted = mute;
|
||||
@@ -251,7 +254,7 @@ namespace Emby.Dlna.PlayTo
|
||||
// Remote control will perform better
|
||||
Volume = value;
|
||||
|
||||
await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType, value))
|
||||
await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType, value))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@@ -270,7 +273,7 @@ namespace Emby.Dlna.PlayTo
|
||||
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).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, string.Format("{0:hh}:{0:mm}:{0:ss}", value), "REL_TIME"))
|
||||
.ConfigureAwait(false);
|
||||
|
||||
RestartTimer(true);
|
||||
@@ -302,7 +305,7 @@ namespace Emby.Dlna.PlayTo
|
||||
}
|
||||
|
||||
var post = avCommands.BuildPost(command, service.ServiceType, url, dictionary);
|
||||
await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header: header)
|
||||
await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header: header)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
await Task.Delay(50).ConfigureAwait(false);
|
||||
@@ -344,7 +347,7 @@ namespace Emby.Dlna.PlayTo
|
||||
throw new InvalidOperationException("Unable to find service");
|
||||
}
|
||||
|
||||
return new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1));
|
||||
return new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1));
|
||||
}
|
||||
|
||||
public async Task SetPlay(CancellationToken cancellationToken)
|
||||
@@ -368,7 +371,7 @@ namespace Emby.Dlna.PlayTo
|
||||
|
||||
var service = GetAvTransportService();
|
||||
|
||||
await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1))
|
||||
await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1))
|
||||
.ConfigureAwait(false);
|
||||
|
||||
RestartTimer(true);
|
||||
@@ -386,7 +389,7 @@ namespace Emby.Dlna.PlayTo
|
||||
|
||||
var service = GetAvTransportService();
|
||||
|
||||
await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1))
|
||||
await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1))
|
||||
.ConfigureAwait(false);
|
||||
|
||||
TransportState = TRANSPORTSTATE.PAUSED;
|
||||
@@ -513,7 +516,7 @@ namespace Emby.Dlna.PlayTo
|
||||
return;
|
||||
}
|
||||
|
||||
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), true)
|
||||
var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), true)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (result == null || result.Document == null)
|
||||
@@ -559,7 +562,7 @@ namespace Emby.Dlna.PlayTo
|
||||
return;
|
||||
}
|
||||
|
||||
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), true)
|
||||
var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), true)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (result == null || result.Document == null)
|
||||
@@ -586,7 +589,7 @@ namespace Emby.Dlna.PlayTo
|
||||
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).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType), false)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (result == null || result.Document == null)
|
||||
@@ -624,7 +627,7 @@ namespace Emby.Dlna.PlayTo
|
||||
|
||||
var rendererCommands = await GetRenderingProtocolAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), false)
|
||||
var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), false)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (result == null || result.Document == null)
|
||||
@@ -687,7 +690,7 @@ namespace Emby.Dlna.PlayTo
|
||||
|
||||
var rendererCommands = await GetRenderingProtocolAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), false)
|
||||
var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), false)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (result == null || result.Document == null)
|
||||
@@ -868,7 +871,7 @@ namespace Emby.Dlna.PlayTo
|
||||
|
||||
string url = NormalizeUrl(Properties.BaseUrl, avService.ScpdUrl);
|
||||
|
||||
var httpClient = new SsdpHttpClient(_httpClient, _config);
|
||||
var httpClient = new SsdpHttpClient(_httpClient);
|
||||
|
||||
var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
@@ -896,7 +899,7 @@ namespace Emby.Dlna.PlayTo
|
||||
|
||||
string url = NormalizeUrl(Properties.BaseUrl, avService.ScpdUrl);
|
||||
|
||||
var httpClient = new SsdpHttpClient(_httpClient, _config);
|
||||
var httpClient = new SsdpHttpClient(_httpClient);
|
||||
_logger.LogDebug("Dlna Device.GetRenderingProtocolAsync");
|
||||
var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
@@ -931,7 +934,7 @@ namespace Emby.Dlna.PlayTo
|
||||
|
||||
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);
|
||||
|
||||
var document = await ssdpHttpClient.GetDataAsync(url.ToString(), cancellationToken).ConfigureAwait(false);
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Emby.Dlna.Common;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
@@ -6,7 +9,6 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Emby.Dlna.Didl;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
@@ -21,7 +24,7 @@ using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Emby.Dlna.PlayTo
|
||||
{
|
||||
class PlayToManager : IDisposable
|
||||
public class PlayToManager : IDisposable
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly ISessionManager _sessionManager;
|
||||
@@ -64,10 +67,10 @@ namespace Emby.Dlna.PlayTo
|
||||
|
||||
public void Start()
|
||||
{
|
||||
_deviceDiscovery.DeviceDiscovered += _deviceDiscovery_DeviceDiscovered;
|
||||
_deviceDiscovery.DeviceDiscovered += OnDeviceDiscoveryDeviceDiscovered;
|
||||
}
|
||||
|
||||
async void _deviceDiscovery_DeviceDiscovered(object sender, GenericEventArgs<UpnpDeviceInfo> e)
|
||||
private async void OnDeviceDiscoveryDeviceDiscovered(object sender, GenericEventArgs<UpnpDeviceInfo> e)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
@@ -160,7 +163,7 @@ namespace Emby.Dlna.PlayTo
|
||||
uuid = location.GetMD5().ToString("N", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
var sessionInfo = _sessionManager.LogSessionActivity("DLNA", _appHost.ApplicationVersion, uuid, null, uri.OriginalString, null);
|
||||
var sessionInfo = _sessionManager.LogSessionActivity("DLNA", _appHost.ApplicationVersionString, uuid, null, uri.OriginalString, null);
|
||||
|
||||
var controller = sessionInfo.SessionControllers.OfType<PlayToController>().FirstOrDefault();
|
||||
|
||||
@@ -231,7 +234,7 @@ namespace Emby.Dlna.PlayTo
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_deviceDiscovery.DeviceDiscovered -= _deviceDiscovery_DeviceDiscovered;
|
||||
_deviceDiscovery.DeviceDiscovered -= OnDeviceDiscoveryDeviceDiscovered;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System;
|
||||
|
||||
namespace Emby.Dlna.PlayTo
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System;
|
||||
|
||||
namespace Emby.Dlna.PlayTo
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System;
|
||||
|
||||
namespace Emby.Dlna.PlayTo
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using MediaBrowser.Model.Dlna;
|
||||
|
||||
namespace Emby.Dlna.PlayTo
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Globalization;
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
using Emby.Dlna.Common;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
|
||||
namespace Emby.Dlna.PlayTo
|
||||
{
|
||||
@@ -19,12 +22,10 @@ namespace Emby.Dlna.PlayTo
|
||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
|
||||
public SsdpHttpClient(IHttpClient httpClient, IServerConfigurationManager config)
|
||||
public SsdpHttpClient(IHttpClient httpClient)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public async Task<XDocument> SendCommandAsync(
|
||||
@@ -64,7 +65,9 @@ namespace Emby.Dlna.PlayTo
|
||||
}
|
||||
|
||||
if (!serviceUrl.StartsWith("/"))
|
||||
{
|
||||
serviceUrl = "/" + serviceUrl;
|
||||
}
|
||||
|
||||
return baseUrl + serviceUrl;
|
||||
}
|
||||
@@ -90,7 +93,7 @@ namespace Emby.Dlna.PlayTo
|
||||
options.RequestHeaders["NT"] = "upnp:event";
|
||||
options.RequestHeaders["TIMEOUT"] = "Second-" + timeOut.ToString(_usCulture);
|
||||
|
||||
using (await _httpClient.SendAsync(options, "SUBSCRIBE").ConfigureAwait(false))
|
||||
using (await _httpClient.SendAsync(options, new HttpMethod("SUBSCRIBE")).ConfigureAwait(false))
|
||||
{
|
||||
|
||||
}
|
||||
@@ -110,7 +113,7 @@ namespace Emby.Dlna.PlayTo
|
||||
|
||||
options.RequestHeaders["FriendlyName.DLNA.ORG"] = FriendlyName;
|
||||
|
||||
using (var response = await _httpClient.SendAsync(options, "GET").ConfigureAwait(false))
|
||||
using (var response = await _httpClient.SendAsync(options, HttpMethod.Get).ConfigureAwait(false))
|
||||
using (var stream = response.Content)
|
||||
using (var reader = new StreamReader(stream, Encoding.UTF8))
|
||||
{
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
namespace Emby.Dlna.PlayTo
|
||||
{
|
||||
public enum TRANSPORTSTATE
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
using Emby.Dlna.Ssdp;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System;
|
||||
|
||||
namespace Emby.Dlna.PlayTo
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Emby.Dlna.PlayTo
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using System.Linq;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using MediaBrowser.Model.Dlna;
|
||||
|
||||
namespace Emby.Dlna.Profiles
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using MediaBrowser.Model.Dlna;
|
||||
|
||||
namespace Emby.Dlna.Profiles
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using MediaBrowser.Model.Dlna;
|
||||
|
||||
namespace Emby.Dlna.Profiles
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable SA1600
|
||||
|
||||
using MediaBrowser.Model.Dlna;
|
||||
|
||||
namespace Emby.Dlna.Profiles
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user