mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-12-06 06:36:25 +00:00
Compare commits
1293 Commits
feat/chrom
...
v4.4.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 266caa3f02 | |||
| ea98598399 | |||
| 83110374f8 | |||
| 1f16271354 | |||
| 0c387fc19a | |||
| 7d423bb049 | |||
| c3bebdec01 | |||
| d26934b602 | |||
| e16fdc1036 | |||
| 0008aa95c2 | |||
| a8d29b5b26 | |||
| 61a8b07f4b | |||
| d3ec0cab9b | |||
| 5e054e12f7 | |||
| e8896b7787 | |||
| 0cf7b1369b | |||
| 7428147100 | |||
| 88f3f7a9ae | |||
| 2ff507f641 | |||
| 3de751c880 | |||
| 9a9e43269d | |||
| 12276ed034 | |||
| 22b68f4dc7 | |||
| 80e928ee43 | |||
| bb3e57ff2a | |||
| 78247acba7 | |||
| e4f00d34bc | |||
| 81d4a13735 | |||
| 5d430f8ee8 | |||
| aba6c873df | |||
| d140a6e392 | |||
| f7603db588 | |||
| 87754ae928 | |||
| ecbf1f5db5 | |||
| 8ddf22d661 | |||
| 13df17544c | |||
| 39ce601344 | |||
| db6670f699 | |||
| bd7991942a | |||
| da594d6df1 | |||
| f6bb77a6a5 | |||
| ea979d9663 | |||
| 646df0f393 | |||
| d24d18ea8e | |||
| 9740a5d0d4 | |||
| 034a554bf4 | |||
| fb1c006cd9 | |||
| 928bfe7876 | |||
| 6485c733bb | |||
| b44bdb8a75 | |||
| 71f56699c8 | |||
| 66fa07f341 | |||
| 2c8467090e | |||
| a18d5d0532 | |||
| c5b0a76982 | |||
| f352085f62 | |||
| 5374666ac9 | |||
| 411bbef65c | |||
| f798f2c025 | |||
| 44c88a885f | |||
| b08bfeceb6 | |||
| be8bf53cc6 | |||
| fee6032e78 | |||
| 64eb70d292 | |||
| dc7f7feab1 | |||
| 8afbc63b85 | |||
| c942794b89 | |||
| e58b5a063f | |||
| dee3af3016 | |||
| 9f42c29714 | |||
| 95bc5b9f7c | |||
| 1cd3704bc3 | |||
| 8bbccd42d5 | |||
| f89ce7a965 | |||
| 7905edaf24 | |||
| 851baa030c | |||
| 567d2ac686 | |||
| 71bf334ac4 | |||
| 2df874e786 | |||
| fe9aa865f9 | |||
| 1e8316e16d | |||
| 380c80bbaf | |||
| a8fe8e2e13 | |||
| 22d0d064f7 | |||
| a5c7aef3b8 | |||
| e1f889f862 | |||
| c6f12ab2a8 | |||
| 31d8dcd6a8 | |||
| 1f3a985d3a | |||
| 6937a982d4 | |||
| 44bb88910f | |||
| 115b9fa4b3 | |||
| b6f9c050e1 | |||
| cbb05ac977 | |||
| f1d72cb480 | |||
| 3a5d6ed2cd | |||
| c15dcb02ec | |||
| 0d91001376 | |||
| 6143125f7a | |||
| ee0f703120 | |||
| 34393bf050 | |||
| 5a461bca7d | |||
| 5fedce71a0 | |||
| c9663ff14f | |||
| 18e301f26a | |||
| 35e37bbe76 | |||
| 5997921eb9 | |||
| e7bedd6a29 | |||
| 7194dcb2c7 | |||
| d62bdfc637 | |||
| ec6b90b33c | |||
| 0c0037416a | |||
| ad9d1ee430 | |||
| d7e5b8b916 | |||
| 3e44d38a90 | |||
| 9493531eaa | |||
| 64031668c1 | |||
| b6d122e449 | |||
| 19f26c6d91 | |||
| 4108434788 | |||
| 01d7f62c36 | |||
| 5cffeea4fd | |||
| e0fb29bd80 | |||
| ad9a59f894 | |||
| ddad768cd8 | |||
| 8ee4446b30 | |||
| 5f936d36b1 | |||
| 08f3e9c06b | |||
| 25b7903c37 | |||
| c6dd7203bb | |||
| 08c7ca99b6 | |||
| 8f7320c298 | |||
| 92bfbf662b | |||
| 44e7323720 | |||
| 78a3ae8aeb | |||
| 041abb732d | |||
| 9ee07794a8 | |||
| 7adfef9f36 | |||
| a3ec224cf0 | |||
| 6d4a6ee52a | |||
| 0add402434 | |||
| 6933aecfa4 | |||
| 93decb02af | |||
| c0acf1c1a0 | |||
| a6c3ab33b1 | |||
| 079a2cdbe3 | |||
| d9022fde9f | |||
| 830a518b86 | |||
| fef04409af | |||
| 4bc54d350b | |||
| e3cc80d32a | |||
| 411e05e998 | |||
| c319f6117a | |||
| a7fd96800a | |||
| a09e229711 | |||
| 7abb66b86f | |||
| f1707db5fb | |||
| 35e1cc7253 | |||
| e8b4a26eda | |||
| 93f93f0186 | |||
| 7c5de3c131 | |||
| a2a3134523 | |||
| 3821950e49 | |||
| d52cc045e0 | |||
| 158058b720 | |||
| df6f9ea71d | |||
| f4464578c0 | |||
| c48ee975c6 | |||
| e60e2306b7 | |||
| af422e62e1 | |||
| 952beccafc | |||
| 06171ae638 | |||
| b3a341847e | |||
| 0d325f2c73 | |||
| 577f3f768d | |||
| 15d479f1eb | |||
| 2b93076146 | |||
| 68c83d8a5d | |||
| 239ad9a4dc | |||
| 5f8d0d1b99 | |||
| 5827a18866 | |||
| 633db89031 | |||
| 1335ae13e8 | |||
| 115d52977d | |||
| 3bb36f5e78 | |||
| 98e9ba0fa7 | |||
| 35a69edfa2 | |||
| 7df1a295f3 | |||
| 85fbd37434 | |||
| 07f0862219 | |||
| bc99408652 | |||
| 461dad2724 | |||
| 6cf76f6535 | |||
| 33a5893da1 | |||
| c14c0a6af5 | |||
| fc7926c2cc | |||
| faf8832572 | |||
| d047e5d48a | |||
| 7baa586738 | |||
| 4c7e335ef4 | |||
| df8a1d3b26 | |||
| 6a1fff227e | |||
| 4810d6cc5c | |||
| 1b73beccf1 | |||
| ff8a791a51 | |||
| 98ead6ac69 | |||
| 8b6741641c | |||
| b035ad07ec | |||
| 25fc5d5835 | |||
| c1cdcddf41 | |||
| 9a5142ced3 | |||
| 586b7900bb | |||
| 0ccb03f004 | |||
| 90676ff8a4 | |||
| 2cacd94f41 | |||
| de3013eebf | |||
| 1c71258984 | |||
| 00831fdb61 | |||
| f5c629cb8a | |||
| 9531795066 | |||
| 71fe10efaf | |||
| b042b4cf60 | |||
| f4980cefde | |||
| 25901cef45 | |||
| d71cd625d0 | |||
| 43350ee1fd | |||
| ae1dee9d51 | |||
| ff2d077a7f | |||
| a383de971a | |||
| 800fa13071 | |||
| 490c68a9f5 | |||
| 1ba03ba909 | |||
| 346750931d | |||
| e612869027 | |||
| 2673ddaf13 | |||
| a3172c7918 | |||
| 8269d80620 | |||
| d1158cab05 | |||
| 09430e56b8 | |||
| 51d3684fcc | |||
| 2968ca3562 | |||
| ee3d8916ed | |||
| acedb77c07 | |||
| 32b1681573 | |||
| 5389e1b783 | |||
| f54a876636 | |||
| 2afed432f7 | |||
| b687d8ea95 | |||
| 2594afc60f | |||
| f5be4a8b99 | |||
| a8b0eeb973 | |||
| ff5ecb474f | |||
| 0a0939fa3d | |||
| 19485a110a | |||
| 79dc4e5f33 | |||
| 7f6721147a | |||
| 20bf6851c0 | |||
| 7adbb5d299 | |||
| 2a3d5de54b | |||
| 18ff6fe71b | |||
| a278e3a565 | |||
| 9f003189e9 | |||
| 050b420f9a | |||
| 2b59a35bf3 | |||
| 7f20a3f36a | |||
| 784289a792 | |||
| d79a73d311 | |||
| 13c0430c93 | |||
| 1e4081a03f | |||
| 275cc70e96 | |||
| 3fccbae676 | |||
| 1fb3088f0e | |||
| 81131edf2d | |||
| 973685ec08 | |||
| 6139deb175 | |||
| 93daed8ec8 | |||
| 08c34a18f2 | |||
| 682dd1093f | |||
| 6806d1f242 | |||
| 394fe4871f | |||
| edc1619962 | |||
| 970d613285 | |||
| 4167704f85 | |||
| 1e0ff4a950 | |||
| 4993d34835 | |||
| 3f9446d46f | |||
| 030a4e0e86 | |||
| d27cf2afc8 | |||
| 5b27eab680 | |||
| 345eabafb2 | |||
| c635fc00c3 | |||
| 2877083ebe | |||
| bb29b7e7f7 | |||
| 7aca2b2d6d | |||
| fe5ba9a84a | |||
| 2067a58c70 | |||
| 8b2c0f732f | |||
| fbd76594ea | |||
| a055dfac5b | |||
| e772a798f7 | |||
| ed9c4ebb68 | |||
| 0439e1f37a | |||
| eb4f88bc60 | |||
| 666477e448 | |||
| 6787400056 | |||
| 2ecda09ee4 | |||
| 0bd497279d | |||
| 1023cf0120 | |||
| f4dc4c315d | |||
| 8b92d0525f | |||
| 530811b699 | |||
| cee7ca2ca0 | |||
| c26a95ed60 | |||
| b43b6d6f75 | |||
| c969908ff5 | |||
| a5638203a6 | |||
| 042cc018cb | |||
| 42d2b8009c | |||
| 5264214eb3 | |||
| bba1fd964d | |||
| 5821a79af9 | |||
| 9dde2475fc | |||
| f90d2d2f04 | |||
| b4ba255afc | |||
| 1abee46f6d | |||
| 0fbfd5731d | |||
| 6265f9bc2c | |||
| 8c910fa532 | |||
| 08d2bb2fd5 | |||
| 885b784f92 | |||
| 7c56ec8285 | |||
| b21fc9db25 | |||
| e06989f2ae | |||
| fab2784e16 | |||
| b323736774 | |||
| a0c1fdbd74 | |||
| 2db6255fae | |||
| 898e7b272e | |||
| f0e6ee5835 | |||
| a01ce5c11c | |||
| c7e6114480 | |||
| e3908da7a9 | |||
| 93608c9549 | |||
| ecc2b70e43 | |||
| 92a3c2945c | |||
| 0be1bf4f15 | |||
| 65b0b22b01 | |||
| 7b4b572802 | |||
| 049474e4bd | |||
| 5c11372543 | |||
| de0eb0b4e9 | |||
| e60a1e5a25 | |||
| 27ae6b512b | |||
| 5f89c6e498 | |||
| b760287ca2 | |||
| e80543e0a2 | |||
| af6436c3d8 | |||
| f65e4bc417 | |||
| 68c28ed358 | |||
| fed94eab1b | |||
| 1dbee1d79f | |||
| 09b146928c | |||
| 983b558510 | |||
| 9fd7ca35f1 | |||
| e886fbcc5f | |||
| 853bfd5f9b | |||
| 6ba0786608 | |||
| b33b428d3b | |||
| 19c5efaed0 | |||
|
|
53285059c5 | ||
| a8e4b74fba | |||
| 2374c2d22e | |||
| 1df8d6589a | |||
| 90498eb117 | |||
| 0cc6274894 | |||
| 085d337fb7 | |||
| a56c06ca33 | |||
| d026f9b418 | |||
| 7803f8f11a | |||
| ec90862262 | |||
| 5efcfb8b61 | |||
| 7193a599b7 | |||
| 6ec387e724 | |||
| c3e8f87562 | |||
| ac846ad351 | |||
| 647a4c3782 | |||
| 1901c908ff | |||
| 797ea13982 | |||
| 6b006e78e5 | |||
| 733d6c8c7b | |||
| d3d59443fa | |||
| a74fbce48e | |||
| cecf7b0f74 | |||
| 8a862c86a5 | |||
| e6a9e2c7da | |||
| b147ee8850 | |||
| 2d8bd207ed | |||
| 3a125263b7 | |||
| a6a26cdf8d | |||
| ec1184d5c9 | |||
| ae518cafe5 | |||
| 3ae167bd16 | |||
| 82c342c7db | |||
| 0e10f29cd2 | |||
| 9c03bac804 | |||
| 6ff41c55fe | |||
| 992b64df8a | |||
| 53ac4a2050 | |||
|
|
d9f4a6ff8d | ||
| 521a68b4c7 | |||
| 8e74413e18 | |||
|
|
5f7ef2a18e | ||
|
|
fa969fa702 | ||
|
|
4aaba75c18 | ||
|
|
b98df08f44 | ||
|
|
4332bfee9b | ||
|
|
4430450431 | ||
|
|
aea6253094 | ||
|
|
37acfa1eec | ||
|
|
0955da489c | ||
|
|
2544f8f333 | ||
|
|
409a613e43 | ||
| 14da738cc8 | |||
| 7a8cc242ae | |||
| c0e6012d70 | |||
| b6df0ba2b1 | |||
| b9c1c766d6 | |||
| 802a872880 | |||
| 415b5b45b9 | |||
| dd9e0b4fc7 | |||
| 6c9a0ea576 | |||
| 995f50cc21 | |||
| 2a491ded00 | |||
| 0517f85d76 | |||
| f1c3844bd3 | |||
| 7309a435c5 | |||
| 2c26072560 | |||
| 425de0b315 | |||
| 30cb171612 | |||
| 43ba1bb449 | |||
| d630f29753 | |||
| 7b13733c9e | |||
| ca6ec6a8ed | |||
| efe07e39c2 | |||
| c738e5bda3 | |||
| 9d7e520168 | |||
| bc61c2e0ff | |||
| f82e720aeb | |||
| afacf61fbc | |||
| 677cab6a57 | |||
| 9df5eb4758 | |||
| 892060334c | |||
| f04d1dcf1e | |||
| 6bb23d7acd | |||
| aef30fecaa | |||
| 5f33172297 | |||
| 23feea4acc | |||
| e9738c2bc1 | |||
| e5954712e2 | |||
| 5d47a28ba6 | |||
| 95b1caeb26 | |||
| 049965cdc9 | |||
| 88406c6ee5 | |||
| 80d1b1af0f | |||
| d3a1c57111 | |||
| 8f824654e0 | |||
| 2d36c6ad6e | |||
| 4193b6b391 | |||
| b312403201 | |||
| a6076eb856 | |||
| 1cb54f44b1 | |||
| 1c2049f918 | |||
| 5c83162a29 | |||
| 45091da5ac | |||
| b0c0ca0e0f | |||
| 46cf60a3b9 | |||
| 68304af99e | |||
| 8805f0f804 | |||
| 570f08755d | |||
| 512aae252c | |||
| e53a90a75d | |||
| b2a0dfa702 | |||
| 439407ea59 | |||
| aa26fd7d54 | |||
| ca35611925 | |||
| c3dae2c704 | |||
| 9fe24cd115 | |||
| b97942b10f | |||
| c528d4dd78 | |||
| ab6e8962e4 | |||
| 6407579dd6 | |||
| da4b877b0d | |||
| 65a254d808 | |||
| 08d9b9d950 | |||
| a374e23821 | |||
| 329b6fc67e | |||
| b4281188d4 | |||
| 1d6d27c0ee | |||
| 721d9937e0 | |||
| c5c527ec10 | |||
| ff154b03f3 | |||
| 8e861faa24 | |||
| fabafcb78b | |||
| e668cdd89c | |||
| 656dc493b8 | |||
| 3d697fbcd0 | |||
| 0b55bd7dbb | |||
| b180429505 | |||
| 472718c595 | |||
| 6e6098b03a | |||
| e1b555781c | |||
| f9d6a816b0 | |||
| d10eb66542 | |||
| 8318a87d5d | |||
| 1b140661ba | |||
| 813d998bfb | |||
| a270edbde4 | |||
| e034d51ae0 | |||
| f110509ea0 | |||
| 5f787bedfe | |||
| b552ca7c51 | |||
| b3ddac60f6 | |||
| 91c88e7f43 | |||
| 5d7fc1ca0c | |||
| d063bd479c | |||
| 47e6c5f978 | |||
| df7b6ae71d | |||
| 80a6ac0c80 | |||
|
|
1dd5c6b9f4 | ||
|
|
fdd3b72e52 | ||
|
|
5664465df5 | ||
|
|
9a55262856 | ||
|
|
df451f56b1 | ||
| 9bee5df036 | |||
| e843b73472 | |||
| 7a99bae541 | |||
| 650ed8056e | |||
| 5ae386bac3 | |||
| 9963bf6179 | |||
| c7061c8c75 | |||
| 2919e07606 | |||
| b406ea6088 | |||
| 7f6da9d79e | |||
| e921095226 | |||
| 2b005d6ea5 | |||
| d4ab42d98f | |||
| a8ab835365 | |||
| c0c39ab4d0 | |||
| 55a246d806 | |||
| 85ba643bcc | |||
| 022cd239d5 | |||
| 4a035327ef | |||
| 78e30cd516 | |||
| 14540081be | |||
| 883f39e4b5 | |||
| 213d5b74b5 | |||
| c0cf11ee79 | |||
| 2e0a0e5eb0 | |||
| 7b035411c0 | |||
| fb04daff9f | |||
| 71d29a303f | |||
| f1cc396bfc | |||
| a483955763 | |||
| 3a2e5f5eb1 | |||
| b51c77dfa7 | |||
| 2603c1b29d | |||
| dd62f8f8ac | |||
| e176664bb4 | |||
| e8bd663ad7 | |||
| c67a11b8b6 | |||
| 10924e2410 | |||
| 8b0faf8a0b | |||
| 0fc23e2c86 | |||
| 0f7a8bd4f3 | |||
| 8640fefc8b | |||
| 21c4a7c577 | |||
| c453422317 | |||
| 60977f3631 | |||
| 57b4463c01 | |||
| fbc8e14125 | |||
| e13f2a7e42 | |||
| d593eb3134 | |||
| 6f81eeef7e | |||
| 991e5004d7 | |||
| 91498f45cd | |||
| 3d53693e68 | |||
| 1c7c4d3ab2 | |||
| 7451452088 | |||
| 7403be6519 | |||
| 7de920154c | |||
| cdccc9bc8b | |||
| dab297413f | |||
| 257ead2415 | |||
| 445f193dbb | |||
| bf68f6b52c | |||
| 7895b535fa | |||
| 545e729f2e | |||
| dfe061e611 | |||
| 21dffc846e | |||
| e3824fc740 | |||
| ac55a56e4a | |||
| 5e95516190 | |||
| 9304c7ad2f | |||
| 0272b82166 | |||
| d5a839b3c6 | |||
| 5d26dd1945 | |||
| a6eb744cc9 | |||
| 6e530786b9 | |||
| ce17229985 | |||
| 869c6fac12 | |||
| 2c465d5249 | |||
| a27b4072be | |||
| 25e4978583 | |||
| 457a3c6709 | |||
|
|
ddb9b2926d | ||
|
|
1e5ef4003a | ||
|
|
f246b6ce32 | ||
|
|
b246f43c70 | ||
|
|
fbf660d532 | ||
|
|
db3f03dc6c | ||
|
|
ba16d7873f | ||
|
|
ee33c71dfe | ||
|
|
1eadcb6521 | ||
|
|
b3a9c9dae8 | ||
|
|
c475691939 | ||
|
|
e6ac7e502c | ||
|
|
30581a4ee1 | ||
| a54311c53f | |||
| 0c9711baea | |||
| bffd71fea5 | |||
| 7e6e56a366 | |||
| baa78b9417 | |||
| b28bf5803d | |||
|
|
ee3eed6c23 | ||
| bf831dba45 | |||
| a43d54ee1d | |||
| f536713f04 | |||
| f438e80d3a | |||
| 38cb4c4f28 | |||
| 1178e8fd6c | |||
| e2414f94f3 | |||
| c87001d91e | |||
| 4cf9609153 | |||
| 83877d8dab | |||
| bab97fba5f | |||
| c289161400 | |||
| 7810f626c6 | |||
| 0294f538eb | |||
| ce07cece06 | |||
| 74013cf113 | |||
| 1eb7198e6f | |||
| c24c8914bf | |||
| e5dde472c9 | |||
| 7ccfab4d8b | |||
| 0bc6512bcc | |||
| e70174cb24 | |||
| fe155898bb | |||
| bd48032a50 | |||
| e124113d41 | |||
| 6974ef0163 | |||
| 015bfe983c | |||
| 275a892ee1 | |||
| 0ac4a1daa0 | |||
| 7bf3ba2443 | |||
| cfa12b0fed | |||
| 2f309440cc | |||
| db3d7f1f2e | |||
| d1febd13fd | |||
| 6fbd00a38f | |||
| 948c98f95b | |||
| 4139362677 | |||
| b9932383c6 | |||
| aa4ea2134a | |||
| 48f77c2f7a | |||
| 6567e78c8c | |||
| 32050bcdcd | |||
| 2aa10c9b1f | |||
| 4f9c06c7bd | |||
| b6bb190e69 | |||
| 4135fc5703 | |||
| c1ba51b903 | |||
| a218271001 | |||
| f4442fad0c | |||
| 87fdc1a444 | |||
| eed764c6e0 | |||
| f9a2185748 | |||
| 4f7c449ea7 | |||
| 7dab3fd094 | |||
| 49d225532c | |||
| b2c67e7df4 | |||
| 07259a7635 | |||
| d63c601812 | |||
| ecd1b55fc6 | |||
| 4c955e4115 | |||
| 14319a5c89 | |||
| 0ac388f3eb | |||
| fbf43fb10f | |||
| e0f41be887 | |||
| bd84989454 | |||
| e0b2e8e937 | |||
| f2ebc5659e | |||
| b72553aa11 | |||
| 0ed35e0354 | |||
| 29d846a944 | |||
| 9609fb150a | |||
| 9a5c4ab087 | |||
| f59f9a7ba0 | |||
| 8a925b35dd | |||
| 3e31c51f65 | |||
| 3c959ff532 | |||
| fa6deb7f82 | |||
| b7f5ede7cd | |||
| b2e0363594 | |||
| 73f4187087 | |||
| 1f63991ca0 | |||
| 8ea8d3ff57 | |||
| 070a94d87d | |||
| 22348e1554 | |||
| 0e2950ab69 | |||
| 2b0f6837a8 | |||
| ee4cc6706e | |||
| 948f8694f2 | |||
| 29314d473f | |||
| 5f177e9338 | |||
| d7dd2bd138 | |||
| ba37786038 | |||
| 179b79c926 | |||
| 411054afe9 | |||
| 067eafbbe4 | |||
| 253e256458 | |||
| 238fdf5d40 | |||
| 13ddeaaf0a | |||
| 07afbdaa4b | |||
| 0ff74d331f | |||
| 3eff6228be | |||
| edc6d11824 | |||
| e9aaa184cf | |||
| e8351e960d | |||
| 0ff03fb413 | |||
| ba83edd26c | |||
| eed058c891 | |||
| 48f82a6f13 | |||
| 177391a74c | |||
| 9ea177e2f6 | |||
| ca6a4d8ab5 | |||
| c5a2a05af6 | |||
| 0034f93caa | |||
| d01ef02389 | |||
| e8f2a72516 | |||
| bc66d35497 | |||
| e1d0d2c186 | |||
| e7c878b30a | |||
| 8fb46099d4 | |||
| 72628519a5 | |||
| f7375428b6 | |||
| ead8a44fe0 | |||
| a1aa71e271 | |||
| a72691a81f | |||
| 3be409ec70 | |||
| 9409197766 | |||
| 1a92094eaf | |||
| fa47ccfd85 | |||
| 6b4468bf7d | |||
| b0927b8388 | |||
| 593dc3ca55 | |||
| a124a1a71f | |||
| 0e71242fd3 | |||
| 556b2a2317 | |||
| 4bfd7c348d | |||
| 972007f9e5 | |||
| 9bfd1a78bd | |||
| 05d8332358 | |||
| dd62611588 | |||
| f0d6402529 | |||
| d73a37fbed | |||
| 9084a78420 | |||
| 1769aa45c9 | |||
| 3386263fbe | |||
| 0eb7a58494 | |||
| b995b86cee | |||
| a825912ad3 | |||
| e788dea8a4 | |||
| 7622420f06 | |||
| 66fff153e1 | |||
| a33171ba87 | |||
| 4bb7b4b6c4 | |||
| f8e887c1f2 | |||
| 47dc244a15 | |||
| f872deffb8 | |||
| 5489f601d2 | |||
| d77813d82f | |||
| b0f9d7906a | |||
| eec08d4a3e | |||
| 320c45096b | |||
| 68a83c31be | |||
| 88eb325079 | |||
| b2f4933a5f | |||
| e12a1d369d | |||
| c4f1e420f8 | |||
| 15a4280a36 | |||
| 3e39ef1705 | |||
| 0dd3a6190e | |||
| f03fbd42df | |||
| dfc86e4b96 | |||
| 167e2853f0 | |||
| 1698de332c | |||
| 377d85c7f1 | |||
| 68a3af0b52 | |||
| 5b7bfa79f9 | |||
| d7dee62e97 | |||
| 4368f0cbe5 | |||
| 12f35fefc4 | |||
| 49a1dad51e | |||
| 40c0403962 | |||
| 068e153ae9 | |||
| 42869cb28f | |||
| 56a96540b4 | |||
| 5a6bb57fd5 | |||
| 44521d0d5f | |||
| 43a4a0e6ee | |||
| 1373d0ce26 | |||
| c9c1ac5126 | |||
| d136b98411 | |||
| 7e0e359f46 | |||
| 86427cf6ef | |||
| c7db07f7ba | |||
| d3fbec1a9d | |||
| c621c45695 | |||
| bb456738f0 | |||
| 0112acdd2f | |||
| ae6121f3aa | |||
| 9b606cf9ac | |||
| 234d3c9c7c | |||
| ce4663d512 | |||
| 97de98b89a | |||
| 76d0c53cc1 | |||
| 8b102b083f | |||
| e13f9c6aa8 | |||
| e8b929d4ca | |||
| 034f048883 | |||
| aceb6ee14c | |||
| 7698a1490e | |||
| 59a25fbee9 | |||
| fc598838c4 | |||
| 11712b5b13 | |||
| d2799adad0 | |||
| 872639dab9 | |||
| e4562648ba | |||
| 941137ff51 | |||
| eaec736676 | |||
| 9ba7cb1ba5 | |||
| 2ce8e7f866 | |||
| 5a618a8db2 | |||
| d21e4ffba2 | |||
| 28855046b8 | |||
| eb351f9bed | |||
| 0e0bb17ad9 | |||
| e95f001dd2 | |||
| 0d4b9fe488 | |||
| 4be4fa2c4f | |||
| 8d4da63855 | |||
| 3a9941f69f | |||
| 01486dfbec | |||
| fb2280798a | |||
| 29f874e390 | |||
| dc6bdf7715 | |||
| 6022f5b9d2 | |||
| 30b6d4791f | |||
| e5c185627d | |||
| 573852d852 | |||
| 385c580358 | |||
| ec2b0e0f78 | |||
| c3816b709c | |||
| 4b8528af65 | |||
| 69ba636d74 | |||
| 1b035035ce | |||
| 4dc0d6a97c | |||
| 34e4036f66 | |||
| 1dd3e37a37 | |||
| e79e568a4c | |||
| 1641ba2898 | |||
| 31d9507033 | |||
| 67deef897f | |||
| 3b84161ec5 | |||
| a04bffbec9 | |||
| 7ad1383acb | |||
| 4217d471c4 | |||
| 5f6e96333c | |||
| 7962d3a16f | |||
| de6d831498 | |||
| be076616cc | |||
| 0a38fdd8d3 | |||
| 2fa5587fbf | |||
| 4bfffa579f | |||
| 010fab93d7 | |||
| 6f3eefb611 | |||
| 328b378978 | |||
| 1f518c2d33 | |||
| a1a5e665fb | |||
| 70afa7cc9b | |||
| 5f1ea76cad | |||
| 462aa44473 | |||
| dc0f0df92f | |||
| 0ec22766ba | |||
| 3549f8b2d2 | |||
| 8a3a2fecf5 | |||
| 5c8c7b8804 | |||
| e88d4c2ca7 | |||
| 83a91eea97 | |||
| 13ef0ba14a | |||
| 938ccd9215 | |||
| d394c390f7 | |||
| 4c705a4605 | |||
| 105aa7874f | |||
| 27ab3b0b21 | |||
| 03af604e94 | |||
| 05b8f5b400 | |||
| e8654ca181 | |||
| 68b4e71281 | |||
| b89617d125 | |||
| 70466aba7e | |||
| 5ddfe1ddb2 | |||
| 25418071fe | |||
| a9d4fb769d | |||
| 1faf234255 | |||
| c06afcd56d | |||
| 607b973dbd | |||
| 22e136d9fd | |||
| 7b2f44d19a | |||
| 74c31a0f18 | |||
| fd3c2e5f9b | |||
| be3724c6b1 | |||
| b8e6c21538 | |||
| 60afaf6211 | |||
| 090f305f02 | |||
| 0a30e5022b | |||
| 6733fe9c40 | |||
| 76ce4b8058 | |||
| 36f4bbc7e7 | |||
| 30d52c6061 | |||
| 7018915686 | |||
| a1fb4ce8eb | |||
| 5446dbce83 | |||
| 93b36f1bd4 | |||
| ab12de8287 | |||
| 3cdfc91c93 | |||
| a6c8105d8c | |||
| ca99421624 | |||
| 5c270a0362 | |||
| 19ae15f53f | |||
| 386c6bf268 | |||
| e075306363 | |||
| 9591350c3e | |||
| 45b18eb8e6 | |||
| 0f59798e73 | |||
| 7b56924466 | |||
| 3d30d65184 | |||
| 9bb896e84b | |||
| e0ee364929 | |||
| 8e9cd2d2f3 | |||
| f58597379b | |||
| e6f263b6de | |||
| c69864d0f5 | |||
| ae901b257b | |||
| fdc537d69a | |||
| f12c1053ca | |||
| 6435114384 | |||
| c55c3bca72 | |||
| 83b8627717 | |||
| 95ccceb259 | |||
| 31d8f5f7b9 | |||
|
|
f1660bbc74 | ||
|
|
5d72fe44ab | ||
| 714b7d845a | |||
| 066229eb0e | |||
| 0f96f02df5 | |||
| b753fdd2b0 | |||
| f9df0b8a12 | |||
| db41c55230 | |||
| 58b799edb4 | |||
| 94d3b8676f | |||
| de7aa58195 | |||
| 5d4e251251 | |||
| 45baa804e6 | |||
| 2c49848dd7 | |||
| be499b3085 | |||
| 4fde5fb65f | |||
| 4c84f857e7 | |||
| 1e55b7bf50 | |||
| 479d3e9f07 | |||
| dcf14c6e6f | |||
| 96d5ca0f3c | |||
| 32fa639d4a | |||
| 69760dd5f8 | |||
| 1237a9157c | |||
| fee59833f2 | |||
| 12f685010b | |||
| 6ac8af9946 | |||
| e8d4c128da | |||
| d2a5d4b3ec | |||
| 7797a7bf53 | |||
| e5430a7aed | |||
| 88cd4a3ec2 | |||
| 8650c2d4c8 | |||
| 1734e57d43 | |||
| 28d0fc161b | |||
| 8ebc767b76 | |||
| bbe8a19189 | |||
| 4bffd359b9 | |||
| 08bbfd91fe | |||
| 1e3cd64ec9 | |||
| 663de0e720 | |||
| 7cffd75749 | |||
| 327ea4912a | |||
| efa743a714 | |||
| cd44e8e4c3 | |||
| e185625f4a | |||
| 3e140e4f43 | |||
| 47a22b6540 | |||
| 72e74cea32 | |||
| 4993ae50fe | |||
| eeb111dd9e | |||
| 4bb992fc67 | |||
| 58040f8f49 | |||
| 4f2cefb1be | |||
| 2b33191db7 | |||
| 0969d68adc | |||
| 86533153bf | |||
| 6349763abc | |||
| 67693d6c31 | |||
| 31a757a5cd | |||
| 2c59dddca0 | |||
| 206466f9cc | |||
| 039c644453 | |||
| 5d377654aa | |||
| ff163026c7 | |||
| 1d431ecad6 | |||
| 6a4c2c6aea | |||
| 3f928ad507 | |||
| 735edf1529 | |||
| f49882fb0d | |||
| 6f4936f6be | |||
| e8eb36284b | |||
| cec8400145 | |||
| 22d8ea8215 | |||
| e6a6131a14 | |||
| 92b5e33940 | |||
| 63f7a75394 | |||
| dbe85322ea | |||
| 64d4ee9168 | |||
| f7f40be956 | |||
| f42eaeb953 | |||
| 954909fecd | |||
| 95133deeb0 | |||
| 8ba80e93e3 | |||
| 47c7617d24 | |||
| a5fc5b3753 | |||
| 0b2d8a7e2e | |||
| 5ee0a0044a | |||
| 6e39690d7a | |||
| ca4e9e0052 | |||
| f76ce5dae1 | |||
| 4e4a90b2d2 | |||
| 98f6fda99f | |||
| 9a125e0359 | |||
| 3778b2148c | |||
| 3ab76006af | |||
| c96db3a3dc | |||
| ea52ce1c65 | |||
| f80289aef1 | |||
| 5cdcff0cd0 | |||
| 4c523d56f5 | |||
| 67e4764a72 | |||
| e7ace4d497 | |||
| c6edf4e2cb | |||
| 2939ea0787 | |||
| 64adc63920 | |||
| 33d212bd84 | |||
| 5543bc4c9d | |||
| d106988fd7 | |||
| bc6fdec360 | |||
| a7d8863998 | |||
| a3b2b80c1e | |||
| 0b614ec4b6 | |||
| 0e2c029249 | |||
| deade0010b | |||
| e94fae1d85 | |||
| 259ca2e14e | |||
| e9f9ae5154 | |||
| 3b98263fbc | |||
| ca1d2dd16f | |||
| 9e254e6813 | |||
| 9e250e6129 | |||
| 8f22785d2f | |||
| bb716ab6b6 | |||
| 5acd231292 | |||
| 7ebe0adace | |||
| 9e3337e9c5 | |||
| 298dc9af27 | |||
| 840b0c07ff | |||
| 592c92785f | |||
| d0db4815f1 | |||
| 8cf105a550 | |||
| 9c6055a52e | |||
| a554b7681f | |||
| cbcc2f30b7 | |||
| 565125da67 | |||
| ec8782ad81 | |||
| 7388719cad | |||
| 75fb4b5809 | |||
| 408873b844 | |||
| 31a349704b | |||
| c3b8595cd7 | |||
| 2334afb3eb | |||
| ce9dc48d81 | |||
| 20f7f87072 | |||
| a9ce596381 | |||
| 8ac5f02d93 | |||
| 10b291b4aa | |||
| c894f33c11 | |||
| 1167cfa3a4 | |||
| 541a7c9e2b | |||
| 8b2dd048d3 | |||
| d4d223dbf0 | |||
| 6b9842c9d3 | |||
| e2387158dc | |||
| 89fbb3a3cf | |||
| 55da64a702 | |||
| edff93917e | |||
| 424390417a | |||
| 7427de1bb4 | |||
| 42adf023d9 | |||
| 02214a127c | |||
| 9e98bf3532 | |||
| 86955cf0cb | |||
| bf281820b9 | |||
| 4d0dd674ad | |||
| 973f9cfdc2 | |||
| 13d79c5338 | |||
| dca91feff8 | |||
| 505ebb48bc | |||
| eaa4060f2a | |||
| 5e87a669de | |||
| 9ce8043667 | |||
| edf2941e01 | |||
| da0c1087e9 | |||
| a4f9d5b461 | |||
| ebb3b962a8 | |||
| 38040ba1d3 | |||
| e17b4c6e23 | |||
| 03bd5b4c78 | |||
| ebe2da0309 | |||
| 201892ea7f | |||
| e12ac9b3a4 | |||
| 2b86a469a9 | |||
| dae11994c2 | |||
| 3e53b28a10 | |||
| 4c4e22a0e0 | |||
| b5f8799d0a | |||
| 875c6eaa5e | |||
| a56af56009 | |||
| eee51216b9 | |||
| 73578736bc | |||
| 33db01cbbf | |||
| a716fd1e22 | |||
| 19c3f44d9a | |||
| ae095b3e2c | |||
| eb92eed532 | |||
| 2652e558d2 | |||
| 262a26e3df | |||
|
|
4af4119561 | ||
|
|
04eae360a7 | ||
|
|
a6c645c33f | ||
| 4b7f59e2e9 | |||
| da17fc3e6d | |||
| b62af8d2ae | |||
| ef3e4dc39b | |||
| fbe624ca6d | |||
| 67112a37da | |||
| c0c263c4d7 | |||
| e32c09f48f | |||
| 91aa673dcb | |||
| 95257771a5 | |||
| fa6bb695f3 | |||
| 9f5b5282b1 | |||
| ea53eb9b24 | |||
| 98a0466761 | |||
| e3be74d519 | |||
| fdc6a88317 | |||
| d67bd62393 | |||
|
|
ea986917af | ||
|
|
ffbf4be19e | ||
|
|
2b87aacc58 | ||
|
|
b62b272492 | ||
|
|
e5027cf00d | ||
|
|
e7b4c01f93 | ||
|
|
304951e463 | ||
|
|
e9622edee9 | ||
|
|
80be960f29 | ||
|
|
d2d736a7ec | ||
|
|
341d799207 | ||
|
|
91289c8588 | ||
|
|
bc878a2e90 | ||
|
|
bb4e7b7712 | ||
|
|
dad0a7d30a | ||
|
|
b0ea38b047 | ||
|
|
9c35801196 | ||
|
|
f5338fc8a8 | ||
|
|
aa38b34191 | ||
|
|
01eae3f680 | ||
|
|
6a098b6317 | ||
|
|
e242867ddb | ||
|
|
e11af205f8 | ||
|
|
9dc9431170 | ||
|
|
1e182e0d75 | ||
|
|
a501c8e571 | ||
|
|
95eb703788 | ||
|
|
942f4f1c75 | ||
|
|
8ca120aa6f | ||
|
|
1f33d52429 | ||
|
|
257e78dcaa | ||
|
|
b88cd583d3 | ||
|
|
67da1563be | ||
|
|
4b92b8a38e | ||
|
|
39ae631cf1 | ||
|
|
84b4c998a7 | ||
|
|
e741b5aa6d | ||
|
|
162891ba1d | ||
|
|
1139a726c9 | ||
|
|
b0eb8c3b42 | ||
|
|
7315d5f5a1 | ||
|
|
7a1bde1b73 | ||
|
|
b1b8772717 | ||
|
|
856eaffda6 | ||
|
|
2c16fdad19 | ||
|
|
c79a991024 | ||
|
|
7b8d916685 | ||
|
|
3c447f5708 | ||
|
|
4f5023f745 | ||
|
|
2c5d37083b | ||
|
|
4f6024a473 | ||
|
|
2ac4c434f5 | ||
|
|
eabf5e1faf | ||
|
|
1ee955fbfe | ||
|
|
de06c7f81f | ||
|
|
4347df0b9b | ||
|
|
b951ef5ce4 | ||
|
|
a12f78761d | ||
|
|
894cbb3c9d | ||
|
|
26f9cf646b | ||
|
|
8c28df9517 | ||
|
|
1b76bbf6c2 | ||
|
|
e5b236f51c | ||
|
|
a213c39445 | ||
|
|
be6551888e | ||
|
|
3b29e1a87a | ||
|
|
bb63340555 | ||
|
|
24dddc3075 | ||
|
|
47ca25fe1c | ||
|
|
1cd418991c | ||
|
|
d15c3ed047 | ||
|
|
26e5ce6852 | ||
|
|
f834e08273 | ||
|
|
26e40adb21 | ||
|
|
43ed65bc76 | ||
|
|
1f049952cc | ||
|
|
869c1fbe51 | ||
|
|
5b78146db9 | ||
|
|
fff73ed2b8 | ||
|
|
71a506443f | ||
|
|
2e50be6254 | ||
|
|
ceaafc495d | ||
|
|
67de27578e | ||
|
|
e82e515a23 | ||
|
|
20c740ce07 | ||
|
|
9a9538d14d | ||
|
|
ca50b53bae | ||
|
|
d420c7d0a9 | ||
|
|
4195371efb | ||
|
|
27e309f04d | ||
|
|
b20a4fa149 | ||
|
|
2c4bcb9c39 | ||
|
|
07b41716e8 | ||
|
|
e92e7758e7 | ||
|
|
c64c34a9fb | ||
|
|
a221e6358e | ||
|
|
f40122d5b2 | ||
|
|
a065205ea0 | ||
|
|
856f42ce27 | ||
|
|
016d50e383 | ||
|
|
1507b279f7 | ||
|
|
000f7cbfe1 | ||
|
|
cbbd04efb6 |
@@ -9,6 +9,6 @@ indent_style = tab
|
||||
indent_size = tab
|
||||
smart_tab = true
|
||||
|
||||
[{*.yaml,*.yml}]
|
||||
[{*.yaml,*.yml,*.nix}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
83
.env.example
83
.env.example
@@ -1,6 +1,79 @@
|
||||
TVDB__APIKEY=
|
||||
THEMOVIEDB__APIKEY=
|
||||
AUTHENTICATION_SECRET=
|
||||
POSTGRES_USER=kyoousername
|
||||
POSTGRES_PASSWORD=kyoopassword
|
||||
# vi: ft=sh
|
||||
# shellcheck disable=SC2034
|
||||
|
||||
|
||||
# Useful config options
|
||||
|
||||
# Library root can either be an absolute path or a relative path to your docker-compose.yml file.
|
||||
LIBRARY_ROOT=./video
|
||||
CACHE_ROOT=/tmp/kyoo_cache
|
||||
LIBRARY_LANGUAGES=en
|
||||
# A pattern (regex) to ignore video files.
|
||||
LIBRARY_IGNORE_PATTERN=".*/[dD]ownloads?/.*"
|
||||
|
||||
# If this is true, new accounts wont have any permissions before you approve them in your admin dashboard.
|
||||
REQUIRE_ACCOUNT_VERIFICATION=true
|
||||
# Specify permissions of guest accounts, default is no permissions.
|
||||
UNLOGGED_PERMISSIONS=
|
||||
# but you can allow anyone to use your instance without account by doing:
|
||||
# UNLOGGED_PERMISSIONS=overall.read,overall.play
|
||||
# You can specify this to allow guests users to see your collection without behing able to play videos for example:
|
||||
# UNLOGGED_PERMISSIONS=overall.read
|
||||
|
||||
# Specify permissions of new accounts.
|
||||
DEFAULT_PERMISSIONS=overall.read,overall.play
|
||||
|
||||
# Hardware transcoding (equivalent of --profile docker compose option).
|
||||
COMPOSE_PROFILES= # vaapi or qsv or nvidia
|
||||
# the preset used during transcode. faster means worst quality, you can probably use a slower preset with hwaccels
|
||||
# warning: using vaapi hwaccel disable presets (they are not supported).
|
||||
GOCODER_PRESET=fast
|
||||
|
||||
|
||||
# The following two values should be set to a random sequence of characters.
|
||||
# You MUST change thoses when installing kyoo (for security)
|
||||
AUTHENTICATION_SECRET="4c@mraGB!KRfF@kpS8739y9FcHemKxBsqqxLbdR?"
|
||||
# You can input multiple api keys separated by a ,
|
||||
KYOO_APIKEYS=t7H5!@4iMNsAaSJQ49pat4jprJgTcF656if#J3
|
||||
|
||||
THEMOVIEDB_APIKEY=
|
||||
|
||||
# The url you can use to reach your kyoo instance. This is used during oidc to redirect users to your instance.
|
||||
PUBLIC_URL=http://localhost:5000
|
||||
|
||||
# Use a builtin oidc service (google, discord, trakt, or simkl):
|
||||
# When you create a client_id, secret combo you may be asked for a redirect url. You need to specify https://YOUR-PUBLIC-URL/api/auth/logged/YOUR-SERVICE-NAME
|
||||
OIDC_DISCORD_CLIENTID=
|
||||
OIDC_DISCORD_SECRET=
|
||||
# Or add your custom one:
|
||||
OIDC_SERVICE_NAME=YourPrettyName
|
||||
OIDC_SERVICE_LOGO=https://url-of-your-logo.com
|
||||
OIDC_SERVICE_CLIENTID=
|
||||
OIDC_SERVICE_SECRET=
|
||||
OIDC_SERVICE_AUTHORIZATION=https://url-of-the-authorization-endpoint-of-the-oidc-service.com/auth
|
||||
OIDC_SERVICE_TOKEN=https://url-of-the-token-endpoint-of-the-oidc-service.com/token
|
||||
OIDC_SERVICE_PROFILE=https://url-of-the-profile-endpoint-of-the-oidc-service.com/userinfo
|
||||
OIDC_SERVICE_SCOPE="the list of scopes space separeted like email identity"
|
||||
# on the previous list, service is the internal name of your service, you can add as many as you want.
|
||||
|
||||
|
||||
# Following options are optional and only useful for debugging.
|
||||
|
||||
# To debug the front end, you can set the following to an external backend
|
||||
KYOO_URL=
|
||||
# The library root inside the container.
|
||||
KYOO_LIBRARY_ROOT=/video
|
||||
|
||||
# Database things
|
||||
POSTGRES_USER=KyooUser
|
||||
POSTGRES_PASSWORD=KyooPassword
|
||||
POSTGRES_DB=kyooDB
|
||||
POSTGRES_SERVER=postgres
|
||||
POSTGRES_PORT=5432
|
||||
|
||||
MEILI_HOST="http://meilisearch:7700"
|
||||
MEILI_MASTER_KEY="ghvjkgisbgkbgskegblfqbgjkebbhgwkjfb"
|
||||
|
||||
RABBITMQ_HOST=rabbitmq
|
||||
RABBITMQ_DEFAULT_USER=kyoo
|
||||
RABBITMQ_DEFAULT_PASS=aohohunuhouhuhhoahothonseuhaoensuthoaentsuhha
|
||||
|
||||
3
.git-blame-ignore-revs
Normal file
3
.git-blame-ignore-revs
Normal file
@@ -0,0 +1,3 @@
|
||||
7e6e56a366babe17e7891a5897180efbf93c00c5
|
||||
a5638203a6ecb9f372a5a61e1c8fd443bf3a17fe
|
||||
18e301f26acd7f2e97eac26c5f48377fa13956f5
|
||||
64
.gitattributes
vendored
64
.gitattributes
vendored
@@ -1,63 +1 @@
|
||||
###############################################################################
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
###############################################################################
|
||||
* text=auto
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
# This is need for earlier builds of msysgit that does not have it on by
|
||||
# default for csharp files.
|
||||
# Note: This is only used by command line
|
||||
###############################################################################
|
||||
#*.cs diff=csharp
|
||||
|
||||
###############################################################################
|
||||
# Set the merge driver for project and solution files
|
||||
#
|
||||
# Merging from the command prompt will add diff markers to the files if there
|
||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||
# the diff markers are never inserted). Diff markers may cause the following
|
||||
# file extensions to fail to load in VS. An alternative would be to treat
|
||||
# these files as binary and thus will always conflict and require user
|
||||
# intervention with every merge. To do so, just uncomment the entries below
|
||||
###############################################################################
|
||||
#*.sln merge=binary
|
||||
#*.csproj merge=binary
|
||||
#*.vbproj merge=binary
|
||||
#*.vcxproj merge=binary
|
||||
#*.vcproj merge=binary
|
||||
#*.dbproj merge=binary
|
||||
#*.fsproj merge=binary
|
||||
#*.lsproj merge=binary
|
||||
#*.wixproj merge=binary
|
||||
#*.modelproj merge=binary
|
||||
#*.sqlproj merge=binary
|
||||
#*.wwaproj merge=binary
|
||||
|
||||
###############################################################################
|
||||
# behavior for image files
|
||||
#
|
||||
# image files are treated as binary by default.
|
||||
###############################################################################
|
||||
#*.jpg binary
|
||||
#*.png binary
|
||||
#*.gif binary
|
||||
|
||||
###############################################################################
|
||||
# diff behavior for common document formats
|
||||
#
|
||||
# Convert binary document formats to text before diffing them. This feature
|
||||
# is only available from the command line. Turn it on by uncommenting the
|
||||
# entries below.
|
||||
###############################################################################
|
||||
#*.doc diff=astextplain
|
||||
#*.DOC diff=astextplain
|
||||
#*.docx diff=astextplain
|
||||
#*.DOCX diff=astextplain
|
||||
#*.dot diff=astextplain
|
||||
#*.DOT diff=astextplain
|
||||
#*.pdf diff=astextplain
|
||||
#*.PDF diff=astextplain
|
||||
#*.rtf diff=astextplain
|
||||
#*.RTF diff=astextplain
|
||||
*.Designer.cs linguist-generated=true
|
||||
|
||||
89
.github/workflows/analysis.yml
vendored
89
.github/workflows/analysis.yml
vendored
@@ -1,89 +0,0 @@
|
||||
name: Analysis
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- next
|
||||
pull_request:
|
||||
|
||||
|
||||
jobs:
|
||||
analysis:
|
||||
name: Static Analysis
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
||||
|
||||
- name: Cache SonarCloud packages
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/sonar/cache
|
||||
key: ${{ runner.os }}-sonar
|
||||
restore-keys: ${{ runner.os }}-sonar
|
||||
|
||||
- name: Cache SonarCloud scanner
|
||||
id: cache-sonar-scanner
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.sonar/scanner
|
||||
key: ${{ runner.os }}-sonar-scanner
|
||||
restore-keys: ${{ runner.os }}-sonar-scanner
|
||||
|
||||
- name: Install SonarCloud scanner
|
||||
if: steps.cache-sonar-scanner.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
cd back
|
||||
mkdir -p ~/.sonar/scanner
|
||||
dotnet tool update dotnet-sonarscanner --tool-path ~/.sonar/scanner
|
||||
|
||||
- name: Wait for tests to run (Push)
|
||||
uses: lewagon/wait-on-check-action@master
|
||||
if: github.event_name != 'pull_request'
|
||||
with:
|
||||
ref: ${{github.ref}}
|
||||
check-name: tests
|
||||
repo-token: ${{secrets.GITHUB_TOKEN}}
|
||||
running-workflow-name: analysis
|
||||
allowed-conclusions: success,skipped,cancelled,neutral,failure
|
||||
- name: Wait for tests to run (PR)
|
||||
uses: lewagon/wait-on-check-action@master
|
||||
if: github.event_name == 'pull_request'
|
||||
with:
|
||||
ref: ${{github.event.pull_request.head.sha}}
|
||||
check-name: tests
|
||||
repo-token: ${{secrets.GITHUB_TOKEN}}
|
||||
running-workflow-name: analysis
|
||||
allowed-conclusions: success,skipped,cancelled,neutral,failure
|
||||
|
||||
- name: Download coverage report
|
||||
uses: dawidd6/action-download-artifact@v2
|
||||
with:
|
||||
commit: ${{env.COMMIT_SHA}}
|
||||
workflow: tests.yml
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
|
||||
- name: Build and analyze
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
cp -r results.xml/ coverage.xml/ back/
|
||||
cd back
|
||||
find . -name 'coverage.opencover.xml'
|
||||
dotnet build-server shutdown
|
||||
|
||||
~/.sonar/scanner/dotnet-sonarscanner begin \
|
||||
-k:"AnonymusRaccoon_Kyoo" \
|
||||
-o:"anonymus-raccoon" \
|
||||
-d:sonar.login="${{ secrets.SONAR_TOKEN }}" \
|
||||
-d:sonar.host.url="https://sonarcloud.io" \
|
||||
-d:sonar.cs.opencover.reportsPaths="**/coverage.opencover.xml" \
|
||||
-d:sonar.cs.vstest.reportsPaths="**/TestOutputResults.xml"
|
||||
|
||||
dotnet build --no-incremental '-p:SkipTranscoder=true'
|
||||
|
||||
~/.sonar/scanner/dotnet-sonarscanner end -d:sonar.login="${{ secrets.SONAR_TOKEN }}"
|
||||
64
.github/workflows/coding-style.yml
vendored
64
.github/workflows/coding-style.yml
vendored
@@ -1,15 +1,61 @@
|
||||
name: CodingStyle
|
||||
name: Coding Style
|
||||
on: [pull_request, workflow_dispatch]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: "Coding style check"
|
||||
back:
|
||||
name: "Lint Back"
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./back
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Check coding style
|
||||
run: |
|
||||
dotnet tool restore
|
||||
dotnet csharpier . --check
|
||||
|
||||
front:
|
||||
name: "Lint Front"
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./front
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.x
|
||||
cache: yarn
|
||||
cache-dependency-path: front/yarn.lock
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Lint
|
||||
run: yarn lint && yarn format
|
||||
|
||||
scanner:
|
||||
name: "Lint scanner/autosync"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v1
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: chartboost/ruff-action@v1
|
||||
with:
|
||||
dotnet-version: 6.0.x
|
||||
- name: Build the app
|
||||
run: cd back && dotnet build -p:CheckCodingStyle=true -p:TreatWarningsAsErrors=true '-p:SkipTranscoder=true'
|
||||
args: format --check
|
||||
|
||||
transcoder:
|
||||
name: "Lint transcoder"
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./transcoder
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Run go fmt
|
||||
run: if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then exit 1; fi
|
||||
|
||||
75
.github/workflows/docker.yml
vendored
75
.github/workflows/docker.yml
vendored
@@ -4,7 +4,10 @@ on:
|
||||
branches:
|
||||
- master
|
||||
- next
|
||||
tags:
|
||||
- v*
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -14,52 +17,94 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- context: ./back
|
||||
dockerfile: Dockerfile
|
||||
label: back
|
||||
image: ghcr.io/${{github.repository_owner}}/kyoo_back
|
||||
image: zoriya/kyoo_back
|
||||
|
||||
- context: ./back
|
||||
dockerfile: Dockerfile.migrations
|
||||
label: migrations
|
||||
image: zoriya/kyoo_migrations
|
||||
|
||||
- context: ./front
|
||||
dockerfile: Dockerfile
|
||||
label: front
|
||||
image: ghcr.io/${{github.repository_owner}}/kyoo_front
|
||||
name: Docker build ${{matrix.label}}
|
||||
image: zoriya/kyoo_front
|
||||
|
||||
- context: ./scanner
|
||||
dockerfile: Dockerfile
|
||||
label: scanner
|
||||
image: zoriya/kyoo_scanner
|
||||
|
||||
- context: ./autosync
|
||||
dockerfile: Dockerfile
|
||||
label: autosync
|
||||
image: zoriya/kyoo_autosync
|
||||
|
||||
- context: ./transcoder
|
||||
dockerfile: Dockerfile
|
||||
label: transcoder
|
||||
image: zoriya/kyoo_transcoder
|
||||
name: Build ${{matrix.label}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: filter
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
filters: |
|
||||
should_run:
|
||||
- '${{matrix.context}}/**'
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{matrix.image}}
|
||||
tags: |
|
||||
type=edge
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
|
||||
- name: Check if a package should be pushed
|
||||
run: |
|
||||
echo "SHOULD_PUSH=$([ "${GITHUB_REF##*/}" == "master" ] || [ "${GITHUB_REF##*/}" == "next" ] && echo "true" || echo "false")" >> $GITHUB_ENV
|
||||
echo "SHOULD_PUSH=$([ "${GITHUB_REF##*/}" == "master" ] || [ "${GITHUB_REF##*/}" == "next" ] || [ "${GITHUB_REF_TYPE}" == "tag" ] && echo "true" || echo "false")" >> $GITHUB_ENV
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
if: env.SHOULD_PUSH == 'true'
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{github.repository_owner}}
|
||||
password: ${{secrets.GITHUB_TOKEN}}
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Build and push
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v5
|
||||
if: steps.filter.outputs.should_run == 'true' || github.event_name == 'workflow_dispatch' || startsWith(github.event.ref, 'refs/tags/v')
|
||||
with:
|
||||
context: ${{matrix.context}}
|
||||
file: ${{matrix.context}}/${{matrix.dockerfile}}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
build-args: |
|
||||
VERSION=0.0.0
|
||||
push: ${{env.SHOULD_PUSH}}
|
||||
tags: ${{steps.meta.outputs.tags}}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Sync README.MD
|
||||
if: env.SHOULD_PUSH == 'true'
|
||||
uses: ms-jpq/sync-dockerhub-readme@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
repository: ${{ matrix.image }}
|
||||
readme: "./README.md"
|
||||
|
||||
32
.github/workflows/documentation.yml
vendored
32
.github/workflows/documentation.yml
vendored
@@ -1,32 +0,0 @@
|
||||
name: Update the documentation
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
Building:
|
||||
runs-on: [ubuntu-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: nikeee/docfx-action@v1.0.0
|
||||
name: Build Documentation
|
||||
with:
|
||||
args: docs/docfx.json
|
||||
- name: Update the docs
|
||||
run: |
|
||||
cd docs/_site
|
||||
sudo chown $(whoami):$(whoami) . -R
|
||||
echo -n docs.kyoo.moe > CNAME
|
||||
git config --global user.email "${GITHUB_ACTOR}@github.com"
|
||||
git config --global user.name "${GITHUB_ACTOR}"
|
||||
git init
|
||||
git add -A
|
||||
git commit -m "Deploying the documentation"
|
||||
git remote add origin https://${GITHUB_ACTOR}:${GITHUB_TOKEN}@${GITHUB_REPO}
|
||||
git checkout -b gh-pages
|
||||
git push --force origin gh-pages
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_REPO: "github.com/${{github.repository_owner}}/Kyoo"
|
||||
66
.github/workflows/native-build.yml
vendored
Normal file
66
.github/workflows/native-build.yml
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
name: Native build
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
|
||||
jobs:
|
||||
update:
|
||||
name: Expo Build
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./front
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Check for EXPO_TOKEN
|
||||
run: |
|
||||
if [ -z "${{ secrets.EXPO_TOKEN }}" ]; then
|
||||
echo "You must provide an EXPO_TOKEN secret linked to this project's Expo account in this repo's secrets. Learn more: https://docs.expo.dev/eas-update/github-actions"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.x
|
||||
cache: yarn
|
||||
cache-dependency-path: front/yarn.lock
|
||||
|
||||
- name: Setup Expo
|
||||
uses: expo/expo-github-action@v7
|
||||
with:
|
||||
expo-version: latest
|
||||
eas-version: latest
|
||||
token: ${{ secrets.EXPO_TOKEN }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Build Mobile Release
|
||||
run: yarn build:mobile:apk | tee log.txt
|
||||
|
||||
- name: Parse Asset URL
|
||||
id: url
|
||||
run: |
|
||||
ASSET_URL=$(cat log.txt | jq '.[0].artifacts.buildUrl' -r)
|
||||
echo The android url is $ASSET_URL
|
||||
echo "assetUrl=$ASSET_URL" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Download APK Asset
|
||||
run: wget -O kyoo.apk ${{ steps.url.outputs.assetUrl }}
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: kyoo.apk
|
||||
path: ./front/kyoo.apk
|
||||
|
||||
- name: Upload release artifacts
|
||||
uses: Roang-zero1/github-upload-release-artifacts-action@v2
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
args: ./front/kyoo.apk
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
43
.github/workflows/native-update.yml
vendored
Normal file
43
.github/workflows/native-update.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: Native update
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
|
||||
jobs:
|
||||
update:
|
||||
name: Expo Update
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./front
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Check for EXPO_TOKEN
|
||||
run: |
|
||||
if [ -z "${{ secrets.EXPO_TOKEN }}" ]; then
|
||||
echo "You must provide an EXPO_TOKEN secret linked to this project's Expo account in this repo's secrets. Learn more: https://docs.expo.dev/eas-update/github-actions"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.x
|
||||
cache: yarn
|
||||
cache-dependency-path: front/yarn.lock
|
||||
|
||||
- name: Setup Expo
|
||||
uses: expo/expo-github-action@v7
|
||||
with:
|
||||
expo-version: latest
|
||||
eas-version: latest
|
||||
token: ${{ secrets.EXPO_TOKEN }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Publish update
|
||||
run: yarn update
|
||||
36
.github/workflows/release.yml
vendored
36
.github/workflows/release.yml
vendored
@@ -1,36 +0,0 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set commit environment
|
||||
run: echo "COMMIT_SHA=$(git rev-list -n 1 ${{github.ref}})" >> $GITHUB_ENV
|
||||
- name: Wait for builds & tests to finish
|
||||
uses: lewagon/wait-on-check-action@master
|
||||
with:
|
||||
ref: ${{github.ref}}
|
||||
repo-token: ${{secrets.GITHUB_TOKEN}}
|
||||
running-workflow-name: release
|
||||
allowed-conclusions: success,skipped,cancelled,neutral
|
||||
# - name: Public the abstractions to nuget
|
||||
# id: publish_nuget
|
||||
# uses: rohith/publish-nuget@v2
|
||||
# with:
|
||||
# PROJECT_FILE_PATH: Kyoo.Abstractions/Kyoo.Abstractions.csproj
|
||||
# PACKAGE_NAME: Kyoo.Abstractions
|
||||
# VERSION_REGEX: ^\s*<PackageVersion>(.*)<\/PackageVersion>\s*$
|
||||
# NUGET_KEY: ${{secrets.NUGET_API_KEY}}
|
||||
# INCLUDE_SYMBOLS: true
|
||||
- name: Create Release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
generateReleaseNotes: true
|
||||
token: ${{secrets.GITHUB_TOKEN}}
|
||||
29
.github/workflows/robot.yml
vendored
29
.github/workflows/robot.yml
vendored
@@ -8,32 +8,31 @@ on:
|
||||
|
||||
|
||||
jobs:
|
||||
build:
|
||||
test:
|
||||
name: Run Robot Tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Pull images
|
||||
run: docker-compose pull
|
||||
run: |
|
||||
cp .env.example .env
|
||||
docker compose version
|
||||
docker compose pull
|
||||
|
||||
- name: Docker cache
|
||||
uses: satackey/action-docker-layer-caching@v0.0.11
|
||||
continue-on-error: true
|
||||
|
||||
- name: Build the app
|
||||
run: docker-compose build
|
||||
|
||||
- name: Start the service
|
||||
run: |
|
||||
cp .env.example .env
|
||||
docker-compose up -d
|
||||
docker compose up -d back postgres ingress meilisearch # --wait Wait is not available on gha
|
||||
|
||||
- name: Perform healthchecks
|
||||
run: |
|
||||
docker-compose ps -a
|
||||
wget --retry-connrefused --retry-on-http-error=502 http://localhost:8901 #/api/healthcheck
|
||||
docker compose ps -a
|
||||
docker compose logs
|
||||
wget --retry-connrefused --retry-on-http-error=502 http://localhost:8901/api/health || (docker compose logs && exit 1)
|
||||
|
||||
- name: Run robot tests
|
||||
run: |
|
||||
@@ -42,9 +41,9 @@ jobs:
|
||||
|
||||
- name: Show logs
|
||||
if: failure()
|
||||
run: docker-compose logs
|
||||
run: docker compose logs
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: results
|
||||
path: out
|
||||
|
||||
59
.github/workflows/tests.yml
vendored
59
.github/workflows/tests.yml
vendored
@@ -1,59 +0,0 @@
|
||||
name: Testing
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- next
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
runs-on: ubuntu-latest
|
||||
container: mcr.microsoft.com/dotnet/sdk:6.0
|
||||
services:
|
||||
postgres:
|
||||
image: postgres
|
||||
env:
|
||||
POSTGRES_PASSWORD: postgres
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd back
|
||||
dotnet build '-p:SkipTranscoder=true' -p:CopyLocalLockFileAssemblies=true
|
||||
cp ./out/bin/Kyoo.Abstractions/Debug/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll ./tests/Kyoo.Tests/bin/Debug/net6.0/
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
cd back
|
||||
dotnet test --no-build '-p:CollectCoverage=true;CoverletOutputFormat=opencover' --logger "trx;LogFileName=TestOutputResults.xml"
|
||||
env:
|
||||
POSTGRES_HOST: postgres
|
||||
POSTGRES_USERNAME: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
|
||||
- name: Sanitize coverage output
|
||||
if: ${{ always() }}
|
||||
run: sed -i "s'$(pwd)/back'.'" back/tests/Kyoo.Tests/coverage.opencover.xml
|
||||
|
||||
- name: Upload tests results
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: results.xml
|
||||
path: "**/TestOutputResults.xml"
|
||||
|
||||
- name: Upload coverage report
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: coverage.xml
|
||||
path: "**/coverage.opencover.xml"
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
||||
/video
|
||||
.env
|
||||
.venv
|
||||
.idea
|
||||
.vscode
|
||||
log.html
|
||||
|
||||
4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -1,4 +0,0 @@
|
||||
[submodule "transcoder"]
|
||||
path = src/Kyoo.Transcoder
|
||||
url = ../Kyoo.Transcoder.git
|
||||
branch = master
|
||||
5
.pg_format
Normal file
5
.pg_format
Normal file
@@ -0,0 +1,5 @@
|
||||
tabs=1
|
||||
function-case=1 #lowercase
|
||||
keyword-case=1
|
||||
type-case=1
|
||||
no-space-function=1
|
||||
@@ -1,4 +1,4 @@
|
||||
# Authors
|
||||
Ordered by the date of the first commit.
|
||||
|
||||
* Zoe Roux ([@AnonymusRaccoon](http://github.com/AnonymusRaccoon))
|
||||
* Zoe Roux ([@zoriya](http://github.com/zoriya))
|
||||
|
||||
@@ -3,21 +3,19 @@
|
||||
Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great.
|
||||
|
||||
Contributions to this project are [released](https://docs.github.com/en/github/site-policy/github-terms-of-service#6-contributions-under-repository-license)
|
||||
to the public under the [GPL-3.0 License](https://github.com/AnonymusRaccoon/Kyoo/blob/master/LICENSE).
|
||||
to the public under the [GPL-3.0 License](https://github.com/zoriya/Kyoo/blob/master/LICENSE).
|
||||
|
||||
## Submitting a pull request
|
||||
|
||||
1. [Fork](https://github.com/AnonymusRaccoon/Kyoo/fork) and clone the repository
|
||||
2. Install the toolstack and/or download precompiled binaries for the transcoder (see [Development & Build](https://github.com/AnonymusRaccoon/Kyoo#development--build))
|
||||
3. Create a new branch: `git checkout -b my-branch-name`
|
||||
4. Make your changes (Please try to follow the same coding style as what has already been made - indent with tabs, align with spaces etc)
|
||||
5. Make sure the tests pass: `dotnet tests`
|
||||
6. Push to your fork and [submit a pull request](https://github.com/AnonymusRaccoon/Kyoo/compare)
|
||||
7. Pat your self on the back and wait for your pull request to be reviewed and merged.
|
||||
1. [Fork](https://github.com/zoriya/Kyoo/fork) and clone the repository
|
||||
2. Create a new branch: `git checkout -b my-branch-name`
|
||||
3. Make your changes (Please try to follow the same coding style as what has already been made - indent with tabs, align with spaces etc).
|
||||
Don't forget to run the auto-formatter.
|
||||
4. Push to your fork and [submit a pull request](https://github.com/zoriya/Kyoo/compare)
|
||||
5. Pat your self on the back and wait for your pull request to be reviewed and merged.
|
||||
|
||||
Here are a few things you can do that will increase the likelihood of your pull request being accepted:
|
||||
|
||||
- Write tests.
|
||||
- Make sure the `README.md` and any other relevant **documentation are kept up-to-date**.
|
||||
- We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option.
|
||||
- Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as **separate pull requests**.
|
||||
|
||||
100
INSTALLING.md
Normal file
100
INSTALLING.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# Installing TLDR
|
||||
|
||||
1. Install docker & docker-compose
|
||||
2. Download the
|
||||
[`docker-compose.yml`](https://raw.githubusercontent.com/zoriya/Kyoo/master/docker-compose.prod.yml),
|
||||
[`nginx.conf.template`](https://raw.githubusercontent.com/zoriya/Kyoo/master/nginx.conf.template) and
|
||||
[`.env`](https://raw.githubusercontent.com/zoriya/Kyoo/master/.env.example) files
|
||||
3. Fill the `.env` file with your configuration options (and an API Key from [themoviedb.org](https://www.themoviedb.org/))
|
||||
4. Look at [Hardware Acceleration section](#Hardware-Acceleration) if you need it
|
||||
5. Run `docker compose up -d` and see kyoo at `http://localhost:8901`
|
||||
|
||||
# Installing
|
||||
|
||||
To install Kyoo, you need docker and docker-compose. Those can be installed from here for
|
||||
[Linux](https://docs.docker.com/engine/install/)
|
||||
[Mac](https://docs.docker.com/desktop/install/mac-install/)
|
||||
or [Windows](https://docs.docker.com/desktop/install/windows-install/). Docker is used to run each services of Kyoo in
|
||||
an isolated environment with all the dependencies they need.
|
||||
|
||||
Kyoo also needs 3 files to work properly. Two of them can simply be copy-pasted from this repository, the other needs to be filled in with your configurations.
|
||||
Those files can be put in any directory of your choice.
|
||||
|
||||
Those 3 files are:
|
||||
|
||||
- A `docker-compose.yml` (simply copy docker-compose.prod.yml from [here](https://raw.githubusercontent.com/zoriya/Kyoo/master/docker-compose.prod.yml)).
|
||||
- A `nginx.conf.template` copied from [here](https://raw.githubusercontent.com/zoriya/Kyoo/master/nginx.conf.template).
|
||||
- A `.env` file that you will need to **fill**. Look at the example [.env.example](https://raw.githubusercontent.com/zoriya/Kyoo/master/.env.example)
|
||||
|
||||
> If you want an explanation of what are those files, you can read the following:
|
||||
> The `docker-compose.yml` file describes the different services of Kyoo, where they should be downloaded and their start order. \
|
||||
> The `nignx.conf.template` file describes which service will be called when accessing the URL of Kyoo. \
|
||||
> The `.env` file contains all the configuration options that the services in `docker-compose.yml` will read.
|
||||
|
||||
To retrieve metadata, Kyoo will need to communicate with an external service. For now, that is `the movie database`.
|
||||
For this purpose, you will need to get an API Key. For that, go to [themoviedb.org](https://www.themoviedb.org/) and create an account, then
|
||||
go [here](https://www.themoviedb.org/settings/api) and copy the `API Key (v3 auth)`, paste it after the `THEMOVIEDB_APIKEY=` on the `.env` file.
|
||||
|
||||
If you need hardware acceleration, look at [Hardware Acceleration section](#Hardware-Acceleration) if you need it
|
||||
|
||||
The next and last step is actually starting Kyoo. To do that, open a terminal in the same directory as the 3 configurations files
|
||||
and run `docker-compose up -d`.
|
||||
|
||||
Congratulation, everything is now ready to use Kyoo. You can navigate to `http://localhost:8901` on a web browser to see your instance of Kyoo.
|
||||
|
||||
# Updating
|
||||
|
||||
Updating Kyoo is exactly the same as installing it. Get an updated version of the `docker-compose.yml` and `nginx.conf.template` files and
|
||||
unsure that your `.env` contains all the options specified in the updated `.env.example` file.
|
||||
|
||||
After that, you will need to update Kyoo's services. For that, open a terminal in the configuration's directory and run
|
||||
the command `docker-compose pull`. You are now ready to restart Kyoo, you can run `docker-compose up -d`.
|
||||
|
||||
You can also enable automatic updates via an external tool like [watchtower](https://containrrr.dev/watchtower/).
|
||||
TLDR: `docker run -d --name watchtower -e WATCHTOWER_CLEANUP=true -e WATCHTOWER_POLL_INTERVAL=86400 -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower`
|
||||
|
||||
# Uninstalling
|
||||
|
||||
To uninstall Kyoo, you need to open a terminal in the configuration's directory and run `docker-compose down`. This will
|
||||
stop Kyoo's services. You can then remove the configuration files.
|
||||
|
||||
# Hardware Acceleration
|
||||
|
||||
## VA-API (intel, amd)
|
||||
|
||||
First install necessary drivers on your system, when running `vainfo` you should have something like this:
|
||||
```
|
||||
libva info: VA-API version 1.20.0
|
||||
libva info: Trying to open /run/opengl-driver/lib/dri/iHD_drv_video.so
|
||||
libva info: Found init function __vaDriverInit_1_20
|
||||
libva info: va_openDriver() returns 0
|
||||
vainfo: VA-API version: 1.20 (libva 2.20.1)
|
||||
vainfo: Driver version: Intel iHD driver for Intel(R) Gen Graphics - 23.3.5 ()
|
||||
vainfo: Supported profile and entrypoints
|
||||
VAProfileH264Main : VAEntrypointVLD
|
||||
VAProfileH264Main : VAEntrypointEncSlice
|
||||
...Truncated...
|
||||
VAProfileHEVCSccMain444_10 : VAEntrypointVLD
|
||||
VAProfileHEVCSccMain444_10 : VAEntrypointEncSliceLP
|
||||
```
|
||||
Kyoo will default to use your primary card (located at `/dev/dri/renderD128`). If you need to specify a secondary one, you
|
||||
can use the `GOCODER_VAAPI_RENDERER` env-var to specify `/dev/dri/renderD129` or another one.
|
||||
|
||||
Then you can simply run kyoo using `docker compose --profile vaapi up -d` (notice the `--profile vaapi` added)
|
||||
You can also add `COMPOSE_PROFILES=vaapi` to your `.env` instead of adding the `--profile` flag.
|
||||
|
||||
## Nvidia
|
||||
|
||||
To enable nvidia hardware acceleration, first install necessary drivers on your system.
|
||||
|
||||
Then, install the [nvidia-container-toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html), you can simply
|
||||
follow the instructions on the official webpage or your distribution wiki.
|
||||
|
||||
To test if everything works, you can run `sudo docker run --rm --gpus all ubuntu nvidia-smi`. If your version of docker is older,
|
||||
you might need to add `--runtime nvidia` like so: `sudo docker run --rm --runtime=nvidia --gpus all ubuntu nvidia-smi`
|
||||
|
||||
After that, you can now use `docker compose --profile nvidia up -d` to start kyoo with nvidia hardware acceleration (notice the `--profile nvidia` added).
|
||||
You can also add `COMPOSE_PROFILES=nvidia` to your `.env` instead of adding the `--profile` flag.
|
||||
|
||||
Note that most nvidia cards have an artificial limit on the number of encodes. You can confirm your card limit [here](https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new).
|
||||
This limit can also be removed by applying an [unofficial patch](https://github.com/keylase/nvidia-patch) to you driver.
|
||||
44
PRIVACY.md
Normal file
44
PRIVACY.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# Privacy Policy for Kyoo
|
||||
|
||||
Effective Date: 2023-06-15
|
||||
|
||||
Thank you for using Kyoo. This Privacy Policy outlines how we collect, use, and protect your personal information when you use our service. We are committed to ensuring the privacy and security of your data. Please read this policy carefully to understand our practices regarding your information.
|
||||
|
||||
### 1. Information We Collect:
|
||||
|
||||
We collect and store only the email addresses you provide during the registration process. No other personal information is requested or stored.
|
||||
|
||||
### 2. Use of Personal Information:
|
||||
|
||||
We use your email address solely for the purpose of user authentication and login. We do not use, access, or share your email address with any third parties.
|
||||
|
||||
### 3. Data Storage and Security:
|
||||
|
||||
All personal information, limited to email addresses, is stored securely on our self-hosted servers. We take appropriate technical and organizational measures to protect against unauthorized access, alteration, disclosure, or destruction of your personal information.
|
||||
|
||||
### 4. Data Sharing:
|
||||
|
||||
We do not share any personal information, including email addresses, with any third parties. Your data remains confidential and is used only for the purposes stated in this Privacy Policy.
|
||||
|
||||
### 5. Account Deletion:
|
||||
|
||||
You have the right to delete your Kyoo account at any time. To do so, please click on the `Delete your account` button on the account's menu of the app/website. Upon account deletion, all associated personal information, including your email address, will be permanently and irreversibly removed from our servers.
|
||||
|
||||
### 6. Cookies and Tracking Technologies:
|
||||
|
||||
Kyoo does not use any cookies or tracking technologies to collect or store user information.
|
||||
|
||||
### 7. Legal Basis for Processing:
|
||||
|
||||
Our collection and processing of your email address is based on your consent, as it is necessary for the performance of the contract between you and Kyoo.
|
||||
|
||||
### 8. Changes to this Privacy Policy:
|
||||
|
||||
We may update this Privacy Policy from time to time. Any changes will be posted on this page, and the effective date will be indicated at the top of the policy. Please review this policy periodically for any updates.
|
||||
|
||||
### 9. Contact Us:
|
||||
|
||||
If you have any questions, concerns, or requests regarding this Privacy Policy or the processing of your personal information, please contact us at https://github.com/zoriya/kyoo/issues.
|
||||
|
||||
|
||||
By using Kyoo, you acknowledge and agree to the practices described in this Privacy Policy.
|
||||
130
README.md
130
README.md
@@ -1,94 +1,64 @@
|
||||
# <img width="24px" src="./icons/icon-256x256.png" alt="Kyoo"> Kyoo
|
||||
<p>
|
||||
<a href="https://github.com/AnonymusRaccoon/Kyoo/actions/workflows/build.yml"><img src="https://img.shields.io/github/workflow/status/AnonymusRaccoon/Kyoo/Build?style=flat-square" alt="Build status"></a>
|
||||
<a href="https://github.com/AnonymusRaccoon/Kyoo/actions/workflows/tests.yml"><img src="https://img.shields.io/github/workflow/status/AnonymusRaccoon/Kyoo/Testing?label=tests&style=flat-square" alt="Tests status"></a>
|
||||
<a href="https://github.com/users/AnonymusRaccoon/packages/container/package/kyoo"><img src="https://img.shields.io/github/workflow/status/AnonymusRaccoon/Kyoo/Docker?label=docker&style=flat-square" alt="Docker status"/></a>
|
||||
<a href="https://sonarcloud.io/dashboard?id=AnonymusRaccoon_Kyoo"><img src="https://img.shields.io/sonar/tests/AnonymusRaccoon_Kyoo?compact_message&server=https%3A%2F%2Fsonarcloud.io&style=flat-square" alt="Test report"></a>
|
||||
<a href="https://sonarcloud.io/dashboard?id=AnonymusRaccoon_Kyoo"><img src="https://img.shields.io/sonar/coverage/AnonymusRaccoon_Kyoo?server=https%3A%2F%2Fsonarcloud.io&style=flat-square" alt="Coverage"></a>
|
||||
<a href="./LICENSE"><img src="https://img.shields.io/github/license/AnonymusRaccoon/Kyoo?style=flat-square" alt="License"></a>
|
||||
</p>
|
||||
# <img width="24px" src="./icons/icon-256x256.png" alt=""> Kyoo
|
||||
|
||||
Kyoo is an open-source media browser which allow you to stream your movies, tv-shows or anime.
|
||||
It is an alternative to Plex, Emby or Jellyfin.
|
||||
Welcome to Kyoo, the next-generation open-source media browser that redefines your streaming experience. Designed from the ground up, Kyoo stands out as a powerful alternative to Plex and Jellyfin. Unleash the full potential of your media library with cutting-edge features and a commitment to being free and open-source.
|
||||
|
||||
Kyoo has been created from scratch, it is not a fork. Everything is and always will be free and open-source.
|
||||

|
||||
|
||||
Feel free to open issues or pull requests, all contribution are welcomed.
|
||||
## 🌐 Getting Started
|
||||
|
||||
## Getting started
|
||||
- **[Installation](./INSTALLING.md):** Set up Kyoo effortlessly to enjoy seamless streaming of your favorite movies, TV shows, or anime.
|
||||
- **[Join the discord](https://discord.gg/E6Apw3aFaA):** Join our Discord community for discussions and support
|
||||
- **[API Documentation](https://kyoo.zoriya.dev/api/doc):** Dive into our comprehensive API documentation to explore advanced functionalities.
|
||||
- **[Contributing](./CONTRIBUTING.md):** Feel free to open issues, submit pull requests, and contribute to making Kyoo even better.
|
||||
|
||||
- [Installation](https://docs.kyoo.moe/start/install.html)
|
||||
- [Setting Up](https://docs.kyoo.moe/start/setting_up.html)
|
||||
- [Api Documentation](https://demo.kyoo.moe/redoc)
|
||||
- [Documentation (work in progress)](https://docs.kyoo.moe)
|
||||
- [Contributing](./CONTRIBUTING.md)
|
||||
## 🚀 Features
|
||||
|
||||
## Features
|
||||
- Manage your movies, tv-series & anime
|
||||
- Download metadata automatically
|
||||
- Transmux files to make them available on every platform (Transcode coming soon)
|
||||
- Account system with a permission system
|
||||
- Handle subtitles natively with embedded fonts (ass, subrip or vtt)
|
||||
- Entirely free and works without internet (when metadata have already been downloaded)
|
||||
- Works on Linux, Windows, Docker and probably Mac
|
||||
- A powerful plugin system
|
||||
- **Dynamic Transcoding:** Transcode your media to any quality, change on the fly with auto quality, and seek effortlessly without waiting for the transcoder.
|
||||
|
||||
- **Auto Watch History:** Enjoy automatic watch history with continue watching, allowing you to quickly resume your series or discover new episodes.
|
||||
|
||||
## Live Demo
|
||||
- **Intelligent Metadata Retrieval:** Experience smart metadata retrieval, even for oddly named files, thanks to the power of guessit and themoviedb. It even uses thexem for enhanced anime handling.
|
||||
|
||||
You can see a live demo with copyright-free movies here: [demo.kyoo.moe](https://demo.kyoo.moe).
|
||||
Thanks to the [blender studio](https://www.blender.org/about/studio/) for providing open-source movies available for all.
|
||||
- **Cross-Platform Access:** Access Kyoo on Android and web clients, ensuring your media is at your fingertips wherever you go.
|
||||
|
||||
The demo server is simply created using the following docker compose:
|
||||
- **Meilisearch-Powered Search:** Utilize our advanced, typo-resilient search system powered by Meilisearch for lightning-fast results.
|
||||
|
||||
```yml
|
||||
version: "3.8"
|
||||
- **Fast Scrubbing Support:** Navigate your media effortlessly with fast scrubbing support, enhancing your control over playback.
|
||||
|
||||
services:
|
||||
kyoo:
|
||||
image: ghcr.io/anonymusraccoon/kyoo:master
|
||||
restart: on-failure
|
||||
environment:
|
||||
- KYOO_DATADIR=/var/lib/kyoo
|
||||
- DATABASE__ENABLED=postgres
|
||||
- DATABASE__CONFIGURATIONS__POSTGRES__SERVER=postgres
|
||||
- DATABASE__CONFIGURATIONS__POSTGRES__USER ID=kyoo
|
||||
- DATABASE__CONFIGURATIONS__POSTGRES__PASSWORD=kyooPassword
|
||||
- TVDB__APIKEY=TheTvDbApiKey
|
||||
- THE-MOVIEDB__APIKEY=TheMovieDbApiKey
|
||||
ports:
|
||||
- "80:5000"
|
||||
depends_on:
|
||||
- postgres
|
||||
volumes:
|
||||
- kyoo:/var/lib/kyoo
|
||||
- video:/video
|
||||
postgres:
|
||||
image: "postgres"
|
||||
restart: on-failure
|
||||
environment:
|
||||
- POSTGRES_USER=kyoo
|
||||
- POSTGRES_PASSWORD=kyooPassword
|
||||
volumes:
|
||||
- db:/var/lib/postgresql/data
|
||||
- **Download and Offline Support:** Enjoy the freedom to download and watch offline, with the watch history seamlessly updating when you reconnect.
|
||||
|
||||
volumes:
|
||||
kyoo:
|
||||
video:
|
||||
db:
|
||||
```
|
||||
- **Enhanced Subtitle Support:** Kyoo goes beyond the basics with enhanced subtitle support, including SSA/ASS formats and customizable fonts.
|
||||
|
||||
## Screens
|
||||
- **OIDC and Scrubbing Support:** Login with your favorites services (Google, Discord or any OIDC compliant service) and automatically mark episodes as watched on linked services (SIMKL and soon others).
|
||||
|
||||

|
||||
- - -
|
||||

|
||||
- - -
|
||||

|
||||
- - -
|
||||

|
||||
- - -
|
||||

|
||||
- - -
|
||||

|
||||
- - -
|
||||

|
||||
## 🌟 Philosophy: Setup Once, Enjoy Forever
|
||||
|
||||
Kyoo's philosophy revolves around simplicity. Set it up once, forget about configuration hassles. Once installed, your library undergoes automatic scanning, adding new episodes or movies as soon as they're moved into your library's folder. No need for a specific file structure or meticulously renamed files – Kyoo does the right thing™.
|
||||
|
||||
## 📜 Why another media-browser?
|
||||
|
||||
From a technical standpoint, both Jellyfin and Plex lean on SQLite and confine everything within a single container, Kyoo takes a different route. We're not afraid to bring in additional containers when it makes sense – whether for specialized features like Meilisearch powering our search system or for scalability, as seen with our transcoder.
|
||||
|
||||
Kyoo embraces the "setup once, forget about it" philosophy. Unlike Plex and Jellyfin, we don't burden you with manual file renaming or specific folder structures. Kyoo seamlessly works with files straight from your download directory, minimizing the maintenance headache for server admins.
|
||||
|
||||
Kyoo narrows its focus to movies, TV shows, and anime streaming. No music, ebooks, or games – just pure cinematic delight.
|
||||
|
||||
## 🔗 Live Demo
|
||||
|
||||
Curious to see Kyoo in action? Check out our live demo featuring copyright-free movies at [kyoo.zoriya.dev](https://kyoo.zoriya.dev). Special thanks to the Blender Studio for providing open-source movies available for all.
|
||||
|
||||
## 👀 Screens
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
<p align="center"><img src="https://raw.githubusercontent.com/zoriya/kyoo/screens/android-movie.png" alt="Android Movie" width="350"></p>
|
||||
|
||||
Ready to elevate your streaming experience? Dive into Kyoo now! 🎬🎉
|
||||
|
||||
1
autosync/.gitignore
vendored
Normal file
1
autosync/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
__pycache__
|
||||
8
autosync/Dockerfile
Normal file
8
autosync/Dockerfile
Normal file
@@ -0,0 +1,8 @@
|
||||
FROM python:3.12
|
||||
WORKDIR /app
|
||||
|
||||
COPY ./requirements.txt .
|
||||
RUN pip3 install -r ./requirements.txt
|
||||
|
||||
COPY . .
|
||||
ENTRYPOINT ["python3", "-m", "autosync"]
|
||||
66
autosync/autosync/__init__.py
Normal file
66
autosync/autosync/__init__.py
Normal file
@@ -0,0 +1,66 @@
|
||||
import logging
|
||||
import os
|
||||
|
||||
import dataclasses_json
|
||||
from datetime import datetime
|
||||
from marshmallow import fields
|
||||
|
||||
dataclasses_json.cfg.global_config.encoders[datetime] = datetime.isoformat
|
||||
dataclasses_json.cfg.global_config.decoders[datetime] = datetime.fromisoformat
|
||||
dataclasses_json.cfg.global_config.mm_fields[datetime] = fields.DateTime(format="iso")
|
||||
dataclasses_json.cfg.global_config.encoders[datetime | None] = datetime.isoformat
|
||||
dataclasses_json.cfg.global_config.decoders[datetime | None] = datetime.fromisoformat
|
||||
dataclasses_json.cfg.global_config.mm_fields[datetime | None] = fields.DateTime(
|
||||
format="iso"
|
||||
)
|
||||
|
||||
import pika
|
||||
from pika import spec
|
||||
from pika.adapters.blocking_connection import BlockingChannel
|
||||
import pika.credentials
|
||||
from autosync.models.message import Message
|
||||
from autosync.services.aggregate import Aggregate
|
||||
|
||||
from autosync.services.simkl import Simkl
|
||||
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
service = Aggregate([Simkl()])
|
||||
|
||||
|
||||
def on_message(
|
||||
ch: BlockingChannel,
|
||||
method: spec.Basic.Deliver,
|
||||
properties: spec.BasicProperties,
|
||||
body: bytes,
|
||||
):
|
||||
try:
|
||||
message = Message.from_json(body) # type: Message
|
||||
service.update(message.value.user, message.value.resource, message.value)
|
||||
except Exception as e:
|
||||
logging.exception("Error processing message.", exc_info=e)
|
||||
logging.exception("Body: %s", body)
|
||||
|
||||
|
||||
def main():
|
||||
connection = pika.BlockingConnection(
|
||||
pika.ConnectionParameters(
|
||||
host=os.environ.get("RABBITMQ_HOST", "rabbitmq"),
|
||||
credentials=pika.credentials.PlainCredentials(
|
||||
os.environ.get("RABBITMQ_DEFAULT_USER", "guest"),
|
||||
os.environ.get("RABBITMQ_DEFAULT_PASS", "guest"),
|
||||
),
|
||||
)
|
||||
)
|
||||
channel = connection.channel()
|
||||
|
||||
channel.exchange_declare(exchange="events.watched", exchange_type="topic")
|
||||
result = channel.queue_declare("", exclusive=True)
|
||||
queue_name = result.method.queue
|
||||
channel.queue_bind(exchange="events.watched", queue=queue_name, routing_key="#")
|
||||
|
||||
channel.basic_consume(
|
||||
queue=queue_name, on_message_callback=on_message, auto_ack=True
|
||||
)
|
||||
logging.info("Listening for autosync.")
|
||||
channel.start_consuming()
|
||||
4
autosync/autosync/__main__.py
Normal file
4
autosync/autosync/__main__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
import autosync
|
||||
|
||||
autosync.main()
|
||||
18
autosync/autosync/models/episode.py
Normal file
18
autosync/autosync/models/episode.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from typing import Literal
|
||||
from dataclasses import dataclass
|
||||
from dataclasses_json import dataclass_json, LetterCase
|
||||
|
||||
from autosync.models.show import Show
|
||||
|
||||
from .metadataid import MetadataID
|
||||
|
||||
|
||||
@dataclass_json(letter_case=LetterCase.CAMEL)
|
||||
@dataclass
|
||||
class Episode:
|
||||
external_id: dict[str, MetadataID]
|
||||
show: Show
|
||||
season_number: int
|
||||
episode_number: int
|
||||
absolute_number: int
|
||||
kind: Literal["episode"]
|
||||
23
autosync/autosync/models/message.py
Normal file
23
autosync/autosync/models/message.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from dataclasses import dataclass
|
||||
from dataclasses_json import dataclass_json, LetterCase
|
||||
|
||||
from autosync.models.episode import Episode
|
||||
from autosync.models.movie import Movie
|
||||
from autosync.models.show import Show
|
||||
from autosync.models.user import User
|
||||
from autosync.models.watch_status import WatchStatus
|
||||
|
||||
|
||||
@dataclass_json(letter_case=LetterCase.CAMEL)
|
||||
@dataclass
|
||||
class WatchStatusMessage(WatchStatus):
|
||||
user: User
|
||||
resource: Movie | Show | Episode
|
||||
|
||||
|
||||
@dataclass_json(letter_case=LetterCase.CAMEL)
|
||||
@dataclass
|
||||
class Message:
|
||||
action: str
|
||||
type: str
|
||||
value: WatchStatusMessage
|
||||
10
autosync/autosync/models/metadataid.py
Normal file
10
autosync/autosync/models/metadataid.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from dataclasses import dataclass
|
||||
from dataclasses_json import dataclass_json, LetterCase
|
||||
from typing import Optional
|
||||
|
||||
|
||||
@dataclass_json(letter_case=LetterCase.CAMEL)
|
||||
@dataclass
|
||||
class MetadataID:
|
||||
data_id: str
|
||||
link: Optional[str]
|
||||
19
autosync/autosync/models/movie.py
Normal file
19
autosync/autosync/models/movie.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from typing import Literal, Optional
|
||||
from datetime import datetime
|
||||
from dataclasses import dataclass
|
||||
from dataclasses_json import dataclass_json, LetterCase
|
||||
|
||||
from .metadataid import MetadataID
|
||||
|
||||
|
||||
@dataclass_json(letter_case=LetterCase.CAMEL)
|
||||
@dataclass
|
||||
class Movie:
|
||||
name: str
|
||||
air_date: Optional[datetime]
|
||||
external_id: dict[str, MetadataID]
|
||||
kind: Literal["movie"]
|
||||
|
||||
@property
|
||||
def year(self):
|
||||
return self.air_date.year if self.air_date is not None else None
|
||||
19
autosync/autosync/models/show.py
Normal file
19
autosync/autosync/models/show.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from typing import Literal, Optional
|
||||
from datetime import datetime
|
||||
from dataclasses import dataclass
|
||||
from dataclasses_json import dataclass_json, LetterCase
|
||||
|
||||
from .metadataid import MetadataID
|
||||
|
||||
|
||||
@dataclass_json(letter_case=LetterCase.CAMEL)
|
||||
@dataclass
|
||||
class Show:
|
||||
name: str
|
||||
start_air: Optional[datetime]
|
||||
external_id: dict[str, MetadataID]
|
||||
kind: Literal["show"]
|
||||
|
||||
@property
|
||||
def year(self):
|
||||
return self.start_air.year if self.start_air is not None else None
|
||||
34
autosync/autosync/models/user.py
Normal file
34
autosync/autosync/models/user.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from datetime import datetime, time
|
||||
from dataclasses import dataclass
|
||||
from dataclasses_json import dataclass_json, LetterCase
|
||||
from typing import Optional
|
||||
|
||||
|
||||
@dataclass_json(letter_case=LetterCase.CAMEL)
|
||||
@dataclass
|
||||
class JwtToken:
|
||||
token_type: str
|
||||
access_token: str
|
||||
refresh_token: Optional[str]
|
||||
expire_in: time
|
||||
expire_at: datetime
|
||||
|
||||
|
||||
@dataclass_json(letter_case=LetterCase.CAMEL)
|
||||
@dataclass
|
||||
class ExternalToken:
|
||||
id: str
|
||||
username: str
|
||||
profileUrl: Optional[str]
|
||||
token: JwtToken
|
||||
|
||||
|
||||
@dataclass_json(letter_case=LetterCase.CAMEL)
|
||||
@dataclass
|
||||
class User:
|
||||
id: str
|
||||
username: str
|
||||
email: str
|
||||
permissions: list[str]
|
||||
settings: dict[str, str]
|
||||
external_id: dict[str, ExternalToken]
|
||||
23
autosync/autosync/models/watch_status.py
Normal file
23
autosync/autosync/models/watch_status.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from datetime import datetime
|
||||
from dataclasses import dataclass
|
||||
from dataclasses_json import dataclass_json, LetterCase
|
||||
from typing import Optional
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class Status(str, Enum):
|
||||
COMPLETED = "Completed"
|
||||
WATCHING = "Watching"
|
||||
DROPED = "Droped"
|
||||
PLANNED = "Planned"
|
||||
DELETED = "Deleted"
|
||||
|
||||
|
||||
@dataclass_json(letter_case=LetterCase.CAMEL)
|
||||
@dataclass
|
||||
class WatchStatus:
|
||||
added_date: datetime
|
||||
played_date: Optional[datetime]
|
||||
status: Status
|
||||
watched_time: Optional[int]
|
||||
watched_percent: Optional[int]
|
||||
26
autosync/autosync/services/aggregate.py
Normal file
26
autosync/autosync/services/aggregate.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import logging
|
||||
from autosync.services.service import Service
|
||||
from ..models.user import User
|
||||
from ..models.show import Show
|
||||
from ..models.movie import Movie
|
||||
from ..models.episode import Episode
|
||||
from ..models.watch_status import WatchStatus
|
||||
|
||||
|
||||
class Aggregate(Service):
|
||||
def __init__(self, services: list[Service]):
|
||||
self._services = [x for x in services if x.enabled]
|
||||
logging.info("Autosync enabled with %s", [x.name for x in self._services])
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return "aggragate"
|
||||
|
||||
def update(self, user: User, resource: Movie | Show | Episode, status: WatchStatus):
|
||||
for service in self._services:
|
||||
try:
|
||||
service.update(user, resource, status)
|
||||
except Exception as e:
|
||||
logging.exception(
|
||||
"Unhandled error on autosync %s:", service.name, exc_info=e
|
||||
)
|
||||
21
autosync/autosync/services/service.py
Normal file
21
autosync/autosync/services/service.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from abc import abstractmethod, abstractproperty
|
||||
|
||||
from ..models.user import User
|
||||
from ..models.show import Show
|
||||
from ..models.movie import Movie
|
||||
from ..models.episode import Episode
|
||||
from ..models.watch_status import WatchStatus
|
||||
|
||||
|
||||
class Service:
|
||||
@abstractproperty
|
||||
def name(self) -> str:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractproperty
|
||||
def enabled(self) -> bool:
|
||||
return True
|
||||
|
||||
@abstractmethod
|
||||
def update(self, user: User, resource: Movie | Show | Episode, status: WatchStatus):
|
||||
raise NotImplementedError
|
||||
115
autosync/autosync/services/simkl.py
Normal file
115
autosync/autosync/services/simkl.py
Normal file
@@ -0,0 +1,115 @@
|
||||
import os
|
||||
import requests
|
||||
import logging
|
||||
from autosync.models.metadataid import MetadataID
|
||||
|
||||
from autosync.services.service import Service
|
||||
from ..models.user import User
|
||||
from ..models.show import Show
|
||||
from ..models.movie import Movie
|
||||
from ..models.episode import Episode
|
||||
from ..models.watch_status import WatchStatus, Status
|
||||
|
||||
|
||||
class Simkl(Service):
|
||||
def __init__(self) -> None:
|
||||
self._api_key = os.environ.get("OIDC_SIMKL_CLIENTID")
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return "simkl"
|
||||
|
||||
@property
|
||||
def enabled(self) -> bool:
|
||||
return self._api_key is not None
|
||||
|
||||
def update(self, user: User, resource: Movie | Show | Episode, status: WatchStatus):
|
||||
if "simkl" not in user.external_id or self._api_key is None:
|
||||
return
|
||||
|
||||
watch_date = status.played_date or status.added_date
|
||||
|
||||
if resource.kind == "episode":
|
||||
if status.status != Status.COMPLETED:
|
||||
return
|
||||
|
||||
resp = requests.post(
|
||||
"https://api.simkl.com/sync/history",
|
||||
json={
|
||||
"shows": [
|
||||
{
|
||||
"watched_at": watch_date.isoformat(),
|
||||
"title": resource.show.name,
|
||||
"year": resource.show.year,
|
||||
"ids": self._map_external_ids(resource.show.external_id),
|
||||
"seasons": [
|
||||
{
|
||||
"number": resource.season_number,
|
||||
"episodes": [{"number": resource.episode_number}],
|
||||
},
|
||||
{
|
||||
"number": 1,
|
||||
"episodes": [{"number": resource.absolute_number}],
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
},
|
||||
headers={
|
||||
"Authorization": f"Bearer {user.external_id["simkl"].token.access_token}",
|
||||
"simkl-api-key": self._api_key,
|
||||
},
|
||||
)
|
||||
logging.info("Simkl response: %s %s", resp.status_code, resp.text)
|
||||
return
|
||||
|
||||
category = "movies" if resource.kind == "movie" else "shows"
|
||||
|
||||
simkl_status = self._map_status(status.status)
|
||||
if simkl_status is None:
|
||||
return
|
||||
|
||||
resp = requests.post(
|
||||
"https://api.simkl.com/sync/add-to-list",
|
||||
json={
|
||||
category: [
|
||||
{
|
||||
"to": simkl_status,
|
||||
"watched_at": watch_date.isoformat()
|
||||
if status.status == Status.COMPLETED
|
||||
else None,
|
||||
"title": resource.name,
|
||||
"year": resource.year,
|
||||
"ids": self._map_external_ids(resource.external_id),
|
||||
}
|
||||
]
|
||||
},
|
||||
headers={
|
||||
"Authorization": f"Bearer {user.external_id["simkl"].token.access_token}",
|
||||
"simkl-api-key": self._api_key,
|
||||
},
|
||||
)
|
||||
logging.info("Simkl response: %s %s", resp.status_code, resp.text)
|
||||
|
||||
def _map_status(self, status: Status):
|
||||
match status:
|
||||
case Status.COMPLETED:
|
||||
return "completed"
|
||||
case Status.WATCHING:
|
||||
return "watching"
|
||||
case Status.COMPLETED:
|
||||
return "completed"
|
||||
case Status.PLANNED:
|
||||
return "plantowatch"
|
||||
case Status.DELETED:
|
||||
# do not delete items on simkl, most of deleted status are for a rewatch.
|
||||
return None
|
||||
case _:
|
||||
return None
|
||||
|
||||
def _map_external_ids(self, ids: dict[str, MetadataID]):
|
||||
return {service: id.data_id for service, id in ids.items()} | {
|
||||
"tmdb": int(ids["themoviedatabase"].data_id)
|
||||
if "themoviedatabase" in ids
|
||||
else None
|
||||
}
|
||||
2
autosync/pyproject.toml
Normal file
2
autosync/pyproject.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[tool.ruff.format]
|
||||
indent-style = "tab"
|
||||
3
autosync/requirements.txt
Normal file
3
autosync/requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
pika
|
||||
requests
|
||||
dataclasses-json
|
||||
18
back/.config/dotnet-tools.json
Normal file
18
back/.config/dotnet-tools.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "8.0.3",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
]
|
||||
},
|
||||
"csharpier": {
|
||||
"version": "0.27.2",
|
||||
"commands": [
|
||||
"dotnet-csharpier"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,17 @@
|
||||
Dockerfile
|
||||
Dockerfile.dev
|
||||
Dockerfile.*
|
||||
.dockerignore
|
||||
.gitignore
|
||||
docker-compose.yml
|
||||
README.md
|
||||
**/build
|
||||
**/dist
|
||||
src/Kyoo.WebApp/Front/nodes_modules
|
||||
**/bin
|
||||
**/obj
|
||||
out
|
||||
docs
|
||||
tests
|
||||
!tests/Kyoo.Tests/Kyoo.Tests.csproj
|
||||
front
|
||||
video
|
||||
nginx.conf.template
|
||||
|
||||
@@ -11,11 +11,13 @@ smart_tab = true
|
||||
|
||||
[*.cs]
|
||||
csharp_prefer_braces = false
|
||||
dotnet_diagnostic.IDE0130.severity = none
|
||||
dotnet_diagnostic.IDE0058.severity = none
|
||||
dotnet_diagnostic.IDE0046.severity = none
|
||||
dotnet_diagnostic.CA1848.severity = none
|
||||
dotnet_diagnostic.CA2007.severity = none
|
||||
dotnet_diagnostic.IDE0055.severity = none
|
||||
dotnet_diagnostic.IDE0058.severity = none
|
||||
dotnet_diagnostic.IDE0130.severity = none
|
||||
|
||||
# Convert to file-scoped namespace
|
||||
csharp_style_namespace_declarations = file_scoped:warning
|
||||
# Sort using and Import directives with System.* appearing first
|
||||
dotnet_sort_system_directives_first = true
|
||||
csharp_using_directive_placement = outside_namespace:warning
|
||||
@@ -43,9 +45,9 @@ dotnet_style_prefer_conditional_expression_over_return = true
|
||||
# Disable strange throw.
|
||||
csharp_style_throw_expression = false:suggestion
|
||||
# Forbid "var" everywhere
|
||||
csharp_style_var_for_built_in_types = false:warning
|
||||
csharp_style_var_when_type_is_apparent = false:warning
|
||||
csharp_style_var_elsewhere = false:warning
|
||||
csharp_style_var_for_built_in_types = false:suggestion
|
||||
csharp_style_var_when_type_is_apparent = false:suggestion
|
||||
csharp_style_var_elsewhere = false:suggestion
|
||||
# Prefer method-like constructs to have a block body
|
||||
csharp_style_expression_bodied_methods = false:none
|
||||
csharp_style_expression_bodied_constructors = false:none
|
||||
@@ -89,6 +91,9 @@ resharper_wrap_before_arrow_with_expressions = true
|
||||
resharper_xmldoc_attribute_indent = align_by_first_attribute
|
||||
resharper_xmldoc_indent_child_elements = RemoveIndent
|
||||
resharper_xmldoc_indent_text = RemoveIndent
|
||||
# Switch on enum
|
||||
dotnet_diagnostic.CS8509.severity=error # missing switch case for named enum value
|
||||
dotnet_diagnostic.CS8524.severity=none # missing switch case for unnamed enum value
|
||||
|
||||
# Waiting for https://github.com/dotnet/roslyn/issues/44596 to get fixed.
|
||||
# file_header_template = Kyoo - A portable and vast media library solution.\nCopyright (c) Kyoo.\n\nSee AUTHORS.md and LICENSE file in the project root for full license information.\n\nKyoo is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\nany later version.\n\nKyoo is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
2
back/.gitignore
vendored
2
back/.gitignore
vendored
@@ -2,6 +2,7 @@ out
|
||||
libtranscoder.so
|
||||
libtranscoder.dylib
|
||||
transcoder.dll
|
||||
kyoo_datadir
|
||||
|
||||
video
|
||||
.env
|
||||
@@ -80,7 +81,6 @@ StyleCopReport.xml
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
|
||||
@@ -1,37 +1,30 @@
|
||||
FROM gcc:latest as transcoder
|
||||
RUN apt-get update && apt-get install -y cmake make libavutil-dev libavcodec-dev libavformat-dev
|
||||
WORKDIR /transcoder
|
||||
COPY src/Kyoo.Transcoder .
|
||||
RUN cmake . && make -j
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 as builder
|
||||
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 as builder
|
||||
ARG TARGETARCH
|
||||
WORKDIR /kyoo
|
||||
|
||||
COPY Kyoo.sln ./Kyoo.sln
|
||||
COPY nuget.config ./nuget.config
|
||||
COPY src/Directory.Build.props src/Directory.Build.props
|
||||
COPY src/Kyoo.Authentication/Kyoo.Authentication.csproj src/Kyoo.Authentication/Kyoo.Authentication.csproj
|
||||
COPY src/Kyoo.Database/Kyoo.Database.csproj src/Kyoo.Database/Kyoo.Database.csproj
|
||||
COPY src/Kyoo.Host.Generic/Kyoo.Host.Generic.csproj src/Kyoo.Host.Generic/Kyoo.Host.Generic.csproj
|
||||
COPY src/Kyoo.SqLite/Kyoo.SqLite.csproj src/Kyoo.SqLite/Kyoo.SqLite.csproj
|
||||
COPY src/Kyoo.TheMovieDb/Kyoo.TheMovieDb.csproj src/Kyoo.TheMovieDb/Kyoo.TheMovieDb.csproj
|
||||
COPY src/Kyoo.Abstractions/Kyoo.Abstractions.csproj src/Kyoo.Abstractions/Kyoo.Abstractions.csproj
|
||||
COPY src/Kyoo.Core/Kyoo.Core.csproj src/Kyoo.Core/Kyoo.Core.csproj
|
||||
COPY src/Kyoo.Host.Console/Kyoo.Host.Console.csproj src/Kyoo.Host.Console/Kyoo.Host.Console.csproj
|
||||
COPY src/Kyoo.Host/Kyoo.Host.csproj src/Kyoo.Host/Kyoo.Host.csproj
|
||||
COPY src/Kyoo.Postgresql/Kyoo.Postgresql.csproj src/Kyoo.Postgresql/Kyoo.Postgresql.csproj
|
||||
COPY src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj
|
||||
COPY src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj
|
||||
COPY src/Kyoo.Swagger/Kyoo.Swagger.csproj src/Kyoo.Swagger/Kyoo.Swagger.csproj
|
||||
COPY src/Kyoo.TheTvdb/Kyoo.TheTvdb.csproj src/Kyoo.TheTvdb/Kyoo.TheTvdb.csproj
|
||||
COPY tests/Kyoo.Tests/Kyoo.Tests.csproj tests/Kyoo.Tests/Kyoo.Tests.csproj
|
||||
RUN dotnet restore
|
||||
RUN dotnet restore -a $TARGETARCH
|
||||
|
||||
COPY . .
|
||||
ARG VERSION
|
||||
RUN dotnet publish --no-restore -c Release -o /opt/kyoo "-p:Version=${VERSION:-"0.0.0-dev"};SkipTranscoder=true" src/Kyoo.Host.Console
|
||||
RUN dotnet publish -a $TARGETARCH --no-restore -c Release -o /app "-p:Version=${VERSION:-"0.0.0-dev"}" src/Kyoo.Host
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:6.0
|
||||
RUN apt-get update && apt-get install -y libavutil-dev libavcodec-dev libavformat-dev
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0
|
||||
RUN apt-get update && apt-get install -y curl
|
||||
COPY --from=builder /app /app
|
||||
|
||||
WORKDIR /kyoo
|
||||
EXPOSE 5000
|
||||
COPY --from=builder /opt/kyoo /usr/lib/kyoo
|
||||
COPY --from=transcoder /transcoder/libtranscoder.so /usr/lib/kyoo
|
||||
CMD ["/usr/lib/kyoo/Kyoo.Host.Console"]
|
||||
|
||||
# The back can take a long time to start if meilisearch is initializing
|
||||
HEALTHCHECK --interval=5s --retries=15 CMD curl --fail http://localhost:5000/health || exit
|
||||
ENTRYPOINT ["/app/Kyoo.Host"]
|
||||
|
||||
@@ -1,35 +1,23 @@
|
||||
FROM gcc:latest as transcoder
|
||||
RUN apt-get update && apt-get install -y cmake make libavutil-dev libavcodec-dev libavformat-dev
|
||||
WORKDIR /transcoder
|
||||
COPY src/Kyoo.Transcoder .
|
||||
RUN cmake . && make -j
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0
|
||||
RUN apt-get update && apt-get install -y libavutil-dev libavcodec-dev libavformat-dev
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0
|
||||
RUN apt-get update && apt-get install -y curl
|
||||
WORKDIR /app
|
||||
|
||||
|
||||
COPY Kyoo.sln ./Kyoo.sln
|
||||
COPY nuget.config ./nuget.config
|
||||
COPY src/Directory.Build.props src/Directory.Build.props
|
||||
COPY src/Kyoo.Authentication/Kyoo.Authentication.csproj src/Kyoo.Authentication/Kyoo.Authentication.csproj
|
||||
COPY src/Kyoo.Database/Kyoo.Database.csproj src/Kyoo.Database/Kyoo.Database.csproj
|
||||
COPY src/Kyoo.Host.Generic/Kyoo.Host.Generic.csproj src/Kyoo.Host.Generic/Kyoo.Host.Generic.csproj
|
||||
COPY src/Kyoo.SqLite/Kyoo.SqLite.csproj src/Kyoo.SqLite/Kyoo.SqLite.csproj
|
||||
COPY src/Kyoo.TheMovieDb/Kyoo.TheMovieDb.csproj src/Kyoo.TheMovieDb/Kyoo.TheMovieDb.csproj
|
||||
COPY src/Kyoo.Abstractions/Kyoo.Abstractions.csproj src/Kyoo.Abstractions/Kyoo.Abstractions.csproj
|
||||
COPY src/Kyoo.Core/Kyoo.Core.csproj src/Kyoo.Core/Kyoo.Core.csproj
|
||||
COPY src/Kyoo.Host.Console/Kyoo.Host.Console.csproj src/Kyoo.Host.Console/Kyoo.Host.Console.csproj
|
||||
COPY src/Kyoo.Host/Kyoo.Host.csproj src/Kyoo.Host/Kyoo.Host.csproj
|
||||
COPY src/Kyoo.Postgresql/Kyoo.Postgresql.csproj src/Kyoo.Postgresql/Kyoo.Postgresql.csproj
|
||||
COPY src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj
|
||||
COPY src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj
|
||||
COPY src/Kyoo.Swagger/Kyoo.Swagger.csproj src/Kyoo.Swagger/Kyoo.Swagger.csproj
|
||||
COPY src/Kyoo.TheTvdb/Kyoo.TheTvdb.csproj src/Kyoo.TheTvdb/Kyoo.TheTvdb.csproj
|
||||
COPY tests/Kyoo.Tests/Kyoo.Tests.csproj tests/Kyoo.Tests/Kyoo.Tests.csproj
|
||||
|
||||
RUN dotnet restore
|
||||
|
||||
COPY --from=transcoder /transcoder/libtranscoder.so /usr/lib/
|
||||
|
||||
WORKDIR /kyoo
|
||||
EXPOSE 5000
|
||||
ENV DOTNET_USE_POLLING_FILE_WATCHER 1
|
||||
CMD ["dotnet", "watch", "run", "--no-restore", "--project", "src/Kyoo.Host.Console"]
|
||||
|
||||
# HEALTHCHECK --interval=5s CMD curl --fail http://localhost:5000/health || exit
|
||||
HEALTHCHECK CMD true
|
||||
ENTRYPOINT ["dotnet", "watch", "--non-interactive", "run", "--no-restore", "--project", "/app/src/Kyoo.Host"]
|
||||
|
||||
28
back/Dockerfile.migrations
Normal file
28
back/Dockerfile.migrations
Normal file
@@ -0,0 +1,28 @@
|
||||
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 as builder
|
||||
ARG TARGETARCH
|
||||
WORKDIR /kyoo
|
||||
|
||||
COPY .config/dotnet-tools.json .config/dotnet-tools.json
|
||||
RUN dotnet tool restore
|
||||
|
||||
COPY Kyoo.sln ./Kyoo.sln
|
||||
COPY nuget.config ./nuget.config
|
||||
COPY src/Directory.Build.props src/Directory.Build.props
|
||||
COPY src/Kyoo.Authentication/Kyoo.Authentication.csproj src/Kyoo.Authentication/Kyoo.Authentication.csproj
|
||||
COPY src/Kyoo.Abstractions/Kyoo.Abstractions.csproj src/Kyoo.Abstractions/Kyoo.Abstractions.csproj
|
||||
COPY src/Kyoo.Core/Kyoo.Core.csproj src/Kyoo.Core/Kyoo.Core.csproj
|
||||
COPY src/Kyoo.Host/Kyoo.Host.csproj src/Kyoo.Host/Kyoo.Host.csproj
|
||||
COPY src/Kyoo.Postgresql/Kyoo.Postgresql.csproj src/Kyoo.Postgresql/Kyoo.Postgresql.csproj
|
||||
COPY src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj
|
||||
COPY src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj
|
||||
COPY src/Kyoo.Swagger/Kyoo.Swagger.csproj src/Kyoo.Swagger/Kyoo.Swagger.csproj
|
||||
RUN dotnet restore -a $TARGETARCH
|
||||
|
||||
COPY . .
|
||||
RUN dotnet build
|
||||
RUN dotnet ef migrations bundle --no-build --self-contained -r linux-${TARGETARCH} -f -o /app/migrate -p src/Kyoo.Postgresql --verbose
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/runtime-deps:8.0
|
||||
COPY --from=builder /app/migrate /app/migrate
|
||||
|
||||
ENTRYPOINT /app/migrate --connection "USER ID=${POSTGRES_USER};PASSWORD=${POSTGRES_PASSWORD};SERVER=postgres;PORT=5432;DATABASE=${POSTGRES_DB};"
|
||||
@@ -2,6 +2,7 @@
|
||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.CSharp.MaintainabilityRules">
|
||||
<Rule Id="SA1413" Action="None" /> <!-- UseTrailingCommasInMultiLineInitializers -->
|
||||
<Rule Id="SA1414" Action="None" /> <!-- UseTrailingCommasInMultiLineInitializers -->
|
||||
<Rule Id="SA1114" Action="None" /> <!-- UseTrailingCommasInMultiLineInitializers -->
|
||||
</Rules>
|
||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.CSharp.OrderingRules">
|
||||
<Rule Id="SA1201" Action="None" /> <!-- ElementsMustAppearInTheCorrectOrder -->
|
||||
@@ -27,18 +28,20 @@
|
||||
<Rule Id="SA1027" Action="None"/> <!-- UseTabsCorrectly (smarts tabs are broken). TODO find a way to enable smart tabs -->
|
||||
</Rules>
|
||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.CSharp.LayoutRules">
|
||||
<Rule Id="SA1402" Action="None"/> <!-- SingleClassPerFile -->
|
||||
<Rule Id="SA1649" Action="None"/> <!-- Class name must be filename -->
|
||||
<Rule Id="SA1503" Action="None"/> <!-- BracesMustNotBeOmitted -->
|
||||
<Rule Id="SA1512" Action="None"/> <!-- Let me comment -->
|
||||
<Rule Id="SA1520" Action="None"/> <!-- UseBracesConsistently -->
|
||||
<Rule Id="SA1515" Action="None"/> <!-- SingleLineCommentMustBePrecededByBlankLine -->
|
||||
<Rule Id="SA1513" Action="None"/> <!-- ClosingBraceMustBeFollowedByBlankLine -->
|
||||
</Rules>
|
||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.CSharp.DocumentationRules">
|
||||
<Rule Id="SA1600" Action="None" /> <!-- Elements Shuld be Documented -->
|
||||
<Rule Id="SA1602" Action="None" /> <!-- Enums should be documented -->
|
||||
<Rule Id="SA1642" Action="None" /> <!-- ConstructorSummaryDocumentationMustBeginWithStandardText -->
|
||||
<Rule Id="SA1643" Action="None" /> <!-- DestructorSummaryDocumentationMustBeginWithStandardText -->
|
||||
<Rule Id="SA1623" Action="None" /> <!-- PropertySummaryDocumentationMustMatchAccessors -->
|
||||
|
||||
|
||||
|
||||
<Rule Id="SA1629" Action="None" /> <!-- DocumentationTextMustEndWithAPeriod TODO remove this, this is only temporary -->
|
||||
<Rule Id="SA1629" Action="None" /> <!-- DocumentationTextMustEndWithAPeriod -->
|
||||
</Rules>
|
||||
</RuleSet>
|
||||
|
||||
@@ -1,35 +1,20 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
#
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kyoo.Core", "src\Kyoo.Core\Kyoo.Core.csproj", "{0F8275B6-C7DD-42DF-A168-755C81B1C329}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Abstractions", "src\Kyoo.Abstractions\Kyoo.Abstractions.csproj", "{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Database", "src\Kyoo.Database\Kyoo.Database.csproj", "{6F91B645-F785-46BB-9C4F-1EFC83E489B6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Postgresql", "src\Kyoo.Postgresql\Kyoo.Postgresql.csproj", "{3213C96D-0BF3-460B-A8B5-B9977229408A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Authentication", "src\Kyoo.Authentication\Kyoo.Authentication.csproj", "{7A841335-6523-47DB-9717-80AA7BD943FD}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.SqLite", "src\Kyoo.SqLite\Kyoo.SqLite.csproj", "{6515380E-1E57-42DA-B6E3-E1C8A848818A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.TheTvdb", "src\Kyoo.TheTvdb\Kyoo.TheTvdb.csproj", "{D06BF829-23F5-40F3-A62D-627D9F4B4D6C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.TheMovieDb", "src\Kyoo.TheMovieDb\Kyoo.TheMovieDb.csproj", "{BAB270D4-E0EA-4329-BA65-512FDAB01001}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Tests", "tests\Kyoo.Tests\Kyoo.Tests.csproj", "{0C8AA7EA-E723-4532-852F-35AA4E8AFED5}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Host.Console", "src\Kyoo.Host.Console\Kyoo.Host.Console.csproj", "{D8658BEA-8949-45AC-BEBB-A4FFC4F800F5}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Swagger", "src\Kyoo.Swagger\Kyoo.Swagger.csproj", "{7D1A7596-73F6-4D35-842E-A5AD9C620596}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{FEAE1B0E-D797-470F-9030-0EF743575ECC}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Host", "src\Kyoo.Host\Kyoo.Host.csproj", "{0938459E-2E2B-457F-8120-7D8CA93866A6}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Providers", "Providers", "{8D28F5EF-0CD7-4697-A2A7-24EC31A48F21}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Meilisearch", "src\Kyoo.Meilisearch\Kyoo.Meilisearch.csproj", "{F8E6018A-FD51-40EB-99FF-A26BA59F2762}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Databases", "Databases", "{865461CA-EC06-4B42-91CF-8723B0A9BB67}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Hosts", "Hosts", "{C569FF25-7E01-484C-9F72-5B99845AD94B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Host.Generic", "src\Kyoo.Host.Generic\Kyoo.Host.Generic.csproj", "{0938459E-2E2B-457F-8120-7D8CA93866A6}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.RabbitMq", "src\Kyoo.RabbitMq\Kyoo.RabbitMq.csproj", "{B97AD4A8-E6E6-41CD-87DF-5F1326FD7198}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -45,10 +30,6 @@ Global
|
||||
{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6F91B645-F785-46BB-9C4F-1EFC83E489B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6F91B645-F785-46BB-9C4F-1EFC83E489B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6F91B645-F785-46BB-9C4F-1EFC83E489B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6F91B645-F785-46BB-9C4F-1EFC83E489B6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3213C96D-0BF3-460B-A8B5-B9977229408A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3213C96D-0BF3-460B-A8B5-B9977229408A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3213C96D-0BF3-460B-A8B5-B9977229408A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@@ -61,18 +42,6 @@ Global
|
||||
{6515380E-1E57-42DA-B6E3-E1C8A848818A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6515380E-1E57-42DA-B6E3-E1C8A848818A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6515380E-1E57-42DA-B6E3-E1C8A848818A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D06BF829-23F5-40F3-A62D-627D9F4B4D6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D06BF829-23F5-40F3-A62D-627D9F4B4D6C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D06BF829-23F5-40F3-A62D-627D9F4B4D6C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D06BF829-23F5-40F3-A62D-627D9F4B4D6C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BAB270D4-E0EA-4329-BA65-512FDAB01001}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BAB270D4-E0EA-4329-BA65-512FDAB01001}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BAB270D4-E0EA-4329-BA65-512FDAB01001}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BAB270D4-E0EA-4329-BA65-512FDAB01001}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0C8AA7EA-E723-4532-852F-35AA4E8AFED5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0C8AA7EA-E723-4532-852F-35AA4E8AFED5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0C8AA7EA-E723-4532-852F-35AA4E8AFED5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0C8AA7EA-E723-4532-852F-35AA4E8AFED5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2374D500-1ADB-4752-85DB-8BB0DDF5A8E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2374D500-1ADB-4752-85DB-8BB0DDF5A8E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2374D500-1ADB-4752-85DB-8BB0DDF5A8E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@@ -81,10 +50,6 @@ Global
|
||||
{4FF1ECD9-6EEF-4440-B037-A661D78FB04D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4FF1ECD9-6EEF-4440-B037-A661D78FB04D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4FF1ECD9-6EEF-4440-B037-A661D78FB04D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D8658BEA-8949-45AC-BEBB-A4FFC4F800F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D8658BEA-8949-45AC-BEBB-A4FFC4F800F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D8658BEA-8949-45AC-BEBB-A4FFC4F800F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D8658BEA-8949-45AC-BEBB-A4FFC4F800F5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7D1A7596-73F6-4D35-842E-A5AD9C620596}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7D1A7596-73F6-4D35-842E-A5AD9C620596}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7D1A7596-73F6-4D35-842E-A5AD9C620596}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@@ -93,15 +58,13 @@ Global
|
||||
{0938459E-2E2B-457F-8120-7D8CA93866A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0938459E-2E2B-457F-8120-7D8CA93866A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0938459E-2E2B-457F-8120-7D8CA93866A6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{0C8AA7EA-E723-4532-852F-35AA4E8AFED5} = {FEAE1B0E-D797-470F-9030-0EF743575ECC}
|
||||
{BAB270D4-E0EA-4329-BA65-512FDAB01001} = {8D28F5EF-0CD7-4697-A2A7-24EC31A48F21}
|
||||
{D06BF829-23F5-40F3-A62D-627D9F4B4D6C} = {8D28F5EF-0CD7-4697-A2A7-24EC31A48F21}
|
||||
{6F91B645-F785-46BB-9C4F-1EFC83E489B6} = {865461CA-EC06-4B42-91CF-8723B0A9BB67}
|
||||
{3213C96D-0BF3-460B-A8B5-B9977229408A} = {865461CA-EC06-4B42-91CF-8723B0A9BB67}
|
||||
{6515380E-1E57-42DA-B6E3-E1C8A848818A} = {865461CA-EC06-4B42-91CF-8723B0A9BB67}
|
||||
{D8658BEA-8949-45AC-BEBB-A4FFC4F800F5} = {C569FF25-7E01-484C-9F72-5B99845AD94B}
|
||||
{0938459E-2E2B-457F-8120-7D8CA93866A6} = {C569FF25-7E01-484C-9F72-5B99845AD94B}
|
||||
{F8E6018A-FD51-40EB-99FF-A26BA59F2762}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F8E6018A-FD51-40EB-99FF-A26BA59F2762}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F8E6018A-FD51-40EB-99FF-A26BA59F2762}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F8E6018A-FD51-40EB-99FF-A26BA59F2762}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B97AD4A8-E6E6-41CD-87DF-5F1326FD7198}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B97AD4A8-E6E6-41CD-87DF-5F1326FD7198}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B97AD4A8-E6E6-41CD-87DF-5F1326FD7198}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B97AD4A8-E6E6-41CD-87DF-5F1326FD7198}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
4
back/ef.rsp
Normal file
4
back/ef.rsp
Normal file
@@ -0,0 +1,4 @@
|
||||
--project
|
||||
src/Kyoo.Postgresql/Kyoo.Postgresql.csproj
|
||||
--msbuildprojectextensionspath
|
||||
out/obj/Kyoo.Postgresql
|
||||
@@ -1,13 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<clear/>
|
||||
<add key="nuget" value="https://api.nuget.org/v3/index.json"/>
|
||||
</packageSources>
|
||||
<disabledPackageSources>
|
||||
<clear/>
|
||||
</disabledPackageSources>
|
||||
<fallbackPackageFolders>
|
||||
<clear/>
|
||||
</fallbackPackageFolders>
|
||||
<packageSources>
|
||||
<clear/>
|
||||
<add key="feedz" value="https://f.feedz.io/zoriya/entityframeworkcore-projectables/nuget/index.json"/>
|
||||
<add key="nuget" value="https://api.nuget.org/v3/index.json"/>
|
||||
</packageSources>
|
||||
<disabledPackageSources>
|
||||
<clear/>
|
||||
</disabledPackageSources>
|
||||
<fallbackPackageFolders>
|
||||
<clear/>
|
||||
</fallbackPackageFolders>
|
||||
</configuration>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<LangVersion>default</LangVersion>
|
||||
<Company>Kyoo</Company>
|
||||
<Authors>Kyoo</Authors>
|
||||
@@ -9,10 +9,10 @@
|
||||
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
|
||||
<RequireLicenseAcceptance>true</RequireLicenseAcceptance>
|
||||
|
||||
<RepositoryUrl>https://github.com/AnonymusRaccoon/Kyoo</RepositoryUrl>
|
||||
<RepositoryUrl>https://github.com/zoriya/Kyoo</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<PackageProjectUrl>https://github.com/AnonymusRaccoon/Kyoo</PackageProjectUrl>
|
||||
<PackageProjectUrl>https://github.com/zoriya/Kyoo</PackageProjectUrl>
|
||||
|
||||
<PackageVersion>1.0.0</PackageVersion>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@@ -24,18 +24,6 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<BaseIntermediateOutputPath>$(MsBuildThisFileDirectory)/../out/obj/$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||
<BaseOutputPath>$(MsBuildThisFileDirectory)/../out/bin/$(MSBuildProjectName)</BaseOutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<IsWindows Condition="$([MSBuild]::IsOSPlatform('Windows'))">true</IsWindows>
|
||||
<IsOSX Condition="$([MSBuild]::IsOSPlatform('OSX'))">true</IsOSX>
|
||||
<IsLinux Condition="$([MSBuild]::IsOSPlatform('Linux'))">true</IsLinux>
|
||||
|
||||
<!-- This is horrible but the only workarround I found to disable the transcoder copy on the dev dockerfile -->
|
||||
<SkipTranscoder Condition="$(MsBuildThisFileDirectory) == '/app/src/'">true</SkipTranscoder>
|
||||
|
||||
<CheckCodingStyle Condition="$(CheckCodingStyle) == ''">true</CheckCodingStyle>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -44,15 +32,14 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="$(CheckCodingStyle) == true">
|
||||
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.354" PrivateAssets="All" />
|
||||
|
||||
<AdditionalFiles Include="$(MSBuildThisFileDirectory)../stylecop.json" Link="stylecop.json" Visible="false" />
|
||||
<None Include="$(MSBuildThisFileDirectory)../.editorconfig" Link=".editorconfig" Visible="false" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition="$(CheckCodingStyle) == true">
|
||||
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)../Kyoo.ruleset</CodeAnalysisRuleSet>
|
||||
<NoWarn>1591;1305;8618;SYSLIB1045;CS1573</NoWarn>
|
||||
<!-- <AnalysisMode>All</AnalysisMode> -->
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- vim: ft=xml -->
|
||||
</Project>
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// An interface that allow one to interact with the host and shutdown or restart the app.
|
||||
/// </summary>
|
||||
public interface IApplication
|
||||
{
|
||||
/// <summary>
|
||||
/// Shutdown the process and stop gracefully.
|
||||
/// </summary>
|
||||
void Shutdown();
|
||||
|
||||
/// <summary>
|
||||
/// Restart Kyoo from scratch, reload plugins, configurations and restart the web server.
|
||||
/// </summary>
|
||||
void Restart();
|
||||
|
||||
/// <summary>
|
||||
/// Get the data directory.
|
||||
/// </summary>
|
||||
/// <returns>Retrieve the data directory where runtime data should be stored.</returns>
|
||||
string GetDataDirectory();
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the path of the json configuration file
|
||||
/// (relative to the data directory, see <see cref="GetDataDirectory"/>).
|
||||
/// </summary>
|
||||
/// <returns>The configuration file name.</returns>
|
||||
string GetConfigFile();
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Kyoo.Abstractions.Models.Exceptions;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// A class to ease configuration management. This work WITH Microsoft's package, you can still use IOptions patterns
|
||||
/// to access your options, this manager ease dynamic work and editing.
|
||||
/// It works with <see cref="ConfigurationReference"/>.
|
||||
/// </summary>
|
||||
public interface IConfigurationManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Add an editable configuration to the editable configuration list.
|
||||
/// </summary>
|
||||
/// <param name="path">The root path of the editable configuration. It should not be a nested type.</param>
|
||||
/// <typeparam name="T">The type of the configuration.</typeparam>
|
||||
void AddTyped<T>(string path);
|
||||
|
||||
/// <summary>
|
||||
/// Add an editable configuration to the editable configuration list.
|
||||
/// WARNING: this method allow you to add an unmanaged type. This type won't be editable. This can be used
|
||||
/// for external libraries or variable arguments.
|
||||
/// </summary>
|
||||
/// <param name="path">The root path of the editable configuration. It should not be a nested type.</param>
|
||||
void AddUntyped(string path);
|
||||
|
||||
/// <summary>
|
||||
/// An helper method of <see cref="AddTyped{T}"/> and <see cref="AddUntyped"/>.
|
||||
/// This register a typed value if <paramref name="type"/> is not <c>null</c> and registers an untyped type
|
||||
/// if <paramref name="type"/> is <c>null</c>.
|
||||
/// </summary>
|
||||
/// <param name="path">The root path of the editable configuration. It should not be a nested type.</param>
|
||||
/// <param name="type">The type of the configuration or null.</param>
|
||||
void Register(string path, [CanBeNull] Type type);
|
||||
|
||||
/// <summary>
|
||||
/// Get the value of a setting using it's path.
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the resource (can be separated by ':' or '__').</param>
|
||||
/// <exception cref="ItemNotFoundException">No setting found at the given path.</exception>
|
||||
/// <returns>The value of the settings (if it's a strongly typed one, the given type is instantiated.</returns>
|
||||
object GetValue(string path);
|
||||
|
||||
/// <summary>
|
||||
/// Get the value of a setting using it's path.
|
||||
/// If your don't need a strongly typed value, see <see cref="GetValue"/>.
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the resource (can be separated by ':' or '__').</param>
|
||||
/// <typeparam name="T">A type to strongly type your option.</typeparam>
|
||||
/// <exception cref="InvalidCastException">If your type is not the same as the registered type.</exception>
|
||||
/// <exception cref="ItemNotFoundException">No setting found at the given path.</exception>
|
||||
/// <returns>The value of the settings (if it's a strongly typed one, the given type is instantiated.</returns>
|
||||
T GetValue<T>(string path);
|
||||
|
||||
/// <summary>
|
||||
/// Edit the value of a setting using it's path. Save it to the json file.
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the resource (can be separated by ':' or '__').</param>
|
||||
/// <param name="value">The new value of the resource.</param>
|
||||
/// <exception cref="ItemNotFoundException">No setting found at the given path.</exception>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task EditValue(string path, object value);
|
||||
}
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// A service to abstract the file system to allow custom file systems
|
||||
/// (like distant file systems or external providers).
|
||||
/// </summary>
|
||||
public interface IFileSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Used for http queries returning a file. This should be used to return local files
|
||||
/// or proxy them from a distant server.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If no file exists at the given path or if the path is null, a NotFoundResult is returned
|
||||
/// to handle it gracefully.
|
||||
/// </remarks>
|
||||
/// <param name="path">The path of the file.</param>
|
||||
/// <param name="rangeSupport">
|
||||
/// Should the file be downloaded at once or is the client allowed to request only part of the file
|
||||
/// </param>
|
||||
/// <param name="type">
|
||||
/// You can manually specify the content type of your file.
|
||||
/// For example you can force a file to be returned as plain text using <c>text/plain</c>.
|
||||
/// If the type is not specified, it will be deduced automatically (from the extension or by sniffing the file).
|
||||
/// </param>
|
||||
/// <returns>An <see cref="IActionResult"/> representing the file returned.</returns>
|
||||
IActionResult FileResult([CanBeNull] string path, bool rangeSupport = false, string type = null);
|
||||
|
||||
/// <summary>
|
||||
/// Read a file present at <paramref name="path"/>. The reader can be used in an arbitrary context.
|
||||
/// To return files from an http endpoint, use <see cref="FileResult"/>.
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the file</param>
|
||||
/// <exception cref="FileNotFoundException">If the file could not be found.</exception>
|
||||
/// <returns>A reader to read the file.</returns>
|
||||
Task<Stream> GetReader([NotNull] string path);
|
||||
|
||||
/// <summary>
|
||||
/// Read a file present at <paramref name="path"/>. The reader can be used in an arbitrary context.
|
||||
/// To return files from an http endpoint, use <see cref="FileResult"/>.
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the file</param>
|
||||
/// <param name="mime">The mime type of the opened file.</param>
|
||||
/// <exception cref="FileNotFoundException">If the file could not be found.</exception>
|
||||
/// <returns>A reader to read the file.</returns>
|
||||
Task<Stream> GetReader([NotNull] string path, AsyncRef<string> mime);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new file at <paramref name="path"></paramref>.
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the new file.</param>
|
||||
/// <returns>A writer to write to the new file.</returns>
|
||||
Task<Stream> NewFile([NotNull] string path);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new directory at the given path
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the directory</param>
|
||||
/// <returns>The path of the newly created directory is returned.</returns>
|
||||
Task<string> CreateDirectory([NotNull] string path);
|
||||
|
||||
/// <summary>
|
||||
/// Combine multiple paths.
|
||||
/// </summary>
|
||||
/// <param name="paths">The paths to combine</param>
|
||||
/// <returns>The combined path.</returns>
|
||||
string Combine(params string[] paths);
|
||||
|
||||
/// <summary>
|
||||
/// List files in a directory.
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the directory</param>
|
||||
/// <param name="options">Should the search be recursive or not.</param>
|
||||
/// <returns>A list of files's path.</returns>
|
||||
Task<ICollection<string>> ListFiles([NotNull] string path,
|
||||
SearchOption options = SearchOption.TopDirectoryOnly);
|
||||
|
||||
/// <summary>
|
||||
/// Check if a file exists at the given path.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to check</param>
|
||||
/// <returns>True if the path exists, false otherwise</returns>
|
||||
Task<bool> Exists([NotNull] string path);
|
||||
|
||||
/// <summary>
|
||||
/// Get the extra directory of a resource <typeparamref name="T"/>.
|
||||
/// This method is in this system to allow a filesystem to use a different metadata policy for one.
|
||||
/// It can be useful if the filesystem is readonly.
|
||||
/// </summary>
|
||||
/// <param name="resource">The resource to proceed</param>
|
||||
/// <typeparam name="T">The type of the resource.</typeparam>
|
||||
/// <returns>The extra directory of the resource.</returns>
|
||||
Task<string> GetExtraDirectory<T>([NotNull] T resource);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve tracks for a specific episode.
|
||||
/// Subtitles, chapters and fonts should also be extracted and cached when calling this method.
|
||||
/// </summary>
|
||||
/// <param name="episode">The episode to retrieve tracks for.</param>
|
||||
/// <param name="reExtract">Should the cache be invalidated and subtitles and others be re-extracted?</param>
|
||||
/// <returns>The list of tracks available for this episode.</returns>
|
||||
Task<ICollection<Track>> ExtractInfos([NotNull] Episode episode, bool reExtract);
|
||||
|
||||
/// <summary>
|
||||
/// Transmux the selected episode to hls.
|
||||
/// </summary>
|
||||
/// <param name="episode">The episode to transmux.</param>
|
||||
/// <returns>The master file (m3u8) of the transmuxed hls file.</returns>
|
||||
IActionResult Transmux([NotNull] Episode episode);
|
||||
|
||||
// Maybe add options for to select the codec.
|
||||
// IActionResult Transcode(Episode episode);
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Kyoo.Abstractions.Models.Exceptions;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// An interface to identify episodes, shows and metadata based on the episode file.
|
||||
/// </summary>
|
||||
public interface IIdentifier
|
||||
{
|
||||
/// <summary>
|
||||
/// Identify a path and return the parsed metadata.
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the episode file to parse.</param>
|
||||
/// <exception cref="IdentificationFailedException">
|
||||
/// The identifier could not work for the given path.
|
||||
/// </exception>
|
||||
/// <returns>
|
||||
/// A tuple of models representing parsed metadata.
|
||||
/// If no metadata could be parsed for a type, null can be returned.
|
||||
/// </returns>
|
||||
Task<(Collection, Show, Season, Episode)> Identify(string path);
|
||||
|
||||
/// <summary>
|
||||
/// Identify an external subtitle or track file from it's path and return the parsed metadata.
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the external track file to parse.</param>
|
||||
/// <exception cref="IdentificationFailedException">
|
||||
/// The identifier could not work for the given path.
|
||||
/// </exception>
|
||||
/// <returns>
|
||||
/// The metadata of the track identified.
|
||||
/// </returns>
|
||||
Task<Track> IdentifyTrack(string path);
|
||||
}
|
||||
}
|
||||
35
back/src/Kyoo.Abstractions/Controllers/IIssueRepository.cs
Normal file
35
back/src/Kyoo.Abstractions/Controllers/IIssueRepository.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Kyoo.Abstractions.Models.Utils;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers;
|
||||
|
||||
public interface IIssueRepository
|
||||
{
|
||||
Task<ICollection<Issue>> GetAll(Filter<Issue>? filter = default);
|
||||
|
||||
Task<int> GetCount(Filter<Issue>? filter = default);
|
||||
|
||||
Task<Issue> Upsert(Issue issue);
|
||||
|
||||
Task DeleteAll(Filter<Issue>? filter = default);
|
||||
}
|
||||
@@ -16,597 +16,65 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Kyoo.Abstractions.Models.Exceptions;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers
|
||||
namespace Kyoo.Abstractions.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// An interface to interact with the database. Every repository is mapped through here.
|
||||
/// </summary>
|
||||
public interface ILibraryManager
|
||||
{
|
||||
IRepository<T> Repository<T>()
|
||||
where T : IResource, IQuery;
|
||||
|
||||
/// <summary>
|
||||
/// An interface to interact with the database. Every repository is mapped through here.
|
||||
/// The repository that handle libraries items (a wrapper around shows and collections).
|
||||
/// </summary>
|
||||
public interface ILibraryManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the repository corresponding to the T item.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type you want</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The repository corresponding</returns>
|
||||
IRepository<T> GetRepository<T>()
|
||||
where T : class, IResource;
|
||||
IRepository<ILibraryItem> LibraryItems { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle libraries.
|
||||
/// </summary>
|
||||
ILibraryRepository LibraryRepository { get; }
|
||||
/// <summary>
|
||||
/// The repository that handle new items.
|
||||
/// </summary>
|
||||
IRepository<INews> News { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle libraries items (a wrapper around shows and collections).
|
||||
/// </summary>
|
||||
ILibraryItemRepository LibraryItemRepository { get; }
|
||||
/// <summary>
|
||||
/// The repository that handle watched items.
|
||||
/// </summary>
|
||||
IWatchStatusRepository WatchStatus { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle collections.
|
||||
/// </summary>
|
||||
ICollectionRepository CollectionRepository { get; }
|
||||
/// <summary>
|
||||
/// The repository that handle collections.
|
||||
/// </summary>
|
||||
IRepository<Collection> Collections { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle shows.
|
||||
/// </summary>
|
||||
IShowRepository ShowRepository { get; }
|
||||
/// <summary>
|
||||
/// The repository that handle shows.
|
||||
/// </summary>
|
||||
IRepository<Movie> Movies { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle seasons.
|
||||
/// </summary>
|
||||
ISeasonRepository SeasonRepository { get; }
|
||||
/// <summary>
|
||||
/// The repository that handle shows.
|
||||
/// </summary>
|
||||
IRepository<Show> Shows { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle episodes.
|
||||
/// </summary>
|
||||
IEpisodeRepository EpisodeRepository { get; }
|
||||
/// <summary>
|
||||
/// The repository that handle seasons.
|
||||
/// </summary>
|
||||
IRepository<Season> Seasons { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle tracks.
|
||||
/// </summary>
|
||||
ITrackRepository TrackRepository { get; }
|
||||
/// <summary>
|
||||
/// The repository that handle episodes.
|
||||
/// </summary>
|
||||
IRepository<Episode> Episodes { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle people.
|
||||
/// </summary>
|
||||
IPeopleRepository PeopleRepository { get; }
|
||||
/// <summary>
|
||||
/// The repository that handle studios.
|
||||
/// </summary>
|
||||
IRepository<Studio> Studios { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle studios.
|
||||
/// </summary>
|
||||
IStudioRepository StudioRepository { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle genres.
|
||||
/// </summary>
|
||||
IGenreRepository GenreRepository { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle providers.
|
||||
/// </summary>
|
||||
IProviderRepository ProviderRepository { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle users.
|
||||
/// </summary>
|
||||
IUserRepository UserRepository { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the resource by it's ID
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the resource</param>
|
||||
/// <typeparam name="T">The type of the resource</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> Get<T>(int id)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Get the resource by it's slug
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the resource</param>
|
||||
/// <typeparam name="T">The type of the resource</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> Get<T>(string slug)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Get the resource by a filter function.
|
||||
/// </summary>
|
||||
/// <param name="where">The filter function.</param>
|
||||
/// <typeparam name="T">The type of the resource</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The first resource found that match the where function</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> Get<T>(Expression<Func<T, bool>> where)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Get a season from it's showID and it's seasonNumber
|
||||
/// </summary>
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The season found</returns>
|
||||
[ItemNotNull]
|
||||
Task<Season> Get(int showID, int seasonNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a season from it's show slug and it's seasonNumber
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The season found</returns>
|
||||
[ItemNotNull]
|
||||
Task<Season> Get(string showSlug, int seasonNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's showID, it's seasonNumber and it's episode number.
|
||||
/// </summary>
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The episode found</returns>
|
||||
[ItemNotNull]
|
||||
Task<Episode> Get(int showID, int seasonNumber, int episodeNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's show slug, it's seasonNumber and it's episode number.
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The episode found</returns>
|
||||
[ItemNotNull]
|
||||
Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get the resource by it's ID or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the resource</param>
|
||||
/// <typeparam name="T">The type of the resource</typeparam>
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<T> GetOrDefault<T>(int id)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Get the resource by it's slug or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the resource</param>
|
||||
/// <typeparam name="T">The type of the resource</typeparam>
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<T> GetOrDefault<T>(string slug)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Get the resource by a filter function or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="where">The filter function.</param>
|
||||
/// <param name="sortBy">A custom sort method to handle cases where multiples items match the filters.</param>
|
||||
/// <typeparam name="T">The type of the resource</typeparam>
|
||||
/// <returns>The first resource found that match the where function</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<T> GetOrDefault<T>(Expression<Func<T, bool>> where, Sort<T> sortBy = default)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Get a season from it's showID and it's seasonNumber or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <returns>The season found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<Season> GetOrDefault(int showID, int seasonNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a season from it's show slug and it's seasonNumber or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <returns>The season found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<Season> GetOrDefault(string showSlug, int seasonNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's showID, it's seasonNumber and it's episode number or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <returns>The episode found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<Episode> GetOrDefault(int showID, int seasonNumber, int episodeNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's show slug, it's seasonNumber and it's episode number or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <returns>The episode found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<Episode> GetOrDefault(string showSlug, int seasonNumber, int episodeNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Load a related resource
|
||||
/// </summary>
|
||||
/// <param name="obj">The source object.</param>
|
||||
/// <param name="member">A getter function for the member to load</param>
|
||||
/// <param name="force">
|
||||
/// <c>true</c> if you want to load the relation even if it is not null, <c>false</c> otherwise.
|
||||
/// </param>
|
||||
/// <typeparam name="T">The type of the source object</typeparam>
|
||||
/// <typeparam name="T2">The related resource's type</typeparam>
|
||||
/// <returns>The param <paramref name="obj"/></returns>
|
||||
/// <seealso cref="Load{T,T2}(T, System.Linq.Expressions.Expression{System.Func{T,System.Collections.Generic.ICollection{T2}}}, bool)"/>
|
||||
/// <seealso cref="Load{T}(T, string, bool)"/>
|
||||
/// <seealso cref="Load(IResource, string, bool)"/>
|
||||
Task<T> Load<T, T2>([NotNull] T obj, Expression<Func<T, T2>> member, bool force = false)
|
||||
where T : class, IResource
|
||||
where T2 : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Load a collection of related resource
|
||||
/// </summary>
|
||||
/// <param name="obj">The source object.</param>
|
||||
/// <param name="member">A getter function for the member to load</param>
|
||||
/// <param name="force">
|
||||
/// <c>true</c> if you want to load the relation even if it is not null, <c>false</c> otherwise.
|
||||
/// </param>
|
||||
/// <typeparam name="T">The type of the source object</typeparam>
|
||||
/// <typeparam name="T2">The related resource's type</typeparam>
|
||||
/// <returns>The param <paramref name="obj"/></returns>
|
||||
/// <seealso cref="Load{T,T2}(T, System.Linq.Expressions.Expression{System.Func{T,T2}}, bool)"/>
|
||||
/// <seealso cref="Load{T}(T, string, bool)"/>
|
||||
/// <seealso cref="Load(IResource, string, bool)"/>
|
||||
Task<T> Load<T, T2>([NotNull] T obj, Expression<Func<T, ICollection<T2>>> member, bool force = false)
|
||||
where T : class, IResource
|
||||
where T2 : class;
|
||||
|
||||
/// <summary>
|
||||
/// Load a related resource by it's name
|
||||
/// </summary>
|
||||
/// <param name="obj">The source object.</param>
|
||||
/// <param name="memberName">The name of the resource to load (case sensitive)</param>
|
||||
/// <param name="force">
|
||||
/// <c>true</c> if you want to load the relation even if it is not null, <c>false</c> otherwise.
|
||||
/// </param>
|
||||
/// <typeparam name="T">The type of the source object</typeparam>
|
||||
/// <returns>The param <paramref name="obj"/></returns>
|
||||
/// <seealso cref="Load{T,T2}(T, System.Linq.Expressions.Expression{System.Func{T,T2}}, bool)"/>
|
||||
/// <seealso cref="Load{T,T2}(T, System.Linq.Expressions.Expression{System.Func{T,System.Collections.Generic.ICollection{T2}}}, bool)"/>
|
||||
/// <seealso cref="Load(IResource, string, bool)"/>
|
||||
Task<T> Load<T>([NotNull] T obj, string memberName, bool force = false)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Load a related resource without specifying it's type.
|
||||
/// </summary>
|
||||
/// <param name="obj">The source object.</param>
|
||||
/// <param name="memberName">The name of the resource to load (case sensitive)</param>
|
||||
/// <param name="force">
|
||||
/// <c>true</c> if you want to load the relation even if it is not null, <c>false</c> otherwise.
|
||||
/// </param>
|
||||
/// <seealso cref="Load{T,T2}(T, System.Linq.Expressions.Expression{System.Func{T,T2}}, bool)"/>
|
||||
/// <seealso cref="Load{T,T2}(T, System.Linq.Expressions.Expression{System.Func{T,System.Collections.Generic.ICollection{T2}}}, bool)"/>
|
||||
/// <seealso cref="Load{T}(T, string, bool)"/>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task Load([NotNull] IResource obj, string memberName, bool force = false);
|
||||
|
||||
/// <summary>
|
||||
/// Get items (A wrapper around shows or collections) from a library.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the library</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No library exist with the given ID.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<LibraryItem>> GetItemsFromLibrary(int id,
|
||||
Expression<Func<LibraryItem, bool>> where = null,
|
||||
Sort<LibraryItem> sort = default,
|
||||
Pagination limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get items (A wrapper around shows or collections) from a library.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the library</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">A sort by method</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No library exist with the given ID.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<LibraryItem>> GetItemsFromLibrary(int id,
|
||||
[Optional] Expression<Func<LibraryItem, bool>> where,
|
||||
Expression<Func<LibraryItem, object>> sort,
|
||||
Pagination limit = default
|
||||
) => GetItemsFromLibrary(id, where, new Sort<LibraryItem>(sort), limit);
|
||||
|
||||
/// <summary>
|
||||
/// Get items (A wrapper around shows or collections) from a library.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the library</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No library exist with the given slug.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<LibraryItem>> GetItemsFromLibrary(string slug,
|
||||
Expression<Func<LibraryItem, bool>> where = null,
|
||||
Sort<LibraryItem> sort = default,
|
||||
Pagination limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get items (A wrapper around shows or collections) from a library.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the library</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">A sort by method</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No library exist with the given slug.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<LibraryItem>> GetItemsFromLibrary(string slug,
|
||||
[Optional] Expression<Func<LibraryItem, bool>> where,
|
||||
Expression<Func<LibraryItem, object>> sort,
|
||||
Pagination limit = default
|
||||
) => GetItemsFromLibrary(slug, where, new Sort<LibraryItem>(sort), limit);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a show.
|
||||
/// </summary>
|
||||
/// <param name="showID">The ID of the show</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="Show"/> exist with the given ID.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetPeopleFromShow(int showID,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a show.
|
||||
/// </summary>
|
||||
/// <param name="showID">The ID of the show</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">A sort by method</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="Show"/> exist with the given ID.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetPeopleFromShow(int showID,
|
||||
[Optional] Expression<Func<PeopleRole, bool>> where,
|
||||
Expression<Func<PeopleRole, object>> sort,
|
||||
Pagination limit = default
|
||||
) => GetPeopleFromShow(showID, where, new Sort<PeopleRole>(sort), limit);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a show.
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="Show"/> exist with the given slug.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetPeopleFromShow(string showSlug,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a show.
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">A sort by method</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="Show"/> exist with the given slug.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetPeopleFromShow(string showSlug,
|
||||
[Optional] Expression<Func<PeopleRole, bool>> where,
|
||||
Expression<Func<PeopleRole, object>> sort,
|
||||
Pagination limit = default
|
||||
) => GetPeopleFromShow(showSlug, where, new Sort<PeopleRole>(sort), limit);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a person.
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the person</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="People"/> exist with the given ID.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetRolesFromPeople(int id,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a person.
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the person</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">A sort by method</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="People"/> exist with the given ID.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetRolesFromPeople(int id,
|
||||
[Optional] Expression<Func<PeopleRole, bool>> where,
|
||||
Expression<Func<PeopleRole, object>> sort,
|
||||
Pagination limit = default
|
||||
) => GetRolesFromPeople(id, where, new Sort<PeopleRole>(sort), limit);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a person.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the person</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="People"/> exist with the given slug.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetRolesFromPeople(string slug,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a person.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the person</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">A sort by method</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="People"/> exist with the given slug.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetRolesFromPeople(string slug,
|
||||
[Optional] Expression<Func<PeopleRole, bool>> where,
|
||||
Expression<Func<PeopleRole, object>> sort,
|
||||
Pagination limit = default
|
||||
) => GetRolesFromPeople(slug, where, new Sort<PeopleRole>(sort), limit);
|
||||
|
||||
/// <summary>
|
||||
/// Setup relations between a show, a library and a collection
|
||||
/// </summary>
|
||||
/// <param name="showID">The show's ID to setup relations with</param>
|
||||
/// <param name="libraryID">The library's ID to setup relations with (optional)</param>
|
||||
/// <param name="collectionID">The collection's ID to setup relations with (optional)</param>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task AddShowLink(int showID, int? libraryID, int? collectionID);
|
||||
|
||||
/// <summary>
|
||||
/// Setup relations between a show, a library and a collection
|
||||
/// </summary>
|
||||
/// <param name="show">The show to setup relations with</param>
|
||||
/// <param name="library">The library to setup relations with (optional)</param>
|
||||
/// <param name="collection">The collection to setup relations with (optional)</param>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task AddShowLink([NotNull] Show show, Library library, Collection collection);
|
||||
|
||||
/// <summary>
|
||||
/// Get all resources with filters
|
||||
/// </summary>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <typeparam name="T">The type of resources to load</typeparam>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
Task<ICollection<T>> GetAll<T>(Expression<Func<T, bool>> where = null,
|
||||
Sort<T> sort = default,
|
||||
Pagination limit = default)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Get all resources with filters
|
||||
/// </summary>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">A sort by function</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <typeparam name="T">The type of resources to load</typeparam>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
Task<ICollection<T>> GetAll<T>([Optional] Expression<Func<T, bool>> where,
|
||||
Expression<Func<T, object>> sort,
|
||||
Pagination limit = default)
|
||||
where T : class, IResource
|
||||
{
|
||||
return GetAll(where, new Sort<T>(sort), limit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the count of resources that match the filter
|
||||
/// </summary>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <typeparam name="T">The type of resources to load</typeparam>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
Task<int> GetCount<T>(Expression<Func<T, bool>> where = null)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Search for a resource
|
||||
/// </summary>
|
||||
/// <param name="query">The search query</param>
|
||||
/// <typeparam name="T">The type of resources</typeparam>
|
||||
/// <returns>A list of 20 items that match the search query</returns>
|
||||
Task<ICollection<T>> Search<T>(string query)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new resource.
|
||||
/// </summary>
|
||||
/// <param name="item">The item to register</param>
|
||||
/// <typeparam name="T">The type of resource</typeparam>
|
||||
/// <returns>The resource registers and completed by database's information (related items and so on)</returns>
|
||||
Task<T> Create<T>([NotNull] T item)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new resource if it does not exist already. If it does, the existing value is returned instead.
|
||||
/// </summary>
|
||||
/// <param name="item">The item to register</param>
|
||||
/// <typeparam name="T">The type of resource</typeparam>
|
||||
/// <returns>The newly created item or the existing value if it existed.</returns>
|
||||
Task<T> CreateIfNotExists<T>([NotNull] T item)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Edit a resource
|
||||
/// </summary>
|
||||
/// <param name="item">The resource to edit, it's ID can't change.</param>
|
||||
/// <param name="resetOld">Should old properties of the resource be discarded or should null values considered as not changed?</param>
|
||||
/// <typeparam name="T">The type of resources</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The resource edited and completed by database's information (related items and so on)</returns>
|
||||
Task<T> Edit<T>(T item, bool resetOld)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Delete a resource.
|
||||
/// </summary>
|
||||
/// <param name="item">The resource to delete</param>
|
||||
/// <typeparam name="T">The type of resource to delete</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task Delete<T>(T item)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Delete a resource by it's ID.
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the resource to delete</param>
|
||||
/// <typeparam name="T">The type of resource to delete</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task Delete<T>(int id)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Delete a resource by it's slug.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the resource to delete</param>
|
||||
/// <typeparam name="T">The type of resource to delete</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task Delete<T>(string slug)
|
||||
where T : class, IResource;
|
||||
}
|
||||
/// <summary>
|
||||
/// The repository that handle users.
|
||||
/// </summary>
|
||||
IRepository<User> Users { get; }
|
||||
}
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Kyoo.Abstractions.Models;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// An interface to automatically retrieve metadata from external providers.
|
||||
/// </summary>
|
||||
public interface IMetadataProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="Provider"/> corresponding to this provider.
|
||||
/// This allow to map metadata to a provider, keep metadata links and
|
||||
/// know witch <see cref="IMetadataProvider"/> is used for a specific <see cref="Library"/>.
|
||||
/// </summary>
|
||||
Provider Provider { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Return a new item with metadata from your provider.
|
||||
/// </summary>
|
||||
/// <param name="item">
|
||||
/// The item to retrieve metadata from. Most of the time, only the name will be available but other
|
||||
/// properties may be filed by other providers before a call to this method. This can allow you to identify
|
||||
/// the collection on your provider.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// You must not use metadata from the given <paramref name="item"/>.
|
||||
/// Merging metadata is the job of Kyoo, a complex <typeparamref name="T"/> is given
|
||||
/// to make a precise search and give you every available properties, not to discard properties.
|
||||
/// </remarks>
|
||||
/// <typeparam name="T">The type of resource to retrieve metadata for.</typeparam>
|
||||
/// <returns>A new <typeparamref name="T"/> containing metadata from your provider or null</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<T> Get<T>([NotNull] T item)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Search for a specific type of items with a given query.
|
||||
/// </summary>
|
||||
/// <param name="query">The search query to use.</param>
|
||||
/// <typeparam name="T">The type of resource to search metadata for.</typeparam>
|
||||
/// <returns>The list of items that could be found on this specific provider.</returns>
|
||||
[ItemNotNull]
|
||||
Task<ICollection<T>> Search<T>(string query)
|
||||
where T : class, IResource;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A special <see cref="IMetadataProvider"/> that merge results.
|
||||
/// This interface exists to specify witch provider to use but it can be used like any other metadata provider.
|
||||
/// </summary>
|
||||
public abstract class AProviderComposite : IMetadataProvider
|
||||
{
|
||||
/// <inheritdoc />
|
||||
[ItemNotNull]
|
||||
public abstract Task<T> Get<T>(T item)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract Task<ICollection<T>> Search<T>(string query)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Since this is a composite and not a real provider, no metadata is available.
|
||||
/// It is not meant to be stored or selected. This class will handle merge based on what is required.
|
||||
/// </summary>
|
||||
public Provider Provider => null;
|
||||
|
||||
/// <summary>
|
||||
/// Select witch providers to use.
|
||||
/// The <see cref="IMetadataProvider"/> associated with the given <see cref="Provider"/> will be used.
|
||||
/// </summary>
|
||||
/// <param name="providers">The list of providers to use</param>
|
||||
public abstract void UseProviders(IEnumerable<Provider> providers);
|
||||
}
|
||||
}
|
||||
@@ -19,29 +19,28 @@
|
||||
using Kyoo.Abstractions.Models.Permissions;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers
|
||||
namespace Kyoo.Abstractions.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// A service to validate permissions.
|
||||
/// </summary>
|
||||
public interface IPermissionValidator
|
||||
{
|
||||
/// <summary>
|
||||
/// A service to validate permissions.
|
||||
/// Create an IAuthorizationFilter that will be used to validate permissions.
|
||||
/// This can registered with any lifetime.
|
||||
/// </summary>
|
||||
public interface IPermissionValidator
|
||||
{
|
||||
/// <summary>
|
||||
/// Create an IAuthorizationFilter that will be used to validate permissions.
|
||||
/// This can registered with any lifetime.
|
||||
/// </summary>
|
||||
/// <param name="attribute">The permission attribute to validate.</param>
|
||||
/// <returns>An authorization filter used to validate the permission.</returns>
|
||||
IFilterMetadata Create(PermissionAttribute attribute);
|
||||
/// <param name="attribute">The permission attribute to validate.</param>
|
||||
/// <returns>An authorization filter used to validate the permission.</returns>
|
||||
IFilterMetadata Create(PermissionAttribute attribute);
|
||||
|
||||
/// <summary>
|
||||
/// Create an IAuthorizationFilter that will be used to validate permissions.
|
||||
/// This can registered with any lifetime.
|
||||
/// </summary>
|
||||
/// <param name="attribute">
|
||||
/// A partial attribute to validate. See <see cref="PartialPermissionAttribute"/>.
|
||||
/// </param>
|
||||
/// <returns>An authorization filter used to validate the permission.</returns>
|
||||
IFilterMetadata Create(PartialPermissionAttribute attribute);
|
||||
}
|
||||
/// <summary>
|
||||
/// Create an IAuthorizationFilter that will be used to validate permissions.
|
||||
/// This can registered with any lifetime.
|
||||
/// </summary>
|
||||
/// <param name="attribute">
|
||||
/// A partial attribute to validate. See <see cref="PartialPermissionAttribute"/>.
|
||||
/// </param>
|
||||
/// <returns>An authorization filter used to validate the permission.</returns>
|
||||
IFilterMetadata Create(PartialPermissionAttribute attribute);
|
||||
}
|
||||
|
||||
@@ -19,97 +19,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Autofac;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers
|
||||
namespace Kyoo.Abstractions.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// A common interface used to discord plugins
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// You can inject services in the IPlugin constructor.
|
||||
/// You should only inject well known services like an ILogger, IConfiguration or IWebHostEnvironment.
|
||||
/// </remarks>
|
||||
public interface IPlugin
|
||||
{
|
||||
/// <summary>
|
||||
/// A common interface used to discord plugins
|
||||
/// The name of the plugin
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// You can inject services in the IPlugin constructor.
|
||||
/// You should only inject well known services like an ILogger, IConfiguration or IWebHostEnvironment.
|
||||
/// </remarks>
|
||||
[UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)]
|
||||
public interface IPlugin
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// An optional configuration step to allow a plugin to change asp net configurations.
|
||||
/// </summary>
|
||||
/// <seealso cref="SA"/>
|
||||
IEnumerable<IStartupAction> ConfigureSteps => ArraySegment<IStartupAction>.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// A configure method that will be run on plugin's startup.
|
||||
/// </summary>
|
||||
/// <param name="builder">The autofac service container to register services.</param>
|
||||
void Configure(ContainerBuilder builder)
|
||||
{
|
||||
/// <summary>
|
||||
/// A slug to identify this plugin in queries.
|
||||
/// </summary>
|
||||
string Slug { get; }
|
||||
// Skipped
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The name of the plugin
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The description of this plugin. This will be displayed on the "installed plugins" page.
|
||||
/// </summary>
|
||||
string Description { get; }
|
||||
|
||||
/// <summary>
|
||||
/// <c>true</c> if the plugin should be enabled, <c>false</c> otherwise.
|
||||
/// If a plugin is not enabled, no configure method will be called.
|
||||
/// This allow one to enable a plugin if a specific configuration value is set or if the environment contains
|
||||
/// the right settings.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// By default, a plugin is always enabled. This method can be overriden to change this behavior.
|
||||
/// </remarks>
|
||||
virtual bool Enabled => true;
|
||||
|
||||
/// <summary>
|
||||
/// A list of types that will be available via the IOptions interfaces and will be listed inside
|
||||
/// an IConfiguration.
|
||||
///
|
||||
/// If a field should be loosely typed, <see cref="Dictionary{TKey,TValue}"/> or <c>null</c>
|
||||
/// can be specified.
|
||||
/// WARNING: null means an unmanaged type that won't be editable. This can be used
|
||||
/// for external libraries or variable arguments.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// All use of the configuration must be specified here and not registered elsewhere, if a type is registered
|
||||
/// elsewhere the configuration won't be editable via the <see cref="IConfigurationManager"/> and all values
|
||||
/// will be discarded on edit.
|
||||
/// </remarks>
|
||||
Dictionary<string, Type> Configuration { get; }
|
||||
|
||||
/// <summary>
|
||||
/// An optional configuration step to allow a plugin to change asp net configurations.
|
||||
/// </summary>
|
||||
/// <seealso cref="SA"/>
|
||||
virtual IEnumerable<IStartupAction> ConfigureSteps => ArraySegment<IStartupAction>.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// A configure method that will be run on plugin's startup.
|
||||
/// </summary>
|
||||
/// <param name="builder">The autofac service container to register services.</param>
|
||||
void Configure(ContainerBuilder builder)
|
||||
{
|
||||
// Skipped
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A configure method that will be run on plugin's startup.
|
||||
/// This is available for libraries that build upon a <see cref="IServiceCollection"/>, for more precise
|
||||
/// configuration use <see cref="Configure(Autofac.ContainerBuilder)"/>.
|
||||
/// </summary>
|
||||
/// <param name="services">A service container to register new services.</param>
|
||||
void Configure(IServiceCollection services)
|
||||
{
|
||||
// Skipped
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An optional function to execute and initialize your plugin.
|
||||
/// It can be used to initialize a database connection, fill initial data or anything.
|
||||
/// </summary>
|
||||
/// <param name="provider">A service provider to request services</param>
|
||||
void Initialize(IServiceProvider provider)
|
||||
{
|
||||
// Skipped
|
||||
}
|
||||
/// <summary>
|
||||
/// A configure method that will be run on plugin's startup.
|
||||
/// This is available for libraries that build upon a <see cref="IServiceCollection"/>, for more precise
|
||||
/// configuration use <see cref="Configure(Autofac.ContainerBuilder)"/>.
|
||||
/// </summary>
|
||||
/// <param name="services">A service container to register new services.</param>
|
||||
void Configure(IServiceCollection services)
|
||||
{
|
||||
// Skipped
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,51 +20,50 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using Kyoo.Abstractions.Models.Exceptions;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers
|
||||
namespace Kyoo.Abstractions.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// A manager to load plugins and retrieve information from them.
|
||||
/// </summary>
|
||||
public interface IPluginManager
|
||||
{
|
||||
/// <summary>
|
||||
/// A manager to load plugins and retrieve information from them.
|
||||
/// Get a single plugin that match the type and name given.
|
||||
/// </summary>
|
||||
public interface IPluginManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Get a single plugin that match the type and name given.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the plugin</param>
|
||||
/// <typeparam name="T">The type of the plugin</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If no plugins match the query</exception>
|
||||
/// <returns>A plugin that match the queries</returns>
|
||||
public T GetPlugin<T>(string name);
|
||||
/// <param name="name">The name of the plugin</param>
|
||||
/// <typeparam name="T">The type of the plugin</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If no plugins match the query</exception>
|
||||
/// <returns>A plugin that match the queries</returns>
|
||||
public T GetPlugin<T>(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Get all plugins of the given type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of plugins to get</typeparam>
|
||||
/// <returns>A list of plugins matching the given type or an empty list of none match.</returns>
|
||||
public ICollection<T> GetPlugins<T>();
|
||||
/// <summary>
|
||||
/// Get all plugins of the given type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of plugins to get</typeparam>
|
||||
/// <returns>A list of plugins matching the given type or an empty list of none match.</returns>
|
||||
public ICollection<T> GetPlugins<T>();
|
||||
|
||||
/// <summary>
|
||||
/// Get all plugins currently running on Kyoo. This also includes deleted plugins if the app as not been restarted.
|
||||
/// </summary>
|
||||
/// <returns>All plugins currently loaded.</returns>
|
||||
public ICollection<IPlugin> GetAllPlugins();
|
||||
/// <summary>
|
||||
/// Get all plugins currently running on Kyoo. This also includes deleted plugins if the app as not been restarted.
|
||||
/// </summary>
|
||||
/// <returns>All plugins currently loaded.</returns>
|
||||
public ICollection<IPlugin> GetAllPlugins();
|
||||
|
||||
/// <summary>
|
||||
/// Load plugins and their dependencies from the plugin directory.
|
||||
/// </summary>
|
||||
/// <param name="plugins">
|
||||
/// An initial plugin list to use.
|
||||
/// You should not try to put plugins from the plugins directory here as they will get automatically loaded.
|
||||
/// </param>
|
||||
public void LoadPlugins(ICollection<IPlugin> plugins);
|
||||
/// <summary>
|
||||
/// Load plugins and their dependencies from the plugin directory.
|
||||
/// </summary>
|
||||
/// <param name="plugins">
|
||||
/// An initial plugin list to use.
|
||||
/// You should not try to put plugins from the plugins directory here as they will get automatically loaded.
|
||||
/// </param>
|
||||
public void LoadPlugins(ICollection<IPlugin> plugins);
|
||||
|
||||
/// <summary>
|
||||
/// Load plugins and their dependencies from the plugin directory.
|
||||
/// </summary>
|
||||
/// <param name="plugins">
|
||||
/// An initial plugin list to use.
|
||||
/// You should not try to put plugins from the plugins directory here as they will get automatically loaded.
|
||||
/// </param>
|
||||
public void LoadPlugins(params Type[] plugins);
|
||||
}
|
||||
/// <summary>
|
||||
/// Load plugins and their dependencies from the plugin directory.
|
||||
/// </summary>
|
||||
/// <param name="plugins">
|
||||
/// An initial plugin list to use.
|
||||
/// You should not try to put plugins from the plugins directory here as they will get automatically loaded.
|
||||
/// </param>
|
||||
public void LoadPlugins(params Type[] plugins);
|
||||
}
|
||||
|
||||
@@ -18,558 +18,250 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Kyoo.Abstractions.Models.Exceptions;
|
||||
using Kyoo.Abstractions.Models.Utils;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers
|
||||
namespace Kyoo.Abstractions.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// A common repository for every resources.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The resource's type that this repository manage.</typeparam>
|
||||
public interface IRepository<T> : IBaseRepository
|
||||
where T : IResource, IQuery
|
||||
{
|
||||
/// <summary>
|
||||
/// A common repository for every resources.
|
||||
/// The event handler type for all events of this repository.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The resource's type that this repository manage.</typeparam>
|
||||
public interface IRepository<T> : IBaseRepository
|
||||
where T : class, IResource
|
||||
{
|
||||
/// <summary>
|
||||
/// Get a resource from it's ID.
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the resource</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item could not be found.</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> Get(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Get a resource from it's slug.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the resource</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item could not be found.</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> Get(string slug);
|
||||
|
||||
/// <summary>
|
||||
/// Get the first resource that match the predicate.
|
||||
/// </summary>
|
||||
/// <param name="where">A predicate to filter the resource.</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item could not be found.</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> Get(Expression<Func<T, bool>> where);
|
||||
|
||||
/// <summary>
|
||||
/// Get a resource from it's ID or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the resource</param>
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<T> GetOrDefault(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Get a resource from it's slug or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the resource</param>
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<T> GetOrDefault(string slug);
|
||||
|
||||
/// <summary>
|
||||
/// Get the first resource that match the predicate or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="where">A predicate to filter the resource.</param>
|
||||
/// <param name="sortBy">A custom sort method to handle cases where multiples items match the filters.</param>
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<T> GetOrDefault(Expression<Func<T, bool>> where, Sort<T> sortBy = default);
|
||||
|
||||
/// <summary>
|
||||
/// Search for resources.
|
||||
/// </summary>
|
||||
/// <param name="query">The query string.</param>
|
||||
/// <returns>A list of resources found</returns>
|
||||
[ItemNotNull]
|
||||
Task<ICollection<T>> Search(string query);
|
||||
|
||||
/// <summary>
|
||||
/// Get every resources that match all filters
|
||||
/// </summary>
|
||||
/// <param name="where">A filter predicate</param>
|
||||
/// <param name="sort">Sort information about the query (sort by, sort order)</param>
|
||||
/// <param name="limit">How pagination should be done (where to start and how many to return)</param>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
[ItemNotNull]
|
||||
Task<ICollection<T>> GetAll(Expression<Func<T, bool>> where = null,
|
||||
Sort<T> sort = default,
|
||||
Pagination limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get every resources that match all filters
|
||||
/// </summary>
|
||||
/// <param name="where">A filter predicate</param>
|
||||
/// <param name="sort">A sort by predicate. The order is ascending.</param>
|
||||
/// <param name="limit">How pagination should be done (where to start and how many to return)</param>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
[ItemNotNull]
|
||||
Task<ICollection<T>> GetAll([Optional] Expression<Func<T, bool>> where,
|
||||
Expression<Func<T, object>> sort,
|
||||
Pagination limit = default
|
||||
) => GetAll(where, new Sort<T>(sort), limit);
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of resources that match the filter's predicate.
|
||||
/// </summary>
|
||||
/// <param name="where">A filter predicate</param>
|
||||
/// <returns>How many resources matched that filter</returns>
|
||||
Task<int> GetCount(Expression<Func<T, bool>> where = null);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new resource.
|
||||
/// </summary>
|
||||
/// <param name="obj">The item to register</param>
|
||||
/// <returns>The resource registers and completed by database's information (related items and so on)</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> Create([NotNull] T obj);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new resource if it does not exist already. If it does, the existing value is returned instead.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to create</param>
|
||||
/// <returns>The newly created item or the existing value if it existed.</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> CreateIfNotExists([NotNull] T obj);
|
||||
|
||||
/// <summary>
|
||||
/// Edit a resource
|
||||
/// </summary>
|
||||
/// <param name="edited">The resource to edit, it's ID can't change.</param>
|
||||
/// <param name="resetOld">Should old properties of the resource be discarded or should null values considered as not changed?</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The resource edited and completed by database's information (related items and so on)</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> Edit([NotNull] T edited, bool resetOld);
|
||||
|
||||
/// <summary>
|
||||
/// Delete a resource by it's ID
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the resource</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task Delete(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Delete a resource by it's slug
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the resource</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task Delete(string slug);
|
||||
|
||||
/// <summary>
|
||||
/// Delete a resource
|
||||
/// </summary>
|
||||
/// <param name="obj">The resource to delete</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task Delete([NotNull] T obj);
|
||||
|
||||
/// <summary>
|
||||
/// Delete all resources that match the predicate.
|
||||
/// </summary>
|
||||
/// <param name="where">A predicate to filter resources to delete. Every resource that match this will be deleted.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task DeleteAll([NotNull] Expression<Func<T, bool>> where);
|
||||
}
|
||||
/// <param name="resource">The resource created/modified/deleted</param>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
public delegate Task ResourceEventHandler(T resource);
|
||||
|
||||
/// <summary>
|
||||
/// A base class for repositories. Every service implementing this will be handled by the <see cref="ILibraryManager"/>.
|
||||
/// Get a resource from it's ID.
|
||||
/// </summary>
|
||||
public interface IBaseRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// The type for witch this repository is responsible or null if non applicable.
|
||||
/// </summary>
|
||||
Type RepositoryType { get; }
|
||||
}
|
||||
/// <param name="id">The id of the resource</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item could not be found.</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T> Get(Guid id, Include<T>? include = default);
|
||||
|
||||
/// <summary>
|
||||
/// A repository to handle shows.
|
||||
/// Get a resource from it's slug.
|
||||
/// </summary>
|
||||
public interface IShowRepository : IRepository<Show>
|
||||
{
|
||||
/// <summary>
|
||||
/// Link a show to a collection and/or a library. The given show is now part of those containers.
|
||||
/// If both a library and a collection are given, the collection is added to the library too.
|
||||
/// </summary>
|
||||
/// <param name="showID">The ID of the show</param>
|
||||
/// <param name="libraryID">The ID of the library (optional)</param>
|
||||
/// <param name="collectionID">The ID of the collection (optional)</param>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task AddShowLink(int showID, int? libraryID, int? collectionID);
|
||||
|
||||
/// <summary>
|
||||
/// Get a show's slug from it's ID.
|
||||
/// </summary>
|
||||
/// <param name="showID">The ID of the show</param>
|
||||
/// <exception cref="ItemNotFoundException">If a show with the given ID is not found.</exception>
|
||||
/// <returns>The show's slug</returns>
|
||||
Task<string> GetSlug(int showID);
|
||||
}
|
||||
/// <param name="slug">The slug of the resource</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item could not be found.</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T> Get(string slug, Include<T>? include = default);
|
||||
|
||||
/// <summary>
|
||||
/// A repository to handle seasons.
|
||||
/// Get the first resource that match the predicate.
|
||||
/// </summary>
|
||||
public interface ISeasonRepository : IRepository<Season>
|
||||
{
|
||||
/// <summary>
|
||||
/// Get a season from it's showID and it's seasonNumber
|
||||
/// </summary>
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The season found</returns>
|
||||
Task<Season> Get(int showID, int seasonNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a season from it's show slug and it's seasonNumber
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The season found</returns>
|
||||
Task<Season> Get(string showSlug, int seasonNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a season from it's showID and it's seasonNumber or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <returns>The season found</returns>
|
||||
Task<Season> GetOrDefault(int showID, int seasonNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a season from it's show slug and it's seasonNumber or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <returns>The season found</returns>
|
||||
Task<Season> GetOrDefault(string showSlug, int seasonNumber);
|
||||
}
|
||||
/// <param name="filter">A predicate to filter the resource.</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <param name="sortBy">A custom sort method to handle cases where multiples items match the filters.</param>
|
||||
/// <param name="reverse">Reverse the sort.</param>
|
||||
/// <param name="afterId">Select the first element after this id if it was in a list.</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item could not be found.</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T> Get(
|
||||
Filter<T> filter,
|
||||
Include<T>? include = default,
|
||||
Sort<T>? sortBy = default,
|
||||
bool reverse = false,
|
||||
Guid? afterId = default
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// The repository to handle episodes
|
||||
/// Get a resource from it's ID or null if it is not found.
|
||||
/// </summary>
|
||||
public interface IEpisodeRepository : IRepository<Episode>
|
||||
{
|
||||
// TODO replace the next methods with extension methods.
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's showID, it's seasonNumber and it's episode number.
|
||||
/// </summary>
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The episode found</returns>
|
||||
Task<Episode> Get(int showID, int seasonNumber, int episodeNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's show slug, it's seasonNumber and it's episode number.
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The episode found</returns>
|
||||
Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's showID, it's seasonNumber and it's episode number or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <returns>The episode found</returns>
|
||||
Task<Episode> GetOrDefault(int showID, int seasonNumber, int episodeNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's show slug, it's seasonNumber and it's episode number or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <returns>The episode found</returns>
|
||||
Task<Episode> GetOrDefault(string showSlug, int seasonNumber, int episodeNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's showID and it's absolute number.
|
||||
/// </summary>
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="absoluteNumber">The episode's absolute number (The episode number does not reset to 1 after the end of a season.</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The episode found</returns>
|
||||
Task<Episode> GetAbsolute(int showID, int absoluteNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's showID and it's absolute number.
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="absoluteNumber">The episode's absolute number (The episode number does not reset to 1 after the end of a season.</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The episode found</returns>
|
||||
Task<Episode> GetAbsolute(string showSlug, int absoluteNumber);
|
||||
}
|
||||
/// <param name="id">The id of the resource</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T?> GetOrDefault(Guid id, Include<T>? include = default);
|
||||
|
||||
/// <summary>
|
||||
/// A repository to handle tracks
|
||||
/// Get a resource from it's slug or null if it is not found.
|
||||
/// </summary>
|
||||
public interface ITrackRepository : IRepository<Track> { }
|
||||
/// <param name="slug">The slug of the resource</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T?> GetOrDefault(string slug, Include<T>? include = default);
|
||||
|
||||
/// <summary>
|
||||
/// A repository to handle libraries.
|
||||
/// Get the first resource that match the predicate or null if it is not found.
|
||||
/// </summary>
|
||||
public interface ILibraryRepository : IRepository<Library> { }
|
||||
/// <param name="filter">A predicate to filter the resource.</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <param name="sortBy">A custom sort method to handle cases where multiples items match the filters.</param>
|
||||
/// <param name="reverse">Reverse the sort.</param>
|
||||
/// <param name="afterId">Select the first element after this id if it was in a list.</param>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T?> GetOrDefault(
|
||||
Filter<T>? filter,
|
||||
Include<T>? include = default,
|
||||
Sort<T>? sortBy = default,
|
||||
bool reverse = false,
|
||||
Guid? afterId = default
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// A repository to handle library items (A wrapper around shows and collections).
|
||||
/// Search for resources with the database.
|
||||
/// </summary>
|
||||
public interface ILibraryItemRepository : IRepository<LibraryItem>
|
||||
{
|
||||
/// <summary>
|
||||
/// Get items (A wrapper around shows or collections) from a library.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the library</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No library exist with the given ID.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
public Task<ICollection<LibraryItem>> GetFromLibrary(int id,
|
||||
Expression<Func<LibraryItem, bool>> where = null,
|
||||
Sort<LibraryItem> sort = default,
|
||||
Pagination limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get items (A wrapper around shows or collections) from a library.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the library</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">A sort by method</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No library exist with the given ID.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
public Task<ICollection<LibraryItem>> GetFromLibrary(int id,
|
||||
[Optional] Expression<Func<LibraryItem, bool>> where,
|
||||
Expression<Func<LibraryItem, object>> sort,
|
||||
Pagination limit = default
|
||||
) => GetFromLibrary(id, where, new Sort<LibraryItem>(sort), limit);
|
||||
|
||||
/// <summary>
|
||||
/// Get items (A wrapper around shows or collections) from a library.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the library</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No library exist with the given slug.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
public Task<ICollection<LibraryItem>> GetFromLibrary(string slug,
|
||||
Expression<Func<LibraryItem, bool>> where = null,
|
||||
Sort<LibraryItem> sort = default,
|
||||
Pagination limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get items (A wrapper around shows or collections) from a library.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the library</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">A sort by method</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No library exist with the given slug.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
public Task<ICollection<LibraryItem>> GetFromLibrary(string slug,
|
||||
[Optional] Expression<Func<LibraryItem, bool>> where,
|
||||
Expression<Func<LibraryItem, object>> sort,
|
||||
Pagination limit = default
|
||||
) => GetFromLibrary(slug, where, new Sort<LibraryItem>(sort), limit);
|
||||
}
|
||||
/// <param name="query">The query string.</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>A list of resources found</returns>
|
||||
Task<ICollection<T>> Search(string query, Include<T>? include = default);
|
||||
|
||||
/// <summary>
|
||||
/// A repository for collections
|
||||
/// Get every resources that match all filters
|
||||
/// </summary>
|
||||
public interface ICollectionRepository : IRepository<Collection> { }
|
||||
/// <param name="filter">A filter predicate</param>
|
||||
/// <param name="sort">Sort information about the query (sort by, sort order)</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <param name="limit">How pagination should be done (where to start and how many to return)</param>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
Task<ICollection<T>> GetAll(
|
||||
Filter<T>? filter = null,
|
||||
Sort<T>? sort = default,
|
||||
Include<T>? include = default,
|
||||
Pagination? limit = default
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// A repository for genres.
|
||||
/// Get the number of resources that match the filter's predicate.
|
||||
/// </summary>
|
||||
public interface IGenreRepository : IRepository<Genre> { }
|
||||
/// <param name="filter">A filter predicate</param>
|
||||
/// <returns>How many resources matched that filter</returns>
|
||||
Task<int> GetCount(Filter<T>? filter = null);
|
||||
|
||||
/// <summary>
|
||||
/// A repository for studios.
|
||||
/// Map a list of ids to a list of items (keep the order).
|
||||
/// </summary>
|
||||
public interface IStudioRepository : IRepository<Studio> { }
|
||||
/// <param name="ids">The list of items id.</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>A list of resources mapped from ids.</returns>
|
||||
Task<ICollection<T>> FromIds(IList<Guid> ids, Include<T>? include = default);
|
||||
|
||||
/// <summary>
|
||||
/// A repository for people.
|
||||
/// Create a new resource.
|
||||
/// </summary>
|
||||
public interface IPeopleRepository : IRepository<People>
|
||||
{
|
||||
/// <summary>
|
||||
/// Get people's roles from a show.
|
||||
/// </summary>
|
||||
/// <param name="showID">The ID of the show</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="Show"/> exist with the given ID.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetFromShow(int showID,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a show.
|
||||
/// </summary>
|
||||
/// <param name="showID">The ID of the show</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">A sort by method</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="Show"/> exist with the given ID.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetFromShow(int showID,
|
||||
[Optional] Expression<Func<PeopleRole, bool>> where,
|
||||
Expression<Func<PeopleRole, object>> sort,
|
||||
Pagination limit = default
|
||||
) => GetFromShow(showID, where, new Sort<PeopleRole>(sort), limit);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a show.
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="Show"/> exist with the given slug.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetFromShow(string showSlug,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a show.
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">A sort by method</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="Show"/> exist with the given slug.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetFromShow(string showSlug,
|
||||
[Optional] Expression<Func<PeopleRole, bool>> where,
|
||||
Expression<Func<PeopleRole, object>> sort,
|
||||
Pagination limit = default
|
||||
) => GetFromShow(showSlug, where, new Sort<PeopleRole>(sort), limit);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a person.
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the person</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="People"/> exist with the given ID.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetFromPeople(int id,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a person.
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the person</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">A sort by method</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="People"/> exist with the given ID.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetFromPeople(int id,
|
||||
[Optional] Expression<Func<PeopleRole, bool>> where,
|
||||
Expression<Func<PeopleRole, object>> sort,
|
||||
Pagination limit = default
|
||||
) => GetFromPeople(id, where, new Sort<PeopleRole>(sort), limit);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a person.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the person</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="People"/> exist with the given slug.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetFromPeople(string slug,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a person.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the person</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">A sort by method</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="People"/> exist with the given slug.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetFromPeople(string slug,
|
||||
[Optional] Expression<Func<PeopleRole, bool>> where,
|
||||
Expression<Func<PeopleRole, object>> sort,
|
||||
Pagination limit = default
|
||||
) => GetFromPeople(slug, where, new Sort<PeopleRole>(sort), limit);
|
||||
}
|
||||
/// <param name="obj">The item to register</param>
|
||||
/// <returns>The resource registers and completed by database's information (related items and so on)</returns>
|
||||
Task<T> Create(T obj);
|
||||
|
||||
/// <summary>
|
||||
/// A repository to handle providers.
|
||||
/// Create a new resource if it does not exist already. If it does, the existing value is returned instead.
|
||||
/// </summary>
|
||||
public interface IProviderRepository : IRepository<Provider>
|
||||
{
|
||||
/// <summary>
|
||||
/// Get a list of external ids that match all filters
|
||||
/// </summary>
|
||||
/// <param name="where">A predicate to add arbitrary filter</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">Pagination information (where to start and how many to get)</param>
|
||||
/// <typeparam name="T">The type of metadata to retrieve</typeparam>
|
||||
/// <returns>A filtered list of external ids.</returns>
|
||||
Task<ICollection<MetadataID>> GetMetadataID<T>(Expression<Func<MetadataID, bool>> where = null,
|
||||
Sort<MetadataID> sort = default,
|
||||
Pagination limit = default)
|
||||
where T : class, IMetadata;
|
||||
|
||||
/// <summary>
|
||||
/// Get a list of external ids that match all filters
|
||||
/// </summary>
|
||||
/// <param name="where">A predicate to add arbitrary filter</param>
|
||||
/// <param name="sort">A sort by expression</param>
|
||||
/// <param name="limit">Pagination information (where to start and how many to get)</param>
|
||||
/// <typeparam name="T">The type of metadata to retrieve</typeparam>
|
||||
/// <returns>A filtered list of external ids.</returns>
|
||||
Task<ICollection<MetadataID>> GetMetadataID<T>([Optional] Expression<Func<MetadataID, bool>> where,
|
||||
Expression<Func<MetadataID, object>> sort,
|
||||
Pagination limit = default
|
||||
)
|
||||
where T : class, IMetadata
|
||||
=> GetMetadataID<T>(where, new Sort<MetadataID>(sort), limit);
|
||||
}
|
||||
/// <param name="obj">The object to create</param>
|
||||
/// <returns>The newly created item or the existing value if it existed.</returns>
|
||||
Task<T> CreateIfNotExists(T obj);
|
||||
|
||||
/// <summary>
|
||||
/// A repository to handle users.
|
||||
/// Called when a resource has been created.
|
||||
/// </summary>
|
||||
public interface IUserRepository : IRepository<User> { }
|
||||
static event ResourceEventHandler OnCreated;
|
||||
|
||||
/// <summary>
|
||||
/// Callback that should be called after a resource has been created.
|
||||
/// </summary>
|
||||
/// <param name="obj">The resource newly created.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
protected static Task OnResourceCreated(T obj) => OnCreated?.Invoke(obj) ?? Task.CompletedTask;
|
||||
|
||||
/// <summary>
|
||||
/// Edit a resource and replace every property
|
||||
/// </summary>
|
||||
/// <param name="edited">The resource to edit, it's ID can't change.</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The resource edited and completed by database's information (related items and so on)</returns>
|
||||
Task<T> Edit(T edited);
|
||||
|
||||
/// <summary>
|
||||
/// Edit only specific properties of a resource
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the resource to edit</param>
|
||||
/// <param name="patch">
|
||||
/// A method that will be called when you need to update every properties that you want to
|
||||
/// persist.
|
||||
/// </param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The resource edited and completed by database's information (related items and so on)</returns>
|
||||
Task<T> Patch(Guid id, Func<T, T> patch);
|
||||
|
||||
/// <summary>
|
||||
/// Called when a resource has been edited.
|
||||
/// </summary>
|
||||
static event ResourceEventHandler OnEdited;
|
||||
|
||||
/// <summary>
|
||||
/// Callback that should be called after a resource has been edited.
|
||||
/// </summary>
|
||||
/// <param name="obj">The resource newly edited.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
protected static Task OnResourceEdited(T obj) => OnEdited?.Invoke(obj) ?? Task.CompletedTask;
|
||||
|
||||
/// <summary>
|
||||
/// Delete a resource by it's ID
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the resource</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task Delete(Guid id);
|
||||
|
||||
/// <summary>
|
||||
/// Delete a resource by it's slug
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the resource</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task Delete(string slug);
|
||||
|
||||
/// <summary>
|
||||
/// Delete a resource
|
||||
/// </summary>
|
||||
/// <param name="obj">The resource to delete</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task Delete(T obj);
|
||||
|
||||
/// <summary>
|
||||
/// Delete all resources that match the predicate.
|
||||
/// </summary>
|
||||
/// <param name="filter">A predicate to filter resources to delete. Every resource that match this will be deleted.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task DeleteAll(Filter<T> filter);
|
||||
|
||||
/// <summary>
|
||||
/// Called when a resource has been edited.
|
||||
/// </summary>
|
||||
static event ResourceEventHandler OnDeleted;
|
||||
|
||||
/// <summary>
|
||||
/// Callback that should be called after a resource has been deleted.
|
||||
/// </summary>
|
||||
/// <param name="obj">The resource newly deleted.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
protected static Task OnResourceDeleted(T obj) => OnDeleted?.Invoke(obj) ?? Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A base class for repositories. Every service implementing this will be handled by the <see cref="ILibraryManager"/>.
|
||||
/// </summary>
|
||||
public interface IBaseRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// The type for witch this repository is responsible or null if non applicable.
|
||||
/// </summary>
|
||||
Type RepositoryType { get; }
|
||||
}
|
||||
|
||||
public interface IUserRepository : IRepository<User>
|
||||
{
|
||||
Task<User?> GetByExternalId(string provider, string id);
|
||||
Task<User> AddExternalToken(Guid userId, string provider, ExternalToken token);
|
||||
Task<User> DeleteExternalToken(Guid userId, string provider);
|
||||
}
|
||||
|
||||
119
back/src/Kyoo.Abstractions/Controllers/ISearchManager.cs
Normal file
119
back/src/Kyoo.Abstractions/Controllers/ISearchManager.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Kyoo.Abstractions.Models.Utils;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// The service to search items.
|
||||
/// </summary>
|
||||
public interface ISearchManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Search for items.
|
||||
/// </summary>
|
||||
/// <param name="query">The seach query.</param>
|
||||
/// <param name="sortBy">Sort information about the query (sort by, sort order)</param>
|
||||
/// <param name="pagination">How pagination should be done (where to start and how many to return)</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
public Task<SearchPage<ILibraryItem>.SearchResult> SearchItems(
|
||||
string? query,
|
||||
Sort<ILibraryItem> sortBy,
|
||||
SearchPagination pagination,
|
||||
Include<ILibraryItem>? include = default
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Search for movies.
|
||||
/// </summary>
|
||||
/// <param name="query">The seach query.</param>
|
||||
/// <param name="sortBy">Sort information about the query (sort by, sort order)</param>
|
||||
/// <param name="pagination">How pagination should be done (where to start and how many to return)</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
public Task<SearchPage<Movie>.SearchResult> SearchMovies(
|
||||
string? query,
|
||||
Sort<Movie> sortBy,
|
||||
SearchPagination pagination,
|
||||
Include<Movie>? include = default
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Search for shows.
|
||||
/// </summary>
|
||||
/// <param name="query">The seach query.</param>
|
||||
/// <param name="sortBy">Sort information about the query (sort by, sort order)</param>
|
||||
/// <param name="pagination">How pagination should be done (where to start and how many to return)</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
public Task<SearchPage<Show>.SearchResult> SearchShows(
|
||||
string? query,
|
||||
Sort<Show> sortBy,
|
||||
SearchPagination pagination,
|
||||
Include<Show>? include = default
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Search for collections.
|
||||
/// </summary>
|
||||
/// <param name="query">The seach query.</param>
|
||||
/// <param name="sortBy">Sort information about the query (sort by, sort order)</param>
|
||||
/// <param name="pagination">How pagination should be done (where to start and how many to return)</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
public Task<SearchPage<Collection>.SearchResult> SearchCollections(
|
||||
string? query,
|
||||
Sort<Collection> sortBy,
|
||||
SearchPagination pagination,
|
||||
Include<Collection>? include = default
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Search for episodes.
|
||||
/// </summary>
|
||||
/// <param name="query">The seach query.</param>
|
||||
/// <param name="sortBy">Sort information about the query (sort by, sort order)</param>
|
||||
/// <param name="pagination">How pagination should be done (where to start and how many to return)</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
public Task<SearchPage<Episode>.SearchResult> SearchEpisodes(
|
||||
string? query,
|
||||
Sort<Episode> sortBy,
|
||||
SearchPagination pagination,
|
||||
Include<Episode>? include = default
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Search for studios.
|
||||
/// </summary>
|
||||
/// <param name="query">The seach query.</param>
|
||||
/// <param name="sortBy">Sort information about the query (sort by, sort order)</param>
|
||||
/// <param name="pagination">How pagination should be done (where to start and how many to return)</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
public Task<SearchPage<Studio>.SearchResult> SearchStudios(
|
||||
string? query,
|
||||
Sort<Studio> sortBy,
|
||||
SearchPagination pagination,
|
||||
Include<Studio>? include = default
|
||||
);
|
||||
}
|
||||
@@ -1,212 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Kyoo.Abstractions.Models.Exceptions;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// A common interface that tasks should implement.
|
||||
/// </summary>
|
||||
public interface ITask
|
||||
{
|
||||
/// <summary>
|
||||
/// The list of parameters
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// All parameters that this task as. Every one of them will be given to the run function with a value.
|
||||
/// </returns>
|
||||
public TaskParameters GetParameters();
|
||||
|
||||
/// <summary>
|
||||
/// Start this task.
|
||||
/// </summary>
|
||||
/// <param name="arguments">
|
||||
/// The list of parameters.
|
||||
/// </param>
|
||||
/// <param name="progress">
|
||||
/// The progress reporter. Used to inform the sender the percentage of completion of this task
|
||||
/// .</param>
|
||||
/// <param name="cancellationToken">A token to request the task's cancellation.
|
||||
/// If this task is not cancelled quickly, it might be killed by the runner.
|
||||
/// </param>
|
||||
/// <exception cref="TaskFailedException">
|
||||
/// An exception meaning that the task has failed for handled reasons like invalid arguments,
|
||||
/// invalid environment, missing plugins or failures not related to a default in the code.
|
||||
/// This exception allow the task to display a failure message to the end user while others exceptions
|
||||
/// will be displayed as unhandled exceptions and display a stack trace.
|
||||
/// </exception>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
public Task Run([NotNull] TaskParameters arguments,
|
||||
[NotNull] IProgress<float> progress,
|
||||
CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A single task parameter. This struct contains metadata to display and utility functions to get them in the task.
|
||||
/// </summary>
|
||||
/// <remarks>This struct will be used to generate the swagger documentation of the task.</remarks>
|
||||
public record TaskParameter
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of this parameter.
|
||||
/// </summary>
|
||||
public string Name { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The description of this parameter.
|
||||
/// </summary>
|
||||
public string Description { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of this parameter.
|
||||
/// </summary>
|
||||
public Type Type { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Is this parameter required or can it be ignored?
|
||||
/// </summary>
|
||||
public bool IsRequired { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The default value of this object.
|
||||
/// </summary>
|
||||
public object DefaultValue { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The value of the parameter.
|
||||
/// </summary>
|
||||
private object _Value { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new task parameter.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the parameter</param>
|
||||
/// <param name="description">The description of the parameter</param>
|
||||
/// <typeparam name="T">The type of the parameter.</typeparam>
|
||||
/// <returns>A new task parameter.</returns>
|
||||
public static TaskParameter Create<T>(string name, string description)
|
||||
{
|
||||
return new TaskParameter
|
||||
{
|
||||
Name = name,
|
||||
Description = description,
|
||||
Type = typeof(T)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new required task parameter.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the parameter</param>
|
||||
/// <param name="description">The description of the parameter</param>
|
||||
/// <typeparam name="T">The type of the parameter.</typeparam>
|
||||
/// <returns>A new task parameter.</returns>
|
||||
public static TaskParameter CreateRequired<T>(string name, string description)
|
||||
{
|
||||
return new TaskParameter
|
||||
{
|
||||
Name = name,
|
||||
Description = description,
|
||||
Type = typeof(T),
|
||||
IsRequired = true
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a parameter's value to give to a task.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the parameter</param>
|
||||
/// <param name="value">The value of the parameter. It's type will be used as parameter's type.</param>
|
||||
/// <typeparam name="T">The type of the parameter</typeparam>
|
||||
/// <returns>A TaskParameter that can be used as value.</returns>
|
||||
public static TaskParameter CreateValue<T>(string name, T value)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Name = name,
|
||||
Type = typeof(T),
|
||||
_Value = value
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a parameter's value for the current parameter.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to use</param>
|
||||
/// <returns>A new parameter's value for this current parameter</returns>
|
||||
public TaskParameter CreateValue(object value)
|
||||
{
|
||||
return this with { _Value = value };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the value of this parameter. If the value is of the wrong type, it will be converted.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of this parameter</typeparam>
|
||||
/// <returns>The value of this parameter.</returns>
|
||||
public T As<T>()
|
||||
{
|
||||
if (typeof(T) == typeof(object))
|
||||
return (T)_Value;
|
||||
|
||||
if (_Value is IResource resource)
|
||||
{
|
||||
if (typeof(T) == typeof(string))
|
||||
return (T)(object)resource.Slug;
|
||||
if (typeof(T) == typeof(int))
|
||||
return (T)(object)resource.ID;
|
||||
}
|
||||
|
||||
return (T)Convert.ChangeType(_Value, typeof(T));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A parameters container implementing an indexer to allow simple usage of parameters.
|
||||
/// </summary>
|
||||
public class TaskParameters : List<TaskParameter>
|
||||
{
|
||||
/// <summary>
|
||||
/// An indexer that return the parameter with the specified name.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the task (case sensitive)</param>
|
||||
public TaskParameter this[string name] => this.FirstOrDefault(x => x.Name == name);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new, empty, <see cref="TaskParameters"/>
|
||||
/// </summary>
|
||||
public TaskParameters() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="TaskParameters"/> with an initial parameters content.
|
||||
/// </summary>
|
||||
/// <param name="parameters">The list of parameters</param>
|
||||
public TaskParameters(IEnumerable<TaskParameter> parameters)
|
||||
{
|
||||
AddRange(parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading;
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
using Kyoo.Abstractions.Models.Exceptions;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// A service to handle long running tasks.
|
||||
/// </summary>
|
||||
/// <remarks>The concurrent number of running tasks is implementation dependent.</remarks>
|
||||
public interface ITaskManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Start a new task (or queue it).
|
||||
/// </summary>
|
||||
/// <param name="taskSlug">
|
||||
/// The slug of the task to run.
|
||||
/// </param>
|
||||
/// <param name="progress">
|
||||
/// A progress reporter to know the percentage of completion of the task.
|
||||
/// </param>
|
||||
/// <param name="arguments">
|
||||
/// A list of arguments to pass to the task. An automatic conversion will be made if arguments to not fit.
|
||||
/// </param>
|
||||
/// <param name="cancellationToken">
|
||||
/// A custom cancellation token for the task.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// If the number of arguments is invalid, if an argument can't be converted or if the task finds the argument
|
||||
/// invalid.
|
||||
/// </exception>
|
||||
/// <exception cref="ItemNotFoundException">
|
||||
/// The task could not be found.
|
||||
/// </exception>
|
||||
void StartTask(string taskSlug,
|
||||
[NotNull] IProgress<float> progress,
|
||||
Dictionary<string, object> arguments = null,
|
||||
CancellationToken? cancellationToken = null);
|
||||
|
||||
/// <summary>
|
||||
/// Start a new task (or queue it).
|
||||
/// </summary>
|
||||
/// <param name="progress">
|
||||
/// A progress reporter to know the percentage of completion of the task.
|
||||
/// </param>
|
||||
/// <param name="arguments">
|
||||
/// A list of arguments to pass to the task. An automatic conversion will be made if arguments to not fit.
|
||||
/// </param>
|
||||
/// <typeparam name="T">
|
||||
/// The type of the task to start.
|
||||
/// </typeparam>
|
||||
/// <param name="cancellationToken">
|
||||
/// A custom cancellation token for the task.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// If the number of arguments is invalid, if an argument can't be converted or if the task finds the argument
|
||||
/// invalid.
|
||||
/// </exception>
|
||||
/// <exception cref="ItemNotFoundException">
|
||||
/// The task could not be found.
|
||||
/// </exception>
|
||||
void StartTask<T>([NotNull] IProgress<float> progress,
|
||||
Dictionary<string, object> arguments = null,
|
||||
CancellationToken? cancellationToken = null)
|
||||
where T : ITask;
|
||||
|
||||
/// <summary>
|
||||
/// Get all currently running tasks
|
||||
/// </summary>
|
||||
/// <returns>A list of currently running tasks.</returns>
|
||||
ICollection<(TaskMetadataAttribute, ITask)> GetRunningTasks();
|
||||
|
||||
/// <summary>
|
||||
/// Get all available tasks
|
||||
/// </summary>
|
||||
/// <returns>A list of every tasks that this instance know.</returns>
|
||||
ICollection<TaskMetadataAttribute> GetAllTasks();
|
||||
}
|
||||
}
|
||||
@@ -16,40 +16,63 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Kyoo.Abstractions.Models;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers
|
||||
namespace Kyoo.Abstractions.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Download images and retrieve the path of those images for a resource.
|
||||
/// </summary>
|
||||
public interface IThumbnailsManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Download images and retrieve the path of those images for a resource.
|
||||
/// Download images of a specified item.
|
||||
/// If no images is available to download, do nothing and silently return.
|
||||
/// </summary>
|
||||
public interface IThumbnailsManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Download images of a specified item.
|
||||
/// If no images is available to download, do nothing and silently return.
|
||||
/// </summary>
|
||||
/// <param name="item">
|
||||
/// The item to cache images.
|
||||
/// </param>
|
||||
/// <param name="alwaysDownload">
|
||||
/// <c>true</c> if images should be downloaded even if they already exists locally, <c>false</c> otherwise.
|
||||
/// </param>
|
||||
/// <typeparam name="T">The type of the item</typeparam>
|
||||
/// <returns><c>true</c> if an image has been downloaded, <c>false</c> otherwise.</returns>
|
||||
Task<bool> DownloadImages<T>([NotNull] T item, bool alwaysDownload = false)
|
||||
where T : IThumbnails;
|
||||
/// <param name="item">
|
||||
/// The item to cache images.
|
||||
/// </param>
|
||||
/// <typeparam name="T">The type of the item</typeparam>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task DownloadImages<T>(T item)
|
||||
where T : IThumbnails;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the local path of an image of the given item.
|
||||
/// </summary>
|
||||
/// <param name="item">The item to retrieve the poster from.</param>
|
||||
/// <param name="imageID">The ID of the image. See <see cref="Images"/> for values.</param>
|
||||
/// <typeparam name="T">The type of the item</typeparam>
|
||||
/// <returns>The path of the image for the given resource or null if it does not exists.</returns>
|
||||
Task<string> GetImagePath<T>([NotNull] T item, int imageID)
|
||||
where T : IThumbnails;
|
||||
}
|
||||
/// <summary>
|
||||
/// Retrieve the local path of an image of the given item.
|
||||
/// </summary>
|
||||
/// <param name="item">The item to retrieve the poster from.</param>
|
||||
/// <param name="image">The ID of the image.</param>
|
||||
/// <param name="quality">The quality of the image</param>
|
||||
/// <typeparam name="T">The type of the item</typeparam>
|
||||
/// <returns>The path of the image for the given resource or null if it does not exists.</returns>
|
||||
string GetImagePath<T>(T item, string image, ImageQuality quality)
|
||||
where T : IThumbnails;
|
||||
|
||||
/// <summary>
|
||||
/// Delete images associated with the item.
|
||||
/// </summary>
|
||||
/// <param name="item">
|
||||
/// The item with cached images.
|
||||
/// </param>
|
||||
/// <typeparam name="T">The type of the item</typeparam>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task DeleteImages<T>(T item)
|
||||
where T : IThumbnails;
|
||||
|
||||
/// <summary>
|
||||
/// Set the user's profile picture
|
||||
/// </summary>
|
||||
/// <param name="userId">The id of the user. </param>
|
||||
/// <returns>The byte stream of the image. Null if no image exist.</returns>
|
||||
Task<Stream> GetUserImage(Guid userId);
|
||||
|
||||
/// <summary>
|
||||
/// Set the user's profile picture
|
||||
/// </summary>
|
||||
/// <param name="userId">The id of the user. </param>
|
||||
/// <param name="image">The byte stream of the image. Null to delete the image.</param>
|
||||
Task SetUserImage(Guid userId, Stream? image);
|
||||
}
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Transcoder responsible of handling low level video details.
|
||||
/// </summary>
|
||||
public interface ITranscoder
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieve tracks for a specific episode.
|
||||
/// Subtitles, chapters and fonts should also be extracted and cached when calling this method.
|
||||
/// </summary>
|
||||
/// <param name="episode">The episode to retrieve tracks for.</param>
|
||||
/// <param name="reExtract">Should the cache be invalidated and subtitles and others be re-extracted?</param>
|
||||
/// <returns>The list of tracks available for this episode.</returns>
|
||||
Task<ICollection<Track>> ExtractInfos(Episode episode, bool reExtract);
|
||||
|
||||
/// <summary>
|
||||
/// List fonts assosiated with this episode.
|
||||
/// </summary>
|
||||
/// <param name="episode">Th episode to list fonts for.</param>
|
||||
/// <returns>The list of attachements for this epiosode.</returns>
|
||||
Task<ICollection<Font>> ListFonts(Episode episode);
|
||||
|
||||
/// <summary>
|
||||
/// Get the specified font for this episode.
|
||||
/// </summary>
|
||||
/// <param name="episode">The episode to list fonts for.</param>
|
||||
/// <param name="slug">The slug of the specific font to retrive.</param>
|
||||
/// <returns>The <see cref="Font"/> with the given slug or null.</returns>
|
||||
[ItemCanBeNull] Task<Font> GetFont(Episode episode, string slug);
|
||||
|
||||
/// <summary>
|
||||
/// Transmux the selected episode to hls.
|
||||
/// </summary>
|
||||
/// <param name="episode">The episode to transmux.</param>
|
||||
/// <returns>The master file (m3u8) of the transmuxed hls file.</returns>
|
||||
IActionResult Transmux(Episode episode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Kyoo.Abstractions.Models.Utils;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// A local repository to handle watched items
|
||||
/// </summary>
|
||||
public interface IWatchStatusRepository
|
||||
{
|
||||
public delegate Task ResourceEventHandler<T>(T resource);
|
||||
|
||||
Task<ICollection<IWatchlist>> GetAll(
|
||||
Filter<IWatchlist>? filter = default,
|
||||
Include<IWatchlist>? include = default,
|
||||
Pagination? limit = default
|
||||
);
|
||||
|
||||
Task<MovieWatchStatus?> GetMovieStatus(Guid movieId, Guid userId);
|
||||
|
||||
Task<MovieWatchStatus?> SetMovieStatus(
|
||||
Guid movieId,
|
||||
Guid userId,
|
||||
WatchStatus status,
|
||||
int? watchedTime,
|
||||
int? percent
|
||||
);
|
||||
|
||||
static event ResourceEventHandler<WatchStatus<Movie>> OnMovieStatusChangedHandler;
|
||||
protected static Task OnMovieStatusChanged(WatchStatus<Movie> obj) =>
|
||||
OnMovieStatusChangedHandler?.Invoke(obj) ?? Task.CompletedTask;
|
||||
|
||||
Task DeleteMovieStatus(Guid movieId, Guid userId);
|
||||
|
||||
Task<ShowWatchStatus?> GetShowStatus(Guid showId, Guid userId);
|
||||
|
||||
Task<ShowWatchStatus?> SetShowStatus(Guid showId, Guid userId, WatchStatus status);
|
||||
|
||||
static event ResourceEventHandler<WatchStatus<Show>> OnShowStatusChangedHandler;
|
||||
protected static Task OnShowStatusChanged(WatchStatus<Show> obj) =>
|
||||
OnShowStatusChangedHandler?.Invoke(obj) ?? Task.CompletedTask;
|
||||
|
||||
Task DeleteShowStatus(Guid showId, Guid userId);
|
||||
|
||||
Task<EpisodeWatchStatus?> GetEpisodeStatus(Guid episodeId, Guid userId);
|
||||
|
||||
/// <param name="watchedTime">Where the user has stopped watching. Only usable if Status
|
||||
/// is <see cref="WatchStatus.Watching"/></param>
|
||||
Task<EpisodeWatchStatus?> SetEpisodeStatus(
|
||||
Guid episodeId,
|
||||
Guid userId,
|
||||
WatchStatus status,
|
||||
int? watchedTime,
|
||||
int? percent
|
||||
);
|
||||
|
||||
static event ResourceEventHandler<WatchStatus<Episode>> OnEpisodeStatusChangedHandler;
|
||||
protected static Task OnEpisodeStatusChanged(WatchStatus<Episode> obj) =>
|
||||
OnEpisodeStatusChangedHandler?.Invoke(obj) ?? Task.CompletedTask;
|
||||
|
||||
Task DeleteEpisodeStatus(Guid episodeId, Guid userId);
|
||||
}
|
||||
@@ -17,253 +17,254 @@
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers
|
||||
namespace Kyoo.Abstractions.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// A list of constant priorities used for <see cref="IStartupAction"/>'s <see cref="IStartupAction.Priority"/>.
|
||||
/// It also contains helper methods for creating new <see cref="StartupAction"/>.
|
||||
/// </summary>
|
||||
public static class SA
|
||||
{
|
||||
/// <summary>
|
||||
/// A list of constant priorities used for <see cref="IStartupAction"/>'s <see cref="IStartupAction.Priority"/>.
|
||||
/// It also contains helper methods for creating new <see cref="StartupAction"/>.
|
||||
/// The highest predefined priority existing for <see cref="StartupAction"/>.
|
||||
/// </summary>
|
||||
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1649:File name should match first type name",
|
||||
Justification = "StartupAction is nested and the name SA is short to improve readability in plugin's startup.")]
|
||||
public static class SA
|
||||
public const int Before = 5000;
|
||||
|
||||
/// <summary>
|
||||
/// Items defining routing (see IApplicationBuilder.UseRouting use this priority.
|
||||
/// </summary>
|
||||
public const int Routing = 4000;
|
||||
|
||||
/// <summary>
|
||||
/// Actions defining new static files router use this priority.
|
||||
/// </summary>
|
||||
public const int StaticFiles = 3000;
|
||||
|
||||
/// <summary>
|
||||
/// Actions calling IApplicationBuilder.UseAuthentication use this priority.
|
||||
/// </summary>
|
||||
public const int Authentication = 2000;
|
||||
|
||||
/// <summary>
|
||||
/// Actions calling IApplicationBuilder.UseAuthorization use this priority.
|
||||
/// </summary>
|
||||
public const int Authorization = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// Action adding endpoint should use this priority (with a negative modificator if there is a catchall).
|
||||
/// </summary>
|
||||
public const int Endpoint = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The lowest predefined priority existing for <see cref="StartupAction"/>.
|
||||
/// It should run after all other actions.
|
||||
/// </summary>
|
||||
public const int After = -1000;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="StartupAction"/>.
|
||||
/// </summary>
|
||||
/// <param name="action">The action to run</param>
|
||||
/// <param name="priority">The priority of the new action</param>
|
||||
/// <returns>A new <see cref="StartupAction"/></returns>
|
||||
public static StartupAction New(Action action, int priority) => new(action, priority);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="StartupAction"/>.
|
||||
/// </summary>
|
||||
/// <param name="action">The action to run</param>
|
||||
/// <param name="priority">The priority of the new action</param>
|
||||
/// <typeparam name="T">A dependency that this action will use.</typeparam>
|
||||
/// <returns>A new <see cref="StartupAction"/></returns>
|
||||
public static StartupAction<T> New<T>(Action<T> action, int priority)
|
||||
where T : notnull => new(action, priority);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="StartupAction"/>.
|
||||
/// </summary>
|
||||
/// <param name="action">The action to run</param>
|
||||
/// <param name="priority">The priority of the new action</param>
|
||||
/// <typeparam name="T">A dependency that this action will use.</typeparam>
|
||||
/// <typeparam name="T2">A second dependency that this action will use.</typeparam>
|
||||
/// <returns>A new <see cref="StartupAction"/></returns>
|
||||
public static StartupAction<T, T2> New<T, T2>(Action<T, T2> action, int priority)
|
||||
where T : notnull
|
||||
where T2 : notnull => new(action, priority);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="StartupAction"/>.
|
||||
/// </summary>
|
||||
/// <param name="action">The action to run</param>
|
||||
/// <param name="priority">The priority of the new action</param>
|
||||
/// <typeparam name="T">A dependency that this action will use.</typeparam>
|
||||
/// <typeparam name="T2">A second dependency that this action will use.</typeparam>
|
||||
/// <typeparam name="T3">A third dependency that this action will use.</typeparam>
|
||||
/// <returns>A new <see cref="StartupAction"/></returns>
|
||||
public static StartupAction<T, T2, T3> New<T, T2, T3>(Action<T, T2, T3> action, int priority)
|
||||
where T : notnull
|
||||
where T2 : notnull
|
||||
where T3 : notnull => new(action, priority);
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="IStartupAction"/> with no dependencies.
|
||||
/// </summary>
|
||||
public class StartupAction : IStartupAction
|
||||
{
|
||||
/// <summary>
|
||||
/// The highest predefined priority existing for <see cref="StartupAction"/>.
|
||||
/// The action to execute at startup.
|
||||
/// </summary>
|
||||
public const int Before = 5000;
|
||||
private readonly Action _action;
|
||||
|
||||
/// <summary>
|
||||
/// Items defining routing (see IApplicationBuilder.UseRouting use this priority.
|
||||
/// </summary>
|
||||
public const int Routing = 4000;
|
||||
|
||||
/// <summary>
|
||||
/// Actions defining new static files router use this priority.
|
||||
/// </summary>
|
||||
public const int StaticFiles = 3000;
|
||||
|
||||
/// <summary>
|
||||
/// Actions calling IApplicationBuilder.UseAuthentication use this priority.
|
||||
/// </summary>
|
||||
public const int Authentication = 2000;
|
||||
|
||||
/// <summary>
|
||||
/// Actions calling IApplicationBuilder.UseAuthorization use this priority.
|
||||
/// </summary>
|
||||
public const int Authorization = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// Action adding endpoint should use this priority (with a negative modificator if there is a catchall).
|
||||
/// </summary>
|
||||
public const int Endpoint = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The lowest predefined priority existing for <see cref="StartupAction"/>.
|
||||
/// It should run after all other actions.
|
||||
/// </summary>
|
||||
public const int After = -1000;
|
||||
/// <inheritdoc />
|
||||
public int Priority { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="StartupAction"/>.
|
||||
/// </summary>
|
||||
/// <param name="action">The action to run</param>
|
||||
/// <param name="priority">The priority of the new action</param>
|
||||
/// <returns>A new <see cref="StartupAction"/></returns>
|
||||
public static StartupAction New(Action action, int priority)
|
||||
=> new(action, priority);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="StartupAction"/>.
|
||||
/// </summary>
|
||||
/// <param name="action">The action to run</param>
|
||||
/// <param name="priority">The priority of the new action</param>
|
||||
/// <typeparam name="T">A dependency that this action will use.</typeparam>
|
||||
/// <returns>A new <see cref="StartupAction"/></returns>
|
||||
public static StartupAction<T> New<T>(Action<T> action, int priority)
|
||||
=> new(action, priority);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="StartupAction"/>.
|
||||
/// </summary>
|
||||
/// <param name="action">The action to run</param>
|
||||
/// <param name="priority">The priority of the new action</param>
|
||||
/// <typeparam name="T">A dependency that this action will use.</typeparam>
|
||||
/// <typeparam name="T2">A second dependency that this action will use.</typeparam>
|
||||
/// <returns>A new <see cref="StartupAction"/></returns>
|
||||
public static StartupAction<T, T2> New<T, T2>(Action<T, T2> action, int priority)
|
||||
=> new(action, priority);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="StartupAction"/>.
|
||||
/// </summary>
|
||||
/// <param name="action">The action to run</param>
|
||||
/// <param name="priority">The priority of the new action</param>
|
||||
/// <typeparam name="T">A dependency that this action will use.</typeparam>
|
||||
/// <typeparam name="T2">A second dependency that this action will use.</typeparam>
|
||||
/// <typeparam name="T3">A third dependency that this action will use.</typeparam>
|
||||
/// <returns>A new <see cref="StartupAction"/></returns>
|
||||
public static StartupAction<T, T2, T3> New<T, T2, T3>(Action<T, T2, T3> action, int priority)
|
||||
=> new(action, priority);
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="IStartupAction"/> with no dependencies.
|
||||
/// </summary>
|
||||
public class StartupAction : IStartupAction
|
||||
/// <param name="action">The action to execute on startup.</param>
|
||||
/// <param name="priority">The priority of this action (see <see cref="Priority"/>).</param>
|
||||
public StartupAction(Action action, int priority)
|
||||
{
|
||||
/// <summary>
|
||||
/// The action to execute at startup.
|
||||
/// </summary>
|
||||
private readonly Action _action;
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Priority { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="StartupAction"/>.
|
||||
/// </summary>
|
||||
/// <param name="action">The action to execute on startup.</param>
|
||||
/// <param name="priority">The priority of this action (see <see cref="Priority"/>).</param>
|
||||
public StartupAction(Action action, int priority)
|
||||
{
|
||||
_action = action;
|
||||
Priority = priority;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Run(IServiceProvider provider)
|
||||
{
|
||||
_action.Invoke();
|
||||
}
|
||||
_action = action;
|
||||
Priority = priority;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="IStartupAction"/> with one dependencies.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The dependency to use.</typeparam>
|
||||
public class StartupAction<T> : IStartupAction
|
||||
/// <inheritdoc />
|
||||
public void Run(IServiceProvider provider)
|
||||
{
|
||||
/// <summary>
|
||||
/// The action to execute at startup.
|
||||
/// </summary>
|
||||
private readonly Action<T> _action;
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Priority { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="StartupAction{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="action">The action to execute on startup.</param>
|
||||
/// <param name="priority">The priority of this action (see <see cref="Priority"/>).</param>
|
||||
public StartupAction(Action<T> action, int priority)
|
||||
{
|
||||
_action = action;
|
||||
Priority = priority;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Run(IServiceProvider provider)
|
||||
{
|
||||
_action.Invoke(provider.GetRequiredService<T>());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="IStartupAction"/> with two dependencies.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The dependency to use.</typeparam>
|
||||
/// <typeparam name="T2">The second dependency to use.</typeparam>
|
||||
public class StartupAction<T, T2> : IStartupAction
|
||||
{
|
||||
/// <summary>
|
||||
/// The action to execute at startup.
|
||||
/// </summary>
|
||||
private readonly Action<T, T2> _action;
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Priority { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="StartupAction{T, T2}"/>.
|
||||
/// </summary>
|
||||
/// <param name="action">The action to execute on startup.</param>
|
||||
/// <param name="priority">The priority of this action (see <see cref="Priority"/>).</param>
|
||||
public StartupAction(Action<T, T2> action, int priority)
|
||||
{
|
||||
_action = action;
|
||||
Priority = priority;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Run(IServiceProvider provider)
|
||||
{
|
||||
_action.Invoke(
|
||||
provider.GetRequiredService<T>(),
|
||||
provider.GetRequiredService<T2>()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="IStartupAction"/> with three dependencies.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The dependency to use.</typeparam>
|
||||
/// <typeparam name="T2">The second dependency to use.</typeparam>
|
||||
/// <typeparam name="T3">The third dependency to use.</typeparam>
|
||||
public class StartupAction<T, T2, T3> : IStartupAction
|
||||
{
|
||||
/// <summary>
|
||||
/// The action to execute at startup.
|
||||
/// </summary>
|
||||
private readonly Action<T, T2, T3> _action;
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Priority { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="StartupAction{T, T2, T3}"/>.
|
||||
/// </summary>
|
||||
/// <param name="action">The action to execute on startup.</param>
|
||||
/// <param name="priority">The priority of this action (see <see cref="Priority"/>).</param>
|
||||
public StartupAction(Action<T, T2, T3> action, int priority)
|
||||
{
|
||||
_action = action;
|
||||
Priority = priority;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Run(IServiceProvider provider)
|
||||
{
|
||||
_action.Invoke(
|
||||
provider.GetRequiredService<T>(),
|
||||
provider.GetRequiredService<T2>(),
|
||||
provider.GetRequiredService<T3>()
|
||||
);
|
||||
}
|
||||
_action.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An action executed on kyoo's startup to initialize the asp-net container.
|
||||
/// A <see cref="IStartupAction"/> with one dependencies.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the base interface, see <see cref="SA.StartupAction"/> for a simpler use of this.
|
||||
/// </remarks>
|
||||
public interface IStartupAction
|
||||
/// <typeparam name="T">The dependency to use.</typeparam>
|
||||
public class StartupAction<T> : IStartupAction
|
||||
where T : notnull
|
||||
{
|
||||
/// <summary>
|
||||
/// The priority of this action. The actions will be executed on descending priority order.
|
||||
/// If two actions have the same priority, their order is undefined.
|
||||
/// The action to execute at startup.
|
||||
/// </summary>
|
||||
int Priority { get; }
|
||||
private readonly Action<T> _action;
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Priority { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Run this action to configure the container, a service provider containing all services can be used.
|
||||
/// Create a new <see cref="StartupAction{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="provider">The service provider containing all services can be used.</param>
|
||||
void Run(IServiceProvider provider);
|
||||
/// <param name="action">The action to execute on startup.</param>
|
||||
/// <param name="priority">The priority of this action (see <see cref="Priority"/>).</param>
|
||||
public StartupAction(Action<T> action, int priority)
|
||||
{
|
||||
_action = action;
|
||||
Priority = priority;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Run(IServiceProvider provider)
|
||||
{
|
||||
_action.Invoke(provider.GetRequiredService<T>());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="IStartupAction"/> with two dependencies.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The dependency to use.</typeparam>
|
||||
/// <typeparam name="T2">The second dependency to use.</typeparam>
|
||||
public class StartupAction<T, T2> : IStartupAction
|
||||
where T : notnull
|
||||
where T2 : notnull
|
||||
{
|
||||
/// <summary>
|
||||
/// The action to execute at startup.
|
||||
/// </summary>
|
||||
private readonly Action<T, T2> _action;
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Priority { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="StartupAction{T, T2}"/>.
|
||||
/// </summary>
|
||||
/// <param name="action">The action to execute on startup.</param>
|
||||
/// <param name="priority">The priority of this action (see <see cref="Priority"/>).</param>
|
||||
public StartupAction(Action<T, T2> action, int priority)
|
||||
{
|
||||
_action = action;
|
||||
Priority = priority;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Run(IServiceProvider provider)
|
||||
{
|
||||
_action.Invoke(provider.GetRequiredService<T>(), provider.GetRequiredService<T2>());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="IStartupAction"/> with three dependencies.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The dependency to use.</typeparam>
|
||||
/// <typeparam name="T2">The second dependency to use.</typeparam>
|
||||
/// <typeparam name="T3">The third dependency to use.</typeparam>
|
||||
public class StartupAction<T, T2, T3> : IStartupAction
|
||||
where T : notnull
|
||||
where T2 : notnull
|
||||
where T3 : notnull
|
||||
{
|
||||
/// <summary>
|
||||
/// The action to execute at startup.
|
||||
/// </summary>
|
||||
private readonly Action<T, T2, T3> _action;
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Priority { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="StartupAction{T, T2, T3}"/>.
|
||||
/// </summary>
|
||||
/// <param name="action">The action to execute on startup.</param>
|
||||
/// <param name="priority">The priority of this action (see <see cref="Priority"/>).</param>
|
||||
public StartupAction(Action<T, T2, T3> action, int priority)
|
||||
{
|
||||
_action = action;
|
||||
Priority = priority;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Run(IServiceProvider provider)
|
||||
{
|
||||
_action.Invoke(
|
||||
provider.GetRequiredService<T>(),
|
||||
provider.GetRequiredService<T2>(),
|
||||
provider.GetRequiredService<T3>()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An action executed on kyoo's startup to initialize the asp-net container.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the base interface, see <see cref="SA.StartupAction"/> for a simpler use of this.
|
||||
/// </remarks>
|
||||
public interface IStartupAction
|
||||
{
|
||||
/// <summary>
|
||||
/// The priority of this action. The actions will be executed on descending priority order.
|
||||
/// If two actions have the same priority, their order is undefined.
|
||||
/// </summary>
|
||||
int Priority { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Run this action to configure the container, a service provider containing all services can be used.
|
||||
/// </summary>
|
||||
/// <param name="provider">The service provider containing all services can be used.</param>
|
||||
void Run(IServiceProvider provider);
|
||||
}
|
||||
|
||||
64
back/src/Kyoo.Abstractions/Extensions.cs
Normal file
64
back/src/Kyoo.Abstractions/Extensions.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using Kyoo.Abstractions.Models.Exceptions;
|
||||
using Kyoo.Authentication.Models;
|
||||
|
||||
namespace Kyoo.Authentication;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods.
|
||||
/// </summary>
|
||||
public static class Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the permissions of an user.
|
||||
/// </summary>
|
||||
/// <param name="user">The user</param>
|
||||
/// <returns>The list of permissions</returns>
|
||||
public static ICollection<string> GetPermissions(this ClaimsPrincipal user)
|
||||
{
|
||||
return user.Claims.FirstOrDefault(x => x.Type == Claims.Permissions)?.Value.Split(',')
|
||||
?? Array.Empty<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the id of the current user or null if unlogged or invalid.
|
||||
/// </summary>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <returns>The id of the user or null.</returns>
|
||||
public static Guid? GetId(this ClaimsPrincipal user)
|
||||
{
|
||||
Claim? value = user.FindFirst(Claims.Id);
|
||||
if (Guid.TryParse(value?.Value, out Guid id))
|
||||
return id;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Guid GetIdOrThrow(this ClaimsPrincipal user)
|
||||
{
|
||||
Guid? ret = user.GetId();
|
||||
if (ret == null)
|
||||
throw new UnauthorizedException();
|
||||
return ret.Value;
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,17 @@
|
||||
<Title>Kyoo.Abstractions</Title>
|
||||
<Description>Base package to create plugins for Kyoo.</Description>
|
||||
<RootNamespace>Kyoo.Abstractions</RootNamespace>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Autofac" Version="6.2.0" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2021.2.0" />
|
||||
<PackageReference Include="Autofac" Version="8.0.0" />
|
||||
<PackageReference Include="Dapper" Version="2.1.37" />
|
||||
<PackageReference Include="EntityFrameworkCore.Projectables" Version="4.1.4-prebeta" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="System.ComponentModel.Composition" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
|
||||
<PackageReference Include="Sprache" Version="2.3.1" />
|
||||
<PackageReference Include="System.ComponentModel.Composition" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -17,39 +17,35 @@
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Attributes
|
||||
namespace Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// An attribute to specify on apis to specify it's documentation's name and category.
|
||||
/// If this is applied on a method, the specified method will be exploded from the controller's page and be
|
||||
/// included on the specified tag page.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
||||
public class ApiDefinitionAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// An attribute to specify on apis to specify it's documentation's name and category.
|
||||
/// If this is applied on a method, the specified method will be exploded from the controller's page and be
|
||||
/// included on the specified tag page.
|
||||
/// The public name of this api.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
||||
public class ApiDefinitionAttribute : Attribute
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the group in witch this API is. You can also specify a custom sort order using the following
|
||||
/// format: <code>order:name</code>. Everything before the first <c>:</c> will be removed but kept for
|
||||
/// th alphabetical ordering.
|
||||
/// </summary>
|
||||
public string? Group { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="ApiDefinitionAttribute"/>.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the api that will be used on the documentation page.</param>
|
||||
public ApiDefinitionAttribute(string name)
|
||||
{
|
||||
/// <summary>
|
||||
/// The public name of this api.
|
||||
/// </summary>
|
||||
[NotNull] public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the group in witch this API is. You can also specify a custom sort order using the following
|
||||
/// format: <code>order:name</code>. Everything before the first <c>:</c> will be removed but kept for
|
||||
/// th alphabetical ordering.
|
||||
/// </summary>
|
||||
public string Group { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="ApiDefinitionAttribute"/>.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the api that will be used on the documentation page.</param>
|
||||
public ApiDefinitionAttribute([NotNull] string name)
|
||||
{
|
||||
if (name == null)
|
||||
throw new ArgumentNullException(nameof(name));
|
||||
Name = name;
|
||||
}
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,10 @@
|
||||
|
||||
using System;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// An attribute to inform that the property is computed automatically and can't be assigned manually.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class ComputedAttribute : NotMergeableAttribute { }
|
||||
}
|
||||
namespace Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// An attribute to inform that the property is computed automatically and can't be assigned manually.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class ComputedAttribute : NotMergeableAttribute { }
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// An attribute to inform how a <see cref="IFileSystem"/> works.
|
||||
/// </summary>
|
||||
[MetadataAttribute]
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class FileSystemMetadataAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// The scheme(s) used to identify this path.
|
||||
/// It can be something like http, https, ftp, file and so on.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If multiples files with the same schemes exists, an exception will be thrown.
|
||||
/// </remarks>
|
||||
public string[] Scheme { get; }
|
||||
|
||||
/// <summary>
|
||||
/// <c>true</c> if the scheme should be removed from the path before calling
|
||||
/// methods of this <see cref="IFileSystem"/>, <c>false</c> otherwise.
|
||||
/// </summary>
|
||||
public bool StripScheme { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="FileSystemMetadataAttribute"/> using the specified schemes.
|
||||
/// </summary>
|
||||
/// <param name="schemes">The schemes to use.</param>
|
||||
public FileSystemMetadataAttribute(string[] schemes)
|
||||
{
|
||||
Scheme = schemes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="FileSystemMetadataAttribute"/> using a dictionary of metadata.
|
||||
/// </summary>
|
||||
/// <param name="metadata">
|
||||
/// The dictionary of metadata. This method expect the dictionary to contain a field
|
||||
/// per property in this attribute, with the same types as the properties of this attribute.
|
||||
/// </param>
|
||||
public FileSystemMetadataAttribute(IDictionary<string, object> metadata)
|
||||
{
|
||||
Scheme = (string[])metadata[nameof(Scheme)];
|
||||
StripScheme = (bool)metadata[nameof(StripScheme)];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,33 +17,37 @@
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Attributes
|
||||
namespace Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// The targeted relation can be loaded.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class LoadableRelationAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// The targeted relation can be loaded via a call to <see cref="ILibraryManager.Load"/>.
|
||||
/// The name of the field containing the related resource's ID.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class LoadableRelationAttribute : Attribute
|
||||
public string? RelationID { get; }
|
||||
|
||||
public string? Sql { get; set; }
|
||||
|
||||
public string? On { get; set; }
|
||||
|
||||
public string? Projected { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="LoadableRelationAttribute"/>.
|
||||
/// </summary>
|
||||
public LoadableRelationAttribute() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="LoadableRelationAttribute"/> with a baking relationID field.
|
||||
/// </summary>
|
||||
/// <param name="relationID">The name of the RelationID field.</param>
|
||||
public LoadableRelationAttribute(string relationID)
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the field containing the related resource's ID.
|
||||
/// </summary>
|
||||
public string RelationID { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="LoadableRelationAttribute"/>.
|
||||
/// </summary>
|
||||
public LoadableRelationAttribute() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="LoadableRelationAttribute"/> with a baking relationID field.
|
||||
/// </summary>
|
||||
/// <param name="relationID">The name of the RelationID field.</param>
|
||||
public LoadableRelationAttribute(string relationID)
|
||||
{
|
||||
RelationID = relationID;
|
||||
}
|
||||
RelationID = relationID;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,23 +18,22 @@
|
||||
|
||||
using System;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Attributes
|
||||
namespace Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// Specify that a property can't be merged.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class NotMergeableAttribute : Attribute { }
|
||||
|
||||
/// <summary>
|
||||
/// An interface with a method called when this object is merged.
|
||||
/// </summary>
|
||||
public interface IOnMerge
|
||||
{
|
||||
/// <summary>
|
||||
/// Specify that a property can't be merged.
|
||||
/// This function is called after the object has been merged.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class NotMergeableAttribute : Attribute { }
|
||||
|
||||
/// <summary>
|
||||
/// An interface with a method called when this object is merged.
|
||||
/// </summary>
|
||||
public interface IOnMerge
|
||||
{
|
||||
/// <summary>
|
||||
/// This function is called after the object has been merged.
|
||||
/// </summary>
|
||||
/// <param name="merged">The object that has been merged with this.</param>
|
||||
void OnMerge(object merged);
|
||||
}
|
||||
/// <param name="merged">The object that has been merged with this.</param>
|
||||
void OnMerge(object merged);
|
||||
}
|
||||
|
||||
@@ -18,11 +18,16 @@
|
||||
|
||||
using System;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Attributes
|
||||
namespace Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// An attribute to inform that this interface is a type union
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Interface)]
|
||||
public class OneOfAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Remove a property from the deserialization pipeline. The user can't input value for this property.
|
||||
/// The types this union concist of.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
|
||||
public class DeserializeIgnoreAttribute : Attribute { }
|
||||
public Type[] Types { get; set; }
|
||||
}
|
||||
@@ -21,68 +21,67 @@ using Kyoo.Abstractions.Controllers;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Permissions
|
||||
namespace Kyoo.Abstractions.Models.Permissions;
|
||||
|
||||
/// <summary>
|
||||
/// Specify one part of a permissions needed for the API (the kind or the type).
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
|
||||
public class PartialPermissionAttribute : Attribute, IFilterFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Specify one part of a permissions needed for the API (the kind or the type).
|
||||
/// The needed permission type.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
|
||||
public class PartialPermissionAttribute : Attribute, IFilterFactory
|
||||
public string? Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The needed permission kind.
|
||||
/// </summary>
|
||||
public Kind? Kind { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The group of this permission.
|
||||
/// </summary>
|
||||
public Group Group { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ask a permission to run an action.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// With this attribute, you can only specify a type or a kind.
|
||||
/// To have a valid permission attribute, you must specify the kind and the permission using two attributes.
|
||||
/// Those attributes can be dispatched at different places (one on the class, one on the method for example).
|
||||
/// If you don't put exactly two of those attributes, the permission attribute will be ill-formed and will
|
||||
/// lead to unspecified behaviors.
|
||||
/// </remarks>
|
||||
/// <param name="type">The type of the action</param>
|
||||
public PartialPermissionAttribute(string type)
|
||||
{
|
||||
/// <summary>
|
||||
/// The needed permission type.
|
||||
/// </summary>
|
||||
public string Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The needed permission kind.
|
||||
/// </summary>
|
||||
public Kind Kind { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The group of this permission.
|
||||
/// </summary>
|
||||
public Group Group { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ask a permission to run an action.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// With this attribute, you can only specify a type or a kind.
|
||||
/// To have a valid permission attribute, you must specify the kind and the permission using two attributes.
|
||||
/// Those attributes can be dispatched at different places (one on the class, one on the method for example).
|
||||
/// If you don't put exactly two of those attributes, the permission attribute will be ill-formed and will
|
||||
/// lead to unspecified behaviors.
|
||||
/// </remarks>
|
||||
/// <param name="type">The type of the action</param>
|
||||
public PartialPermissionAttribute(string type)
|
||||
{
|
||||
Type = type.ToLower();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ask a permission to run an action.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// With this attribute, you can only specify a type or a kind.
|
||||
/// To have a valid permission attribute, you must specify the kind and the permission using two attributes.
|
||||
/// Those attributes can be dispatched at different places (one on the class, one on the method for example).
|
||||
/// If you don't put exactly two of those attributes, the permission attribute will be ill-formed and will
|
||||
/// lead to unspecified behaviors.
|
||||
/// </remarks>
|
||||
/// <param name="permission">The kind of permission needed.</param>
|
||||
public PartialPermissionAttribute(Kind permission)
|
||||
{
|
||||
Kind = permission;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
|
||||
{
|
||||
return serviceProvider.GetRequiredService<IPermissionValidator>().Create(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsReusable => true;
|
||||
Type = type.ToLower();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ask a permission to run an action.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// With this attribute, you can only specify a type or a kind.
|
||||
/// To have a valid permission attribute, you must specify the kind and the permission using two attributes.
|
||||
/// Those attributes can be dispatched at different places (one on the class, one on the method for example).
|
||||
/// If you don't put exactly two of those attributes, the permission attribute will be ill-formed and will
|
||||
/// lead to unspecified behaviors.
|
||||
/// </remarks>
|
||||
/// <param name="permission">The kind of permission needed.</param>
|
||||
public PartialPermissionAttribute(Kind permission)
|
||||
{
|
||||
Kind = permission;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
|
||||
{
|
||||
return serviceProvider.GetRequiredService<IPermissionValidator>().Create(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsReusable => true;
|
||||
}
|
||||
|
||||
@@ -21,107 +21,116 @@ using Kyoo.Abstractions.Controllers;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Permissions
|
||||
namespace Kyoo.Abstractions.Models.Permissions;
|
||||
|
||||
/// <summary>
|
||||
/// The kind of permission needed.
|
||||
/// </summary>
|
||||
public enum Kind
|
||||
{
|
||||
/// <summary>
|
||||
/// Allow the user to read for this kind of data.
|
||||
/// </summary>
|
||||
Read,
|
||||
|
||||
/// <summary>
|
||||
/// Allow the user to write for this kind of data.
|
||||
/// </summary>
|
||||
Write,
|
||||
|
||||
/// <summary>
|
||||
/// Allow the user to create this kind of data.
|
||||
/// </summary>
|
||||
Create,
|
||||
|
||||
/// <summary>
|
||||
/// Allow the user to delete this kind of data.
|
||||
/// </summary>
|
||||
Delete,
|
||||
|
||||
/// <summary>
|
||||
/// Allow the user to play this file.
|
||||
/// </summary>
|
||||
Play,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The group of the permission.
|
||||
/// </summary>
|
||||
public enum Group
|
||||
{
|
||||
/// <summary>
|
||||
/// Default group indicating no value.
|
||||
/// </summary>
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// Allow all operations on basic items types.
|
||||
/// </summary>
|
||||
Overall,
|
||||
|
||||
/// <summary>
|
||||
/// Allow operation on sensitive items like libraries path, configurations and so on.
|
||||
/// </summary>
|
||||
Admin
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specify permissions needed for the API.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
|
||||
public class PermissionAttribute : Attribute, IFilterFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// The needed permission as string.
|
||||
/// </summary>
|
||||
public string Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The needed permission kind.
|
||||
/// </summary>
|
||||
public Kind Kind { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The group of this permission.
|
||||
/// </summary>
|
||||
public Group Group { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Ask a permission to run an action.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// The type of the action
|
||||
/// </param>
|
||||
/// <param name="permission">
|
||||
/// The kind of permission needed.
|
||||
/// </summary>
|
||||
public enum Kind
|
||||
/// </param>
|
||||
/// <param name="group">
|
||||
/// The group of this permission (allow grouped permission like overall.read
|
||||
/// for all read permissions of this group).
|
||||
/// </param>
|
||||
public PermissionAttribute(string type, Kind permission, Group group = Group.Overall)
|
||||
{
|
||||
/// <summary>
|
||||
/// Allow the user to read for this kind of data.
|
||||
/// </summary>
|
||||
Read,
|
||||
|
||||
/// <summary>
|
||||
/// Allow the user to write for this kind of data.
|
||||
/// </summary>
|
||||
Write,
|
||||
|
||||
/// <summary>
|
||||
/// Allow the user to create this kind of data.
|
||||
/// </summary>
|
||||
Create,
|
||||
|
||||
/// <summary>
|
||||
/// Allow the user to delete this kind od data.
|
||||
/// </summary>
|
||||
Delete
|
||||
Type = type.ToLower();
|
||||
Kind = permission;
|
||||
Group = group;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The group of the permission.
|
||||
/// </summary>
|
||||
public enum Group
|
||||
/// <inheritdoc />
|
||||
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
|
||||
{
|
||||
/// <summary>
|
||||
/// Allow all operations on basic items types.
|
||||
/// </summary>
|
||||
Overall,
|
||||
|
||||
/// <summary>
|
||||
/// Allow operation on sensitive items like libraries path, configurations and so on.
|
||||
/// </summary>
|
||||
Admin
|
||||
return serviceProvider.GetRequiredService<IPermissionValidator>().Create(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsReusable => true;
|
||||
|
||||
/// <summary>
|
||||
/// Specify permissions needed for the API.
|
||||
/// Return this permission attribute as a string.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
|
||||
public class PermissionAttribute : Attribute, IFilterFactory
|
||||
/// <returns>The string representation.</returns>
|
||||
public string AsPermissionString()
|
||||
{
|
||||
/// <summary>
|
||||
/// The needed permission as string.
|
||||
/// </summary>
|
||||
public string Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The needed permission kind.
|
||||
/// </summary>
|
||||
public Kind Kind { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The group of this permission.
|
||||
/// </summary>
|
||||
public Group Group { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Ask a permission to run an action.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// The type of the action
|
||||
/// </param>
|
||||
/// <param name="permission">
|
||||
/// The kind of permission needed.
|
||||
/// </param>
|
||||
/// <param name="group">
|
||||
/// The group of this permission (allow grouped permission like overall.read
|
||||
/// for all read permissions of this group).
|
||||
/// </param>
|
||||
public PermissionAttribute(string type, Kind permission, Group group = Group.Overall)
|
||||
{
|
||||
Type = type.ToLower();
|
||||
Kind = permission;
|
||||
Group = group;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
|
||||
{
|
||||
return serviceProvider.GetRequiredService<IPermissionValidator>().Create(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsReusable => true;
|
||||
|
||||
/// <summary>
|
||||
/// Return this permission attribute as a string.
|
||||
/// </summary>
|
||||
/// <returns>The string representation.</returns>
|
||||
public string AsPermissionString()
|
||||
{
|
||||
return Type;
|
||||
}
|
||||
return Type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,14 +18,13 @@
|
||||
|
||||
using System;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Permissions
|
||||
namespace Kyoo.Abstractions.Models.Permissions;
|
||||
|
||||
/// <summary>
|
||||
/// The annotated route can only be accessed by a logged in user.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
|
||||
public class UserOnlyAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// The annotated route can only be accessed by a logged in user.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
|
||||
public class UserOnlyAttribute : Attribute
|
||||
{
|
||||
// TODO: Implement a Filter Attribute to make this work. For now, this attribute is only useful as documentation.
|
||||
}
|
||||
// TODO: Implement a Filter Attribute to make this work. For now, this attribute is only useful as documentation.
|
||||
}
|
||||
|
||||
@@ -16,26 +16,22 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
namespace Kyoo.Core.Models.Options
|
||||
using System;
|
||||
using Kyoo.Utils;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class SqlFirstColumnAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Options for media registering.
|
||||
/// The name of the first column of the element. Used to split multiples
|
||||
/// items on a single sql query. If not specified, it defaults to "Id".
|
||||
/// </summary>
|
||||
public class MediaOptions
|
||||
public string Name { get; set; }
|
||||
|
||||
public SqlFirstColumnAttribute(string name)
|
||||
{
|
||||
/// <summary>
|
||||
/// The path of this options
|
||||
/// </summary>
|
||||
public const string Path = "Media";
|
||||
|
||||
/// <summary>
|
||||
/// A regex for episodes
|
||||
/// </summary>
|
||||
public string[] Regex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A regex for subtitles
|
||||
/// </summary>
|
||||
public string[] SubtitleRegex { get; set; }
|
||||
Name = name.ToSnakeCase();
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// An attribute to inform how a <see cref="IFileSystem"/> works.
|
||||
/// </summary>
|
||||
[MetadataAttribute]
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class TaskMetadataAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// The slug of the task, used to start it.
|
||||
/// </summary>
|
||||
public string Slug { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the task that will be displayed to the user.
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A quick description of what this task will do.
|
||||
/// </summary>
|
||||
public string Description { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Should this task be automatically run at app startup?
|
||||
/// </summary>
|
||||
public bool RunOnStartup { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The priority of this task. Only used if <see cref="RunOnStartup"/> is true.
|
||||
/// It allow one to specify witch task will be started first as tasked are run on a Priority's descending order.
|
||||
/// </summary>
|
||||
public int Priority { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <c>true</c> if this task should not be displayed to the user, <c>false</c> otherwise.
|
||||
/// </summary>
|
||||
public bool IsHidden { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="TaskMetadataAttribute"/> with the given slug, name and description.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the task, used to start it.</param>
|
||||
/// <param name="name">The name of the task that will be displayed to the user.</param>
|
||||
/// <param name="description">A quick description of what this task will do.</param>
|
||||
public TaskMetadataAttribute(string slug, string name, string description)
|
||||
{
|
||||
Slug = slug;
|
||||
Name = name;
|
||||
Description = description;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="TaskMetadataAttribute"/> using a dictionary of metadata.
|
||||
/// </summary>
|
||||
/// <param name="metadata">
|
||||
/// The dictionary of metadata. This method expect the dictionary to contain a field
|
||||
/// per property in this attribute, with the same types as the properties of this attribute.
|
||||
/// </param>
|
||||
public TaskMetadataAttribute(IDictionary<string, object> metadata)
|
||||
{
|
||||
Slug = (string)metadata[nameof(Slug)];
|
||||
Name = (string)metadata[nameof(Name)];
|
||||
Description = (string)metadata[nameof(Description)];
|
||||
RunOnStartup = (bool)metadata[nameof(RunOnStartup)];
|
||||
Priority = (int)metadata[nameof(Priority)];
|
||||
IsHidden = (bool)metadata[nameof(IsHidden)];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// A chapter to split an episode in multiple parts.
|
||||
/// </summary>
|
||||
public class Chapter
|
||||
{
|
||||
/// <summary>
|
||||
/// The start time of the chapter (in second from the start of the episode).
|
||||
/// </summary>
|
||||
public float StartTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The end time of the chapter (in second from the start of the episode).
|
||||
/// </summary>
|
||||
public float EndTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of this chapter. This should be a human-readable name that could be presented to the user.
|
||||
/// There should be well-known chapters name for commonly used chapters.
|
||||
/// For example, use "Opening" for the introduction-song and "Credits" for the end chapter with credits.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="Chapter"/>.
|
||||
/// </summary>
|
||||
/// <param name="startTime">The start time of the chapter (in second)</param>
|
||||
/// <param name="endTime">The end time of the chapter (in second)</param>
|
||||
/// <param name="name">The name of this chapter</param>
|
||||
public Chapter(float startTime, float endTime, string name)
|
||||
{
|
||||
StartTime = startTime;
|
||||
EndTime = endTime;
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using JetBrains.Annotations;
|
||||
using Kyoo.Utils;
|
||||
|
||||
namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// A class given information about a strongly typed configuration.
|
||||
/// </summary>
|
||||
public class ConfigurationReference
|
||||
{
|
||||
/// <summary>
|
||||
/// The path of the resource (separated by ':')
|
||||
/// </summary>
|
||||
public string Path { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of the resource.
|
||||
/// </summary>
|
||||
public Type Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="ConfigurationReference"/> using a given path and type.
|
||||
/// This method does not create sub configuration resources. Please see <see cref="CreateReference"/>
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the resource (separated by ':' or "__")</param>
|
||||
/// <param name="type">The type of the resource</param>
|
||||
/// <seealso cref="CreateReference"/>
|
||||
public ConfigurationReference(string path, Type type)
|
||||
{
|
||||
Path = path;
|
||||
Type = type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the list of configuration reference a type has.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// The base path of the type (separated by ':' or "__". If empty, it will start at root)
|
||||
/// </param>
|
||||
/// <param name="type">The type of the object</param>
|
||||
/// <returns>The list of configuration reference a type has.</returns>
|
||||
public static IEnumerable<ConfigurationReference> CreateReference(string path, [NotNull] Type type)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException(nameof(type));
|
||||
|
||||
List<ConfigurationReference> ret = new()
|
||||
{
|
||||
new ConfigurationReference(path, type)
|
||||
};
|
||||
|
||||
if (!type.IsClass || type.AssemblyQualifiedName?.StartsWith("System") == true)
|
||||
return ret;
|
||||
|
||||
Type enumerable = Utility.GetGenericDefinition(type, typeof(IEnumerable<>));
|
||||
Type dictionary = Utility.GetGenericDefinition(type, typeof(IDictionary<,>));
|
||||
Type dictionaryKey = dictionary?.GetGenericArguments()[0];
|
||||
|
||||
if (dictionary != null && dictionaryKey == typeof(string))
|
||||
ret.AddRange(CreateReference($"{path}:{type.Name}:*", dictionary.GetGenericArguments()[1]));
|
||||
else if (dictionary != null && dictionaryKey == typeof(int))
|
||||
ret.AddRange(CreateReference($"{path}:{type.Name}:", dictionary.GetGenericArguments()[1]));
|
||||
else if (enumerable != null)
|
||||
ret.AddRange(CreateReference($"{path}:{type.Name}:", enumerable.GetGenericArguments()[0]));
|
||||
else
|
||||
{
|
||||
foreach (PropertyInfo child in type.GetProperties())
|
||||
ret.AddRange(CreateReference($"{path}:{child.Name}", child.PropertyType));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the list of configuration reference a type has.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// The base path of the type (separated by ':' or "__". If empty, it will start at root)
|
||||
/// </param>
|
||||
/// <typeparam name="T">The type of the object</typeparam>
|
||||
/// <returns>The list of configuration reference a type has.</returns>
|
||||
public static IEnumerable<ConfigurationReference> CreateReference<T>(string path)
|
||||
{
|
||||
return CreateReference(path, typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a <see cref="ConfigurationReference"/> meaning that the given path is of any type.
|
||||
/// It means that the type can't be edited.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// The path that will be untyped (separated by ':' or "__". If empty, it will start at root).
|
||||
/// </param>
|
||||
/// <returns>A configuration reference representing a path of any type.</returns>
|
||||
public static ConfigurationReference CreateUntyped(string path)
|
||||
{
|
||||
return new ConfigurationReference(path, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,38 +17,18 @@
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Exceptions
|
||||
namespace Kyoo.Abstractions.Models.Exceptions;
|
||||
|
||||
/// <summary>
|
||||
/// An exception raised when an item already exists in the database.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class DuplicatedItemException(object? existing = null)
|
||||
: Exception("Already exists in the database.")
|
||||
{
|
||||
/// <summary>
|
||||
/// An exception raised when an item already exists in the database.
|
||||
/// The existing object.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class DuplicatedItemException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new <see cref="DuplicatedItemException"/> with the default message.
|
||||
/// </summary>
|
||||
public DuplicatedItemException()
|
||||
: base("Already exists in the database.")
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="DuplicatedItemException"/> with a custom message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to use</param>
|
||||
public DuplicatedItemException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// The serialization constructor.
|
||||
/// </summary>
|
||||
/// <param name="info">Serialization infos</param>
|
||||
/// <param name="context">The serialization context</param>
|
||||
protected DuplicatedItemException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{ }
|
||||
}
|
||||
public object? Existing { get; } = existing;
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Exceptions
|
||||
{
|
||||
/// <summary>
|
||||
/// An exception thrown when a part of the app has a fatal issue.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class HealthException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new <see cref="HealthException"/> with a custom message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to use.</param>
|
||||
public HealthException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// The serialization constructor
|
||||
/// </summary>
|
||||
/// <param name="info">Serialization infos</param>
|
||||
/// <param name="context">The serialization context</param>
|
||||
protected HealthException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Exceptions
|
||||
{
|
||||
/// <summary>
|
||||
/// An exception raised when an <see cref="IIdentifier"/> failed.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class IdentificationFailedException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new <see cref="IdentificationFailedException"/> with a default message.
|
||||
/// </summary>
|
||||
public IdentificationFailedException()
|
||||
: base("An identification failed.")
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="IdentificationFailedException"/> with a custom message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to use.</param>
|
||||
public IdentificationFailedException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// The serialization constructor
|
||||
/// </summary>
|
||||
/// <param name="info">Serialization infos</param>
|
||||
/// <param name="context">The serialization context</param>
|
||||
protected IdentificationFailedException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -17,36 +17,25 @@
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Exceptions
|
||||
namespace Kyoo.Abstractions.Models.Exceptions;
|
||||
|
||||
/// <summary>
|
||||
/// An exception raised when an item could not be found.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class ItemNotFoundException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// An exception raised when an item could not be found.
|
||||
/// Create a default <see cref="ItemNotFoundException"/> with no message.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class ItemNotFoundException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a default <see cref="ItemNotFoundException"/> with no message.
|
||||
/// </summary>
|
||||
public ItemNotFoundException() { }
|
||||
public ItemNotFoundException()
|
||||
: base("Item not found") { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="ItemNotFoundException"/> with a message
|
||||
/// </summary>
|
||||
/// <param name="message">The message of the exception</param>
|
||||
public ItemNotFoundException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// The serialization constructor
|
||||
/// </summary>
|
||||
/// <param name="info">Serialization infos</param>
|
||||
/// <param name="context">The serialization context</param>
|
||||
protected ItemNotFoundException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{ }
|
||||
}
|
||||
/// <summary>
|
||||
/// Create a new <see cref="ItemNotFoundException"/> with a message
|
||||
/// </summary>
|
||||
/// <param name="message">The message of the exception</param>
|
||||
public ItemNotFoundException(string message)
|
||||
: base(message) { }
|
||||
}
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Exceptions
|
||||
{
|
||||
/// <summary>
|
||||
/// An exception raised when an <see cref="ITask"/> failed.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class TaskFailedException : AggregateException
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new <see cref="TaskFailedException"/> with a default message.
|
||||
/// </summary>
|
||||
public TaskFailedException()
|
||||
: base("A task failed.")
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="TaskFailedException"/> with a custom message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to use.</param>
|
||||
public TaskFailedException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="TaskFailedException"/> wrapping another exception.
|
||||
/// </summary>
|
||||
/// <param name="exception">The exception to wrap.</param>
|
||||
public TaskFailedException(Exception exception)
|
||||
: base(exception)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// The serialization constructor
|
||||
/// </summary>
|
||||
/// <param name="info">Serialization infos</param>
|
||||
/// <param name="context">The serialization context</param>
|
||||
protected TaskFailedException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -16,16 +16,16 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
namespace Kyoo.Abstractions.Models
|
||||
using System;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Exceptions;
|
||||
|
||||
[Serializable]
|
||||
public class UnauthorizedException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// An interface to represent resources that should have a link field in their return values (like videos).
|
||||
/// </summary>
|
||||
public interface ILink
|
||||
{
|
||||
/// <summary>
|
||||
/// The link to return, in most cases this should be a string.
|
||||
/// </summary>
|
||||
public object Link { get; }
|
||||
}
|
||||
public UnauthorizedException()
|
||||
: base("User not authenticated or token invalid.") { }
|
||||
|
||||
public UnauthorizedException(string message)
|
||||
: base(message) { }
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
using Kyoo.Utils;
|
||||
using PathIO = System.IO.Path;
|
||||
|
||||
namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// A font of an <see cref="Episode"/>.
|
||||
/// </summary>
|
||||
public class Font : ILink
|
||||
{
|
||||
/// <summary>
|
||||
/// A human-readable identifier, used in the URL.
|
||||
/// </summary>
|
||||
public string Slug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the font file (with the extension).
|
||||
/// </summary>
|
||||
public string File { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The format of this font (the extension).
|
||||
/// </summary>
|
||||
public string Format { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The path of the font.
|
||||
/// </summary>
|
||||
[SerializeIgnore] public string Path { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object Link { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new empty <see cref="Font"/>.
|
||||
/// </summary>
|
||||
public Font() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="Font"/> from a path.
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the font.</param>
|
||||
/// <param name="episodeSlug">The slug of the episode that contains this font.</param>
|
||||
public Font(string path, string episodeSlug)
|
||||
{
|
||||
Slug = Utility.ToSlug(PathIO.GetFileNameWithoutExtension(path));
|
||||
Path = path;
|
||||
File = PathIO.GetFileName(path);
|
||||
Format = PathIO.GetExtension(path).Replace(".", string.Empty);
|
||||
Link = $"/watch/{episodeSlug}/font/{Slug}.{Format}";
|
||||
}
|
||||
}
|
||||
}
|
||||
44
back/src/Kyoo.Abstractions/Models/Genre.cs
Normal file
44
back/src/Kyoo.Abstractions/Models/Genre.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A genre that allow one to specify categories for shows.
|
||||
/// </summary>
|
||||
public enum Genre
|
||||
{
|
||||
Action,
|
||||
Adventure,
|
||||
Animation,
|
||||
Comedy,
|
||||
Crime,
|
||||
Documentary,
|
||||
Drama,
|
||||
Family,
|
||||
Fantasy,
|
||||
History,
|
||||
Horror,
|
||||
Music,
|
||||
Mystery,
|
||||
Romance,
|
||||
ScienceFiction,
|
||||
Thriller,
|
||||
War,
|
||||
Western,
|
||||
}
|
||||
31
back/src/Kyoo.Abstractions/Models/ILibraryItem.cs
Normal file
31
back/src/Kyoo.Abstractions/Models/ILibraryItem.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A show, a movie or a collection.
|
||||
/// </summary>
|
||||
[OneOf(Types = new[] { typeof(Show), typeof(Movie), typeof(Collection) })]
|
||||
public interface ILibraryItem : IResource, IThumbnails, IMetadata, IAddedDate, IQuery
|
||||
{
|
||||
static Sort IQuery.DefaultSort => new Sort<ILibraryItem>.By(nameof(Movie.Name));
|
||||
}
|
||||
31
back/src/Kyoo.Abstractions/Models/INews.cs
Normal file
31
back/src/Kyoo.Abstractions/Models/INews.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A show, a movie or a collection.
|
||||
/// </summary>
|
||||
[OneOf(Types = new[] { typeof(Episode), typeof(Movie) })]
|
||||
public interface INews : IResource, IThumbnails, IMetadata, IAddedDate, IQuery
|
||||
{
|
||||
static Sort IQuery.DefaultSort => new Sort<INews>.By(nameof(AddedDate), true);
|
||||
}
|
||||
27
back/src/Kyoo.Abstractions/Models/IWatchlist.cs
Normal file
27
back/src/Kyoo.Abstractions/Models/IWatchlist.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A watch list item.
|
||||
/// </summary>
|
||||
[OneOf(Types = new[] { typeof(Show), typeof(Movie) })]
|
||||
public interface IWatchlist : IResource, IThumbnails, IMetadata, IAddedDate { }
|
||||
52
back/src/Kyoo.Abstractions/Models/Issues.cs
Normal file
52
back/src/Kyoo.Abstractions/Models/Issues.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// An issue that occured on kyoo.
|
||||
/// </summary>
|
||||
public class Issue : IAddedDate
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of issue (for example, "Scanner" if this issue was created due to scanning error).
|
||||
/// </summary>
|
||||
public string Domain { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Why this issue was caused? An unique cause that can be used to identify this issue.
|
||||
/// For the scanner, a cause should be a video path.
|
||||
/// </summary>
|
||||
public string Cause { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A human readable string explaining why this issue occured.
|
||||
/// </summary>
|
||||
public string Reason { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Some extra data that could store domain-specific info.
|
||||
/// </summary>
|
||||
public Dictionary<string, object> Extra { get; set; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DateTime AddedDate { get; set; }
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of item, ether a show, a movie or a collection.
|
||||
/// </summary>
|
||||
public enum ItemType
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="LibraryItem"/> is a <see cref="Show"/>.
|
||||
/// </summary>
|
||||
Show,
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="LibraryItem"/> is a Movie (a <see cref="Show"/> with
|
||||
/// <see cref="Models.Show.IsMovie"/> equals to true).
|
||||
/// </summary>
|
||||
Movie,
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="LibraryItem"/> is a <see cref="Collection"/>.
|
||||
/// </summary>
|
||||
Collection
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A type union between <see cref="Show"/> and <see cref="Collection"/>.
|
||||
/// This is used to list content put inside a library.
|
||||
/// </summary>
|
||||
public class LibraryItem : CustomTypeDescriptor, IResource, IThumbnails
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int ID { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Slug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The title of the show or collection.
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The summary of the show or collection.
|
||||
/// </summary>
|
||||
public string Overview { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is this show airing, not aired yet or finished? This is only applicable for shows.
|
||||
/// </summary>
|
||||
public Status? Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The date this show or collection started airing. It can be null if this is unknown.
|
||||
/// </summary>
|
||||
public DateTime? StartAir { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The date this show or collection finished airing.
|
||||
/// It must be after the <see cref="StartAir"/> but can be the same (example: for movies).
|
||||
/// It can also be null if this is unknown.
|
||||
/// </summary>
|
||||
public DateTime? EndAir { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<int, string> Images { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of this item (ether a collection, a show or a movie).
|
||||
/// </summary>
|
||||
public ItemType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new, empty <see cref="LibraryItem"/>.
|
||||
/// </summary>
|
||||
public LibraryItem() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="LibraryItem"/> from a show.
|
||||
/// </summary>
|
||||
/// <param name="show">The show that this library item should represent.</param>
|
||||
public LibraryItem(Show show)
|
||||
{
|
||||
ID = show.ID;
|
||||
Slug = show.Slug;
|
||||
Title = show.Title;
|
||||
Overview = show.Overview;
|
||||
Status = show.Status;
|
||||
StartAir = show.StartAir;
|
||||
EndAir = show.EndAir;
|
||||
Images = show.Images;
|
||||
Type = show.IsMovie ? ItemType.Movie : ItemType.Show;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="LibraryItem"/> from a collection
|
||||
/// </summary>
|
||||
/// <param name="collection">The collection that this library item should represent.</param>
|
||||
public LibraryItem(Collection collection)
|
||||
{
|
||||
ID = -collection.ID;
|
||||
Slug = collection.Slug;
|
||||
Title = collection.Name;
|
||||
Overview = collection.Overview;
|
||||
Status = Models.Status.Unknown;
|
||||
StartAir = null;
|
||||
EndAir = null;
|
||||
Images = collection.Images;
|
||||
Type = ItemType.Collection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An expression to create a <see cref="LibraryItem"/> representing a show.
|
||||
/// </summary>
|
||||
public static Expression<Func<Show, LibraryItem>> FromShow => x => new LibraryItem
|
||||
{
|
||||
ID = x.ID,
|
||||
Slug = x.Slug,
|
||||
Title = x.Title,
|
||||
Overview = x.Overview,
|
||||
Status = x.Status,
|
||||
StartAir = x.StartAir,
|
||||
EndAir = x.EndAir,
|
||||
Images = x.Images,
|
||||
Type = x.IsMovie ? ItemType.Movie : ItemType.Show
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// An expression to create a <see cref="LibraryItem"/> representing a collection.
|
||||
/// </summary>
|
||||
public static Expression<Func<Collection, LibraryItem>> FromCollection => x => new LibraryItem
|
||||
{
|
||||
ID = -x.ID,
|
||||
Slug = x.Slug,
|
||||
Title = x.Name,
|
||||
Overview = x.Overview,
|
||||
Status = Models.Status.Unknown,
|
||||
StartAir = null,
|
||||
EndAir = null,
|
||||
Images = x.Images,
|
||||
Type = ItemType.Collection
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string GetClassName()
|
||||
{
|
||||
return Type.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,48 +16,20 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
namespace Kyoo.Abstractions.Models
|
||||
/// <summary>
|
||||
/// ID and link of an item on an external provider.
|
||||
/// </summary>
|
||||
public class MetadataId
|
||||
{
|
||||
/// <summary>
|
||||
/// ID and link of an item on an external provider.
|
||||
/// The ID of the resource on the external provider.
|
||||
/// </summary>
|
||||
public class MetadataID
|
||||
{
|
||||
/// <summary>
|
||||
/// The expression to retrieve the unique ID of a MetadataID. This is an aggregate of the two resources IDs.
|
||||
/// </summary>
|
||||
public static Expression<Func<MetadataID, object>> PrimaryKey
|
||||
{
|
||||
get { return x => new { First = x.ResourceID, Second = x.ProviderID }; }
|
||||
}
|
||||
public string DataId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the resource which possess the metadata.
|
||||
/// </summary>
|
||||
[SerializeIgnore] public int ResourceID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the provider.
|
||||
/// </summary>
|
||||
[SerializeIgnore] public int ProviderID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The provider that can do something with this ID.
|
||||
/// </summary>
|
||||
public Provider Provider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the resource on the external provider.
|
||||
/// </summary>
|
||||
public string DataID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The URL of the resource on the external provider.
|
||||
/// </summary>
|
||||
public string Link { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// The URL of the resource on the external provider.
|
||||
/// </summary>
|
||||
public string? Link { get; set; }
|
||||
}
|
||||
|
||||
@@ -16,83 +16,90 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Kyoo.Utils;
|
||||
|
||||
namespace Kyoo.Abstractions.Models
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A page of resource that contains information about the pagination of resources.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of resource contained in this page.</typeparam>
|
||||
public class Page<T>
|
||||
where T : IResource
|
||||
{
|
||||
/// <summary>
|
||||
/// A page of resource that contains information about the pagination of resources.
|
||||
/// The link of the current page.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of resource contained in this page.</typeparam>
|
||||
public class Page<T>
|
||||
where T : IResource
|
||||
public string This { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The link of the first page.
|
||||
/// </summary>
|
||||
public string First { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The link of the previous page.
|
||||
/// </summary>
|
||||
public string? Previous { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The link of the next page.
|
||||
/// </summary>
|
||||
public string? Next { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of items in the current page.
|
||||
/// </summary>
|
||||
public int Count => Items.Count;
|
||||
|
||||
/// <summary>
|
||||
/// The list of items in the page.
|
||||
/// </summary>
|
||||
public ICollection<T> Items { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="Page{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="items">The list of items in the page.</param>
|
||||
/// <param name="this">The link of the current page.</param>
|
||||
/// <param name="previous">The link of the previous page.</param>
|
||||
/// <param name="next">The link of the next page.</param>
|
||||
/// <param name="first">The link of the first page.</param>
|
||||
public Page(ICollection<T> items, string @this, string? previous, string? next, string first)
|
||||
{
|
||||
/// <summary>
|
||||
/// The link of the current page.
|
||||
/// </summary>
|
||||
public string This { get; }
|
||||
Items = items;
|
||||
This = @this;
|
||||
Previous = previous;
|
||||
Next = next;
|
||||
First = first;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The link of the first page.
|
||||
/// </summary>
|
||||
public string First { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The link of the next page.
|
||||
/// </summary>
|
||||
public string Next { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of items in the current page.
|
||||
/// </summary>
|
||||
public int Count => Items.Count;
|
||||
|
||||
/// <summary>
|
||||
/// The list of items in the page.
|
||||
/// </summary>
|
||||
public ICollection<T> Items { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="Page{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="items">The list of items in the page.</param>
|
||||
/// <param name="this">The link of the current page.</param>
|
||||
/// <param name="next">The link of the next page.</param>
|
||||
/// <param name="first">The link of the first page.</param>
|
||||
public Page(ICollection<T> items, string @this, string next, string first)
|
||||
/// <summary>
|
||||
/// Create a new <see cref="Page{T}"/> and compute the urls.
|
||||
/// </summary>
|
||||
/// <param name="items">The list of items in the page.</param>
|
||||
/// <param name="url">The base url of the resources available from this page.</param>
|
||||
/// <param name="query">The list of query strings of the current page</param>
|
||||
/// <param name="limit">The number of items requested for the current page.</param>
|
||||
public Page(ICollection<T> items, string url, Dictionary<string, string> query, int limit)
|
||||
{
|
||||
Items = items;
|
||||
This = url + query.ToQueryString();
|
||||
if (items.Count > 0 && query.ContainsKey("afterID"))
|
||||
{
|
||||
Items = items;
|
||||
This = @this;
|
||||
Next = next;
|
||||
First = first;
|
||||
query["afterID"] = items.First().Id.ToString();
|
||||
query["reverse"] = "true";
|
||||
Previous = url + query.ToQueryString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="Page{T}"/> and compute the urls.
|
||||
/// </summary>
|
||||
/// <param name="items">The list of items in the page.</param>
|
||||
/// <param name="url">The base url of the resources available from this page.</param>
|
||||
/// <param name="query">The list of query strings of the current page</param>
|
||||
/// <param name="limit">The number of items requested for the current page.</param>
|
||||
public Page(ICollection<T> items,
|
||||
string url,
|
||||
Dictionary<string, string> query,
|
||||
int limit)
|
||||
query.Remove("reverse");
|
||||
if (items.Count == limit && limit > 0)
|
||||
{
|
||||
Items = items;
|
||||
This = url + query.ToQueryString();
|
||||
|
||||
if (items.Count == limit && limit > 0)
|
||||
{
|
||||
query["afterID"] = items.Last().ID.ToString();
|
||||
Next = url + query.ToQueryString();
|
||||
}
|
||||
|
||||
query.Remove("afterID");
|
||||
First = url + query.ToQueryString();
|
||||
query["afterID"] = items.Last().Id.ToString();
|
||||
Next = url + query.ToQueryString();
|
||||
}
|
||||
query.Remove("afterID");
|
||||
First = url + query.ToQueryString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,39 +17,30 @@
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Kyoo.Tests.Database
|
||||
namespace Kyoo.Models;
|
||||
|
||||
public class Patch<T> : Dictionary<string, JsonDocument>
|
||||
where T : class, IResource
|
||||
{
|
||||
public class GlobalTests : IDisposable, IAsyncDisposable
|
||||
public Guid? Id => this.GetValueOrDefault(nameof(IResource.Id))?.Deserialize<Guid>();
|
||||
|
||||
public string? Slug => this.GetValueOrDefault(nameof(IResource.Slug))?.Deserialize<string>();
|
||||
|
||||
public T Apply(T current)
|
||||
{
|
||||
private readonly RepositoryActivator _repositories;
|
||||
|
||||
public GlobalTests(ITestOutputHelper output)
|
||||
foreach ((string property, JsonDocument value) in this)
|
||||
{
|
||||
_repositories = new RepositoryActivator(output);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_repositories.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public ValueTask DisposeAsync()
|
||||
{
|
||||
return _repositories.DisposeAsync();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[SuppressMessage("ReSharper", "EqualExpressionComparison")]
|
||||
public void SampleTest()
|
||||
{
|
||||
Assert.False(ReferenceEquals(TestSample.Get<Show>(), TestSample.Get<Show>()));
|
||||
PropertyInfo prop = typeof(T).GetProperty(
|
||||
property,
|
||||
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance
|
||||
)!;
|
||||
prop.SetValue(current, value.Deserialize(prop.PropertyType));
|
||||
}
|
||||
return current;
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// A role a person played for a show. It can be an actor, musician, voice actor, director, writer...
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class is not serialized like other classes.
|
||||
/// Based on the <see cref="ForPeople"/> field, it is serialized like
|
||||
/// a show with two extra fields (<see cref="Role"/> and <see cref="Type"/>).
|
||||
/// </remarks>
|
||||
public class PeopleRole : IResource
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int ID { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Slug => ForPeople ? Show.Slug : People.Slug;
|
||||
|
||||
/// <summary>
|
||||
/// Should this role be used as a Show substitute (the value is <c>true</c>) or
|
||||
/// as a People substitute (the value is <c>false</c>).
|
||||
/// </summary>
|
||||
public bool ForPeople { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the People playing the role.
|
||||
/// </summary>
|
||||
public int PeopleID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The people that played this role.
|
||||
/// </summary>
|
||||
public People People { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the Show where the People playing in.
|
||||
/// </summary>
|
||||
public int ShowID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The show where the People played in.
|
||||
/// </summary>
|
||||
public Show Show { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of work the person has done for the show.
|
||||
/// That can be something like "Actor", "Writer", "Music", "Voice Actor"...
|
||||
/// </summary>
|
||||
public string Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The role the People played.
|
||||
/// This is mostly used to inform witch character was played for actor and voice actors.
|
||||
/// </summary>
|
||||
public string Role { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -16,47 +16,75 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Serialization;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
using Kyoo.Utils;
|
||||
|
||||
namespace Kyoo.Abstractions.Models
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A class representing collections of <see cref="Show"/>.
|
||||
/// </summary>
|
||||
public class Collection : IQuery, IResource, IMetadata, IThumbnails, IAddedDate, ILibraryItem
|
||||
{
|
||||
public static Sort DefaultSort => new Sort<Collection>.By(nameof(Collection.Name));
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[MaxLength(256)]
|
||||
public string Slug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A class representing collections of <see cref="Show"/>.
|
||||
/// A collection can also be stored in a <see cref="Library"/>.
|
||||
/// The name of this collection.
|
||||
/// </summary>
|
||||
public class Collection : IResource, IMetadata, IThumbnails
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The description of this collection.
|
||||
/// </summary>
|
||||
public string? Overview { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public DateTime AddedDate { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image? Poster { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image? Thumbnail { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image? Logo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of movies contained in this collection.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public ICollection<Movie>? Movies { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of shows contained in this collection.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public ICollection<Show>? Shows { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, MetadataId> ExternalId { get; set; } = new();
|
||||
|
||||
public Collection() { }
|
||||
|
||||
[JsonConstructor]
|
||||
public Collection(string name)
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int ID { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Slug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of this collection.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<int, string> Images { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The description of this collection.
|
||||
/// </summary>
|
||||
public string Overview { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of shows contained in this collection.
|
||||
/// </summary>
|
||||
[LoadableRelation] public ICollection<Show> Shows { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of libraries that contains this collection.
|
||||
/// </summary>
|
||||
[LoadableRelation] public ICollection<Library> Libraries { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[EditableRelation] [LoadableRelation] public ICollection<MetadataID> ExternalIDs { get; set; }
|
||||
if (name != null)
|
||||
{
|
||||
Slug = Utility.ToSlug(name);
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user