Compare commits
723 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ba8e23e8d4 | |||
| 7fa4641dfe | |||
| 4167af098f | |||
| c5f551e963 | |||
| fbd0e5b27b | |||
| 5877b8cc6f | |||
| 23f4bfde99 | |||
| 4898fa7dcf | |||
| a6990fd732 | |||
| 2fac9efc1b | |||
| a3a84766e4 | |||
| 0e9a77ffe0 | |||
| 8f7e6a5222 | |||
| 736945d6ef | |||
| f97e855f51 | |||
| d6e628099c | |||
| d7ca25525c | |||
| 72099cb1fe | |||
| eeefe9d9dc | |||
| 86c3e54119 | |||
| ea0737cf1f | |||
| f4eaacc64a | |||
| 7f6efbe6dc | |||
| 72811dbedb | |||
| 493e13ebc0 | |||
| 14aeee888f | |||
| cbc08d6f03 | |||
| 77703b904f | |||
| 762644d23d | |||
| 75403078d2 | |||
| 255a131f3b | |||
| e56350c1c2 | |||
| aaa1b5f63a | |||
| 3d409bb6f1 | |||
| 7ab532be07 | |||
| 946b73d215 | |||
| 2f0634dc03 | |||
| f8ecb3fc53 | |||
| 01608fa875 | |||
| 14a6766072 | |||
| 0fa5b6496f | |||
| 43c11ab6e3 | |||
| 41a901f3c4 | |||
| 2bdc664619 | |||
| 8835fc640a | |||
| f92cd89c46 | |||
| a1a113d3c6 | |||
| 3f78c3f420 | |||
| f10912d930 | |||
| 98fa47348c | |||
| d38c846e80 | |||
| 007a099951 | |||
| 9622cd346c | |||
| c3c1f4cc5f | |||
| d97fe4c621 | |||
| 7e5733db34 | |||
| d1dde2428f | |||
| 190dd71b3c | |||
| feb61c28d7 | |||
| f380eccc68 | |||
| cf43bf360e | |||
| 48dfd469ed | |||
| 5dd860735d | |||
| 7cd2077dcd | |||
| 7430bba853 | |||
| 782c351ca6 | |||
| 3aef2a80a7 | |||
| 85a10c799a | |||
| 9eef570740 | |||
| 58f38b2655 | |||
| 85d2576bdc | |||
| 23f9bd4e9f | |||
| 8eb0029bb8 | |||
| c8a0df4759 | |||
| e7bc29a8f1 | |||
| 5295c69f46 | |||
| f58552be84 | |||
| cd57142caf | |||
| 86ad2d0383 | |||
| 7d5aa6fd13 | |||
| f2ef630921 | |||
| 9250b30249 | |||
| 2b16cce0aa | |||
| 34870556b4 | |||
| 7e2d9bd585 | |||
| 691bc8f1ef | |||
| 5dbc0c61c5 | |||
| 0bc1ee3492 | |||
| 7403a46f91 | |||
| 8ffb81093d | |||
| d312c3c70a | |||
| cd66a9dccb | |||
| f2690b262f | |||
| 63c5a83911 | |||
| 17b1acad9d | |||
| e7c7eb3ec0 | |||
| fa0a21a021 | |||
| 791088deb6 | |||
| 9c1a2a4a8d | |||
| 6d092d9ebc | |||
| 73997cf6c7 | |||
| 1d074dae2e | |||
| a878875f83 | |||
| d055ae89e0 | |||
| f83639d5f8 | |||
| 97ccf3bc6d | |||
| 76805a0b19 | |||
| 0103a84358 | |||
| 611cbc6dd9 | |||
| 011f260e94 | |||
| e937425f4f | |||
| bc2624bffd | |||
| 4f21c26e5d | |||
| e6a4ce2e64 | |||
| 5b98238b3a | |||
| d96c0d547a | |||
| 3c62de8347 | |||
| 07d4dc37b5 | |||
| 64c5f25d18 | |||
| 098e86b1f4 | |||
| adc3e421f6 | |||
| d289797d65 | |||
| 6218b27117 | |||
| 549db7b1bf | |||
| 8ee99adb2d | |||
| da519c2250 | |||
| 7cd33ad388 | |||
| 8ae368ea4f | |||
| 22e31b92a4 | |||
| a308efaf06 | |||
| 977cb89481 | |||
| 0c3b030b13 | |||
| 86080c7875 | |||
| b71c3c7c53 | |||
| debdb92dcf | |||
| ba6f2a1637 | |||
| 7c6f62023a | |||
| de50002ea7 | |||
| 41a251c2ac | |||
| 10d7664733 | |||
| fed96d1fce | |||
| 106fc90c4a | |||
| c1c6ce33e4 | |||
| 26bc7d23ae | |||
| 30dc833b79 | |||
| 292737d53c | |||
| 652c4a1f81 | |||
| fb158bc069 | |||
| 51c2731b07 | |||
| 93530008a9 | |||
| 6747fbb701 | |||
| 06d253228a | |||
| c8b1b4d394 | |||
| 0320fe6dcc | |||
| 1f36978bb9 | |||
| 6a01d44600 | |||
| 35f9798bed | |||
| 897af4661b | |||
| 3df2915f5f | |||
| 02caf896ff | |||
| 7dd56bfb9b | |||
| fe59011882 | |||
| c854fd0a5b | |||
| 645b4fe332 | |||
| e5f24b3160 | |||
| fff1315fa5 | |||
| ba0543f861 | |||
| 30c4d5baf1 | |||
| e8f7ae637f | |||
| b5fa6f0baa | |||
| c4fb9a2e72 | |||
| 2cefc092ce | |||
| a7ea54cf4b | |||
| deb4e34895 | |||
| 33ecf9faa6 | |||
| cf6325d0ba | |||
| c12c1bad73 | |||
| cf9ed31dfd | |||
| c296927bbb | |||
| 32ebe6b739 | |||
| c85a7079eb | |||
| 822060b82c | |||
| 547fe7be38 | |||
| ccf5588435 | |||
| 4cb54bc9da | |||
| ce72ff5e8d | |||
| 71b9cace53 | |||
| 5637327e8a | |||
| a1072b461f | |||
| 3fb24d5f64 | |||
| e45252d16c | |||
| 48ef7a987f | |||
| 58d912065b | |||
| d8130f48e2 | |||
| 89afa9b836 | |||
| 684ba13175 | |||
| 2399105f6c | |||
| d42f4dbe4f | |||
| cf32a7ff21 | |||
| 5eea3d7e01 | |||
| e2e3a50f1f | |||
| 4c98afb613 | |||
| d7f24262fd | |||
| 6056504f00 | |||
| cef92243f5 | |||
| 8d5c82b0c6 | |||
| 003fb26c60 | |||
| 4eb90d20a2 | |||
| cf489d3934 | |||
| 416476cc66 | |||
| bdc3daf6da | |||
| 129515d57a | |||
| 76ca03d8e3 | |||
| e49fe6c452 | |||
| ec7a053a74 | |||
| 9e4e6172c3 | |||
| eca26e912f | |||
| f9e410a1f5 | |||
| 87abd0c6f5 | |||
| e3665e6407 | |||
| c87905f6c2 | |||
| 2100c1495d | |||
| b5da8aeb55 | |||
| 5eeded6c72 | |||
| 346b8be122 | |||
| a19673d3c2 | |||
| 3efeaa7359 | |||
| 63be8c8fb8 | |||
| 975c31635a | |||
| 9b5bce34a0 | |||
| bb27758310 | |||
| 2d7c52a6b6 | |||
| cbb15ac7ee | |||
| b2db2b27da | |||
| 3dfeed1432 | |||
| 2101f1e9a7 | |||
| 8a0a8e4d54 | |||
| a9ca3f9083 | |||
| 6d5e10a31c | |||
| 5b616d5928 | |||
| 62670964c0 | |||
| 314bd766df | |||
| bdd023fde3 | |||
| 40aabd2217 | |||
| b9d5447b4f | |||
| 68a1cb9aaa | |||
| bf3024939a | |||
| df9464f762 | |||
| 17cf624f6a | |||
| 8f042ad448 | |||
| 1cbd61888f | |||
| 2ce49fc54e | |||
| bec328f1f4 | |||
| ea8c63b71b | |||
| 52049ce163 | |||
| 70c62c8b52 | |||
| fa79b4cbe0 | |||
| 438085633b | |||
| fe043d1823 | |||
| 9bd12df8f6 | |||
| 637d420e1c | |||
| c593b7bc46 | |||
| 5e90139b17 | |||
| ed86d8ffd2 | |||
| bcaaaac586 | |||
| a614a6ff9c | |||
| 08a1cb1ae9 | |||
| 75e93b8ea2 | |||
| 5d28abae91 | |||
| c483cdb871 | |||
| fe14ca25c6 | |||
| 0965efab21 | |||
| 598b627bb4 | |||
| b8614495f6 | |||
| e02643123c | |||
| 5d8cad06d7 | |||
| 2b8a97b8c2 | |||
| 44cd1b33bf | |||
| 90b503906f | |||
| 77bfb916ba | |||
| f35152a169 | |||
| 0d9224bc09 | |||
| cf4f80c82b | |||
| fa717b9bca | |||
| 8e2dce34f0 | |||
| dce6fc7e7d | |||
| 781e3c3c4d | |||
| 0d4d5b5de0 | |||
| 293d8ec584 | |||
| 6ccef6e515 | |||
| 5f7b005626 | |||
| b590636303 | |||
| a17e0adf44 | |||
| 2b1c1d5e59 | |||
| eecbcddea3 | |||
| 373441e4c6 | |||
| dbcda5b634 | |||
| bc5f1f13f0 | |||
| 0c13b09029 | |||
| 4ffc544e87 | |||
| cf00992d71 | |||
| 3848e9840d | |||
| 930bbb33fd | |||
| 4332a9ea3a | |||
| ccfe0bfd9d | |||
| f5fc56eee1 | |||
| cd6bf25011 | |||
| 335287d119 | |||
| 50af8f4d3a | |||
| 58c7370536 | |||
| ececc394e2 | |||
| 219a9ed613 | |||
| e47fcfc62e | |||
| 6cfdb8ff84 | |||
| ef4cdfa028 | |||
| 1eed26abab | |||
| a2851dd700 | |||
| 563db1138e | |||
| 84587da701 | |||
| f0a836fc1f | |||
| 5539e2cd4e | |||
| 30b013dfa5 | |||
| 8343f4f80b | |||
| e8dcba0456 | |||
| 27cbc23d87 | |||
| 275d68ec5b | |||
| 7f9de4b180 | |||
| 231f10cbe2 | |||
| b4664f45b4 | |||
| 3153cdd6c4 | |||
| 69292a083d | |||
| 123478a24f | |||
| 828cca9c19 | |||
| f7740407c3 | |||
| 157ac9f3a2 | |||
| f21c9010ac | |||
| 7c045e5b23 | |||
| ae292e3a5f | |||
| 918b77eebb | |||
| 661751f306 | |||
| 2260caba00 | |||
| 3fe0873dc1 | |||
| 7c6ec73617 | |||
| 76dcd1c28e | |||
| 4fb1f4d2cb | |||
| 92039b95c3 | |||
| c0a703be7a | |||
| f08538cbfb | |||
| 1fa975ccec | |||
| ac62c26099 | |||
| 7ae3d9d99a | |||
| a9cfcaeda6 | |||
| 3d8b25922e | |||
| a9089859ce | |||
| c878e36015 | |||
| 8eec6b6b8a | |||
| 60219c2522 | |||
| cdb5cdf442 | |||
| 23f84d68e8 | |||
| 0f7f4b969f | |||
| 563a4b3a7c | |||
| 4700772e6d | |||
| ffb7f915c3 | |||
| 17d5ef1f6b | |||
| 9dcc42ff28 | |||
| 2845476d83 | |||
| 147b155d60 | |||
| 8b5e463546 | |||
| 822dcd8429 | |||
| 9f2e873366 | |||
| d2c0d4c11f | |||
| 48b6e8bf93 | |||
| 17a6b37545 | |||
| eedcef8f52 | |||
| 757eddd6f1 | |||
| 13f48711a9 | |||
| 1bbdf09dcc | |||
| 3b7c6ce25e | |||
| 38118e74ae | |||
| 6872a7e8b2 | |||
| ab3236230b | |||
| 6ef88e56ec | |||
| 18c18ea322 | |||
| 22fec8f9d3 | |||
| f50ec5cf31 | |||
| 4cbc28a087 | |||
| 01fdd25406 | |||
| 320f583660 | |||
| 8cc5ec6797 | |||
| edfbc2538d | |||
| 484c96187c | |||
| 85bf910d65 | |||
| 5ddd0872ef | |||
| 2700774469 | |||
| c79a992829 | |||
| 5e693313d8 | |||
| 59f4f43e84 | |||
| be39c2bc1f | |||
| b49ba2d04c | |||
| d7c87efe10 | |||
| 44a4b88809 | |||
| 768269f074 | |||
| d23ae2a8db | |||
| 88591697a2 | |||
| dcbb00f7c4 | |||
| e063ee0c29 | |||
| e5f478218e | |||
| 9a809a61dd | |||
| 4058ab7491 | |||
| 48ccebd4c2 | |||
| fcf00b9de1 | |||
| f7919b296b | |||
| 0b6af1fd21 | |||
| 3f424b72f6 | |||
| fc9d4616ba | |||
| 2e74f7533a | |||
| 784da2f8b9 | |||
| dbc29568ca | |||
| 5614ad54f2 | |||
| 67523f1e7b | |||
| fc57605219 | |||
| a31a2ffdbf | |||
| 900d47d6f9 | |||
| 6bdf0736ec | |||
| 92cde507d9 | |||
| 8afd626806 | |||
| 53f3758d2a | |||
| 1e6eb33408 | |||
| 51e20a81b7 | |||
| 4e8dc868bb | |||
| 9b8bcb05bd | |||
| 55e2a9bf37 | |||
| a82b087969 | |||
| 45aef104fe | |||
| 6746903808 | |||
| 36c1f4e736 | |||
| b0ca7ab127 | |||
| 2026bc8f48 | |||
| 6da8663a1d | |||
| b4e9f48667 | |||
| d58ba92cbd | |||
| c51194cd03 | |||
| ba0ec909c8 | |||
| 0db1c36d86 | |||
| 3e9fb521f0 | |||
| b5ad30a9bc | |||
| 5344493845 | |||
| 6f2108940e | |||
| 4f3e732891 | |||
| 0e2678575a | |||
| d6035a5f97 | |||
| b82a5eda78 | |||
| d17f30f5e6 | |||
| 7a3bdb531d | |||
| c6f3b49a6e | |||
| 99cd48ca6d | |||
| 02ed9b7a5c | |||
| 0f66687843 | |||
| 586f42867d | |||
| 14a7f0254d | |||
| 0aa0e51daa | |||
| f4f06abd72 | |||
| 7d8cb0bb45 | |||
| 2edffa02d0 | |||
| cfa4e5e45c | |||
| f879171398 | |||
| 6bfebd2923 | |||
| 3c60f406ea | |||
| af1c16ee51 | |||
| 1b25d88692 | |||
| 8a48abbbc8 | |||
| 6deab38c67 | |||
| 915b0eb372 | |||
| 6bb0474d62 | |||
| 2df96c0d31 | |||
| d94d7b5ee5 | |||
| 2f7f6bead9 | |||
| 3bbddcf092 | |||
| 838c6a8b6a | |||
| 5889b8976c | |||
| d06ddc9560 | |||
| 9b1f4e7154 | |||
| b569ec31ae | |||
| f7b8e34905 | |||
| 3cf7127f56 | |||
| cb823d94e5 | |||
| 4d0620c5df | |||
| 01371d0227 | |||
| 9e6a81cb62 | |||
| 7b616b44fa | |||
| 4c275ea878 | |||
| b59c86f78f | |||
| 14e6b4e7d6 | |||
| 63cdefcb27 | |||
| 11f9721abe | |||
| 0a82438beb | |||
| 8bd1cc80bc | |||
| 624b1bb94d | |||
| cf904b5d51 | |||
| 2ab48f5c97 | |||
| d56799e519 | |||
| 083e219ed2 | |||
| 1b379882f5 | |||
| ab031820f6 | |||
| d1dfbaedaa | |||
| 3070586104 | |||
| bcfb9dbec3 | |||
| 888bab50c9 | |||
| 715ee0fa3f | |||
| 1963e93d2e | |||
| ad3728a55d | |||
| df4f05b14c | |||
| 0c7a0cc88a | |||
| 98ef0b44ec | |||
| 24f06db2b8 | |||
| d63e5f5784 | |||
| 75ef43dffb | |||
| 65974dbf28 | |||
| 16433457ad | |||
| 19eaf44394 | |||
| 861fcec14f | |||
| 72cbd23089 | |||
| 1048431742 | |||
| 633c9f59d9 | |||
| 0ed13c75af | |||
| b0bc4c3cf3 | |||
| b8b8ca9f66 | |||
| f2e6a418b0 | |||
| 7fef7e4689 | |||
| 21bf995335 | |||
| bd13fb63ae | |||
| 67ccc20147 | |||
| 83991cf5a1 | |||
| dfb0ff42b3 | |||
| 008c12626d | |||
| 19e3f435c4 | |||
| ac6242ea94 | |||
| b87d7778df | |||
| acb906aad9 | |||
| 196cb1bd48 | |||
| 3981ad3eb5 | |||
| d54131b34a | |||
| 6ad6617d88 | |||
| 52163534db | |||
| 5dd65b18b7 | |||
| 1e77e1074a | |||
| 9537309fe2 | |||
| 4dc8920ff4 | |||
| 26e6f479b7 | |||
| d93e6a612e | |||
| 0baa6f4488 | |||
| 6490118741 | |||
| 58827a1dcf | |||
| a3804808b4 | |||
| d49bba42ef | |||
| c56f6a355d | |||
| 7b13e24ce4 | |||
| 088f1d0f99 | |||
| d7d611c6d1 | |||
| 65465d6cae | |||
| 3d8ba2e808 | |||
| 152be5d7e6 | |||
| 4326f6cf91 | |||
| 90dec929f4 | |||
| d6dc880ef4 | |||
| d0e2a798fe | |||
| fecaa2e6b8 | |||
| cdbd3f8c7b | |||
| b037329377 | |||
| 8b04f70106 | |||
| 737a05e2c5 | |||
| 78a30c2db4 | |||
| 5cef23944f | |||
| aa1cd742ad | |||
| 0f364f7c5c | |||
| 11be5c811f | |||
| 6174dc128d | |||
| 81455602ef | |||
| d6936634db | |||
| 88f53c17db | |||
| 82f107d835 | |||
| 1fee4c1946 | |||
| ec79d91d30 | |||
| 00a21269dd | |||
| 58ed2f3706 | |||
| 0a9dcf36b9 | |||
| dc1e728a2e | |||
| 085a3856e0 | |||
| a693981333 | |||
| 2a797bd6c9 | |||
| 4a64f5fe9b | |||
| 1f232fa4da | |||
| b3d95f765c | |||
| f298e60929 | |||
| 4745c4a42d | |||
| 6fddea552d | |||
| 24af17b8fe | |||
| 185175aa89 | |||
| 38a4e1b749 | |||
| 5929360fd8 | |||
| 25c96f2b18 | |||
| 93960d4605 | |||
| 73fd57cf33 | |||
| 5ff89aff8e | |||
| b3b17013bf | |||
| bd9cbea9b7 | |||
| 8f5115b9c6 | |||
| 5aae7180e7 | |||
| e7ccee4634 | |||
| 2e42e134e4 | |||
| be52f61fdb | |||
| 46a23318af | |||
| 1d82c84c9e | |||
| b2f9c73300 | |||
| f2e03266c2 | |||
| d5435686bf | |||
| d5ccf64bda | |||
| a24816ad6d | |||
| 35c4f85085 | |||
| 8dd920b294 | |||
| 3c86e6e28c | |||
| f4ba82531c | |||
| dc6936b22c | |||
| 131d7c5e3b | |||
| a423a45352 | |||
| 3ff46ce724 | |||
| e50c59c903 | |||
| 28c4646708 | |||
| 131e3b3c65 | |||
| 9836d548a6 | |||
| 694969cf41 | |||
| c86b452c90 | |||
| b39d11c0cc | |||
| 4d5e4082bb | |||
| 8ebe882236 | |||
| 0edba7e222 | |||
| 3c39bdaa29 | |||
| 04275a272b | |||
| 5c479e96ad | |||
| b967c8cb19 | |||
| e5ad41b9da | |||
| 7500046ac6 | |||
| b9a03fc412 | |||
| 552ad1b2a6 | |||
| 728b177e7a | |||
| 363f597e17 | |||
| b57ec3c966 | |||
| 026b1f6ec2 | |||
| 6bcc984b44 | |||
| 8a42a1bc6c | |||
| c7f588539d | |||
| 2b0d4c44a6 | |||
| d1c038ea6f | |||
| e94783820e | |||
| 9841fa3c63 | |||
| df5eba629a | |||
| feb4839ccd | |||
| d2ab8b470d | |||
| 926d7f714e | |||
| 5ed06f79b3 | |||
| 1883164150 | |||
| 69a10f4677 | |||
| c673218a8b | |||
| d1507604f2 | |||
| be3cc74e5d | |||
| a8243c476c | |||
| df9aad36c4 | |||
| 3b769233cf | |||
| e08ffcf20d | |||
| 84bdb30b57 | |||
| c10a4a9fd3 | |||
| 7cc3adedc4 | |||
| 7f62b583af | |||
| 4353e81df3 | |||
| ae5afe868e | |||
| 1fbdfe725c | |||
| 4614358163 | |||
| b6fd3a4f66 | |||
| 58d557e4e8 | |||
| 6d037e4760 | |||
| d203d287df | |||
| 2c8057df70 | |||
| bc15bee747 | |||
| 74b513f31a | |||
| ad3cfb01ce | |||
| 2e8d033614 | |||
| 39e2212d1d | |||
| 26ea4c0cc9 | |||
| 520b7ce136 | |||
| d011c29ce8 | |||
| ed12d59564 | |||
| 8699bba067 | |||
| f786b6f01b | |||
| 7d1083d1f7 | |||
| 6eb08243b7 | |||
| 747633fb25 | |||
| a4584ecd5c | |||
| 57c34637cf | |||
| 223cf469f4 | |||
| b4301486f3 | |||
| 226fea2c6d | |||
| 3dc3d6fe28 | |||
| ae3c331061 | |||
| 19f55b4a2e | |||
| b742b814c0 | |||
| 2a858f3107 | |||
| 9100b6197a | |||
| a354cab797 | |||
| 3399fc6bf6 | |||
| 45ecdadae2 | |||
| 39a114aad9 | |||
| a147b56485 | |||
| 33f1e8d70a | |||
| 6685bfe9d3 | |||
| e0883e7eb0 | |||
| c858479d57 | |||
| 3dd9e620a8 | |||
| 3c889d87ef | |||
| 93c6d046ee | |||
| b0cd967ae6 | |||
| 2445b334eb | |||
| 325bf54abe | |||
| e87c814068 |
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"rules": {
|
||||||
|
"no-console": "off",
|
||||||
|
"global-require": "off",
|
||||||
|
"import/no-dynamic-require": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/**
|
||||||
|
* Base webpack config used across other specific configs
|
||||||
|
*/
|
||||||
|
|
||||||
|
import webpack from 'webpack';
|
||||||
|
import { dependencies as externals } from '../../release/app/package.json';
|
||||||
|
import webpackPaths from './webpack.paths';
|
||||||
|
import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin';
|
||||||
|
|
||||||
|
const configuration: webpack.Configuration = {
|
||||||
|
externals: [...Object.keys(externals || {})],
|
||||||
|
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
exclude: /node_modules/,
|
||||||
|
test: /\.[jt]sx?$/,
|
||||||
|
use: {
|
||||||
|
loader: 'ts-loader',
|
||||||
|
options: {
|
||||||
|
// Remove this line to enable type checking in webpack builds
|
||||||
|
transpileOnly: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
output: {
|
||||||
|
// https://github.com/webpack/webpack/issues/1114
|
||||||
|
library: {
|
||||||
|
type: 'commonjs2',
|
||||||
|
},
|
||||||
|
|
||||||
|
path: webpackPaths.srcPath,
|
||||||
|
},
|
||||||
|
|
||||||
|
plugins: [
|
||||||
|
new webpack.EnvironmentPlugin({
|
||||||
|
NODE_ENV: 'production',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the array of extensions that should be used to resolve modules.
|
||||||
|
*/
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'],
|
||||||
|
fallback: {
|
||||||
|
child_process: false,
|
||||||
|
},
|
||||||
|
plugins: [new TsconfigPathsPlugin({ baseUrl: webpackPaths.srcPath })],
|
||||||
|
modules: [webpackPaths.srcPath, 'node_modules'],
|
||||||
|
},
|
||||||
|
|
||||||
|
stats: 'errors-only',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default configuration;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
/* eslint import/no-unresolved: off, import/no-self-import: off */
|
||||||
|
|
||||||
|
module.exports = require('./webpack.config.renderer.dev').default;
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
/**
|
||||||
|
* Webpack config for production electron main process
|
||||||
|
*/
|
||||||
|
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
import TerserPlugin from 'terser-webpack-plugin';
|
||||||
|
import webpack from 'webpack';
|
||||||
|
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
|
||||||
|
import { merge } from 'webpack-merge';
|
||||||
|
|
||||||
|
import checkNodeEnv from '../scripts/check-node-env';
|
||||||
|
import deleteSourceMaps from '../scripts/delete-source-maps';
|
||||||
|
import baseConfig from './webpack.config.base';
|
||||||
|
import webpackPaths from './webpack.paths';
|
||||||
|
|
||||||
|
checkNodeEnv('production');
|
||||||
|
deleteSourceMaps();
|
||||||
|
|
||||||
|
const devtoolsConfig =
|
||||||
|
process.env.DEBUG_PROD === 'true'
|
||||||
|
? {
|
||||||
|
devtool: 'source-map',
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
|
||||||
|
const configuration: webpack.Configuration = {
|
||||||
|
...devtoolsConfig,
|
||||||
|
|
||||||
|
mode: 'production',
|
||||||
|
|
||||||
|
target: 'electron-main',
|
||||||
|
|
||||||
|
entry: {
|
||||||
|
main: path.join(webpackPaths.srcMainPath, 'main.ts'),
|
||||||
|
preload: path.join(webpackPaths.srcMainPath, 'preload.ts'),
|
||||||
|
},
|
||||||
|
|
||||||
|
output: {
|
||||||
|
path: webpackPaths.distMainPath,
|
||||||
|
filename: '[name].js',
|
||||||
|
},
|
||||||
|
|
||||||
|
optimization: {
|
||||||
|
minimizer: [
|
||||||
|
new TerserPlugin({
|
||||||
|
parallel: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
plugins: [
|
||||||
|
new BundleAnalyzerPlugin({
|
||||||
|
analyzerMode: process.env.ANALYZE === 'true' ? 'server' : 'disabled',
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create global constants which can be configured at compile time.
|
||||||
|
*
|
||||||
|
* Useful for allowing different behaviour between development builds and
|
||||||
|
* release builds
|
||||||
|
*
|
||||||
|
* NODE_ENV should be production so that modules do not perform certain
|
||||||
|
* development checks
|
||||||
|
*/
|
||||||
|
new webpack.EnvironmentPlugin({
|
||||||
|
NODE_ENV: 'production',
|
||||||
|
DEBUG_PROD: false,
|
||||||
|
START_MINIMIZED: false,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables webpack processing of __dirname and __filename.
|
||||||
|
* If you run the bundle in node.js it falls back to these values of node.js.
|
||||||
|
* https://github.com/webpack/webpack/issues/2010
|
||||||
|
*/
|
||||||
|
node: {
|
||||||
|
__dirname: false,
|
||||||
|
__filename: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default merge(baseConfig, configuration);
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
import webpack from 'webpack';
|
||||||
|
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
|
||||||
|
import { merge } from 'webpack-merge';
|
||||||
|
|
||||||
|
import checkNodeEnv from '../scripts/check-node-env';
|
||||||
|
import baseConfig from './webpack.config.base';
|
||||||
|
import webpackPaths from './webpack.paths';
|
||||||
|
|
||||||
|
// When an ESLint server is running, we can't set the NODE_ENV so we'll check if it's
|
||||||
|
// at the dev webpack config is not accidentally run in a production environment
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
checkNodeEnv('development');
|
||||||
|
}
|
||||||
|
|
||||||
|
const configuration: webpack.Configuration = {
|
||||||
|
devtool: 'inline-source-map',
|
||||||
|
|
||||||
|
mode: 'development',
|
||||||
|
|
||||||
|
target: 'electron-preload',
|
||||||
|
|
||||||
|
entry: path.join(webpackPaths.srcMainPath, 'preload.ts'),
|
||||||
|
|
||||||
|
output: {
|
||||||
|
path: webpackPaths.dllPath,
|
||||||
|
filename: 'preload.js',
|
||||||
|
},
|
||||||
|
|
||||||
|
plugins: [
|
||||||
|
new BundleAnalyzerPlugin({
|
||||||
|
analyzerMode: process.env.ANALYZE === 'true' ? 'server' : 'disabled',
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create global constants which can be configured at compile time.
|
||||||
|
*
|
||||||
|
* Useful for allowing different behaviour between development builds and
|
||||||
|
* release builds
|
||||||
|
*
|
||||||
|
* NODE_ENV should be production so that modules do not perform certain
|
||||||
|
* development checks
|
||||||
|
*
|
||||||
|
* By default, use 'development' as NODE_ENV. This can be overriden with
|
||||||
|
* 'staging', for example, by changing the ENV variables in the npm scripts
|
||||||
|
*/
|
||||||
|
new webpack.EnvironmentPlugin({
|
||||||
|
NODE_ENV: 'development',
|
||||||
|
}),
|
||||||
|
|
||||||
|
new webpack.LoaderOptionsPlugin({
|
||||||
|
debug: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables webpack processing of __dirname and __filename.
|
||||||
|
* If you run the bundle in node.js it falls back to these values of node.js.
|
||||||
|
* https://github.com/webpack/webpack/issues/2010
|
||||||
|
*/
|
||||||
|
node: {
|
||||||
|
__dirname: false,
|
||||||
|
__filename: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default merge(baseConfig, configuration);
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/**
|
||||||
|
* Builds the DLL for development electron renderer process
|
||||||
|
*/
|
||||||
|
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
import webpack from 'webpack';
|
||||||
|
import { merge } from 'webpack-merge';
|
||||||
|
|
||||||
|
import { dependencies } from '../../package.json';
|
||||||
|
import checkNodeEnv from '../scripts/check-node-env';
|
||||||
|
import baseConfig from './webpack.config.base';
|
||||||
|
import webpackPaths from './webpack.paths';
|
||||||
|
|
||||||
|
checkNodeEnv('development');
|
||||||
|
|
||||||
|
const dist = webpackPaths.dllPath;
|
||||||
|
|
||||||
|
const configuration: webpack.Configuration = {
|
||||||
|
context: webpackPaths.rootPath,
|
||||||
|
|
||||||
|
devtool: 'eval',
|
||||||
|
|
||||||
|
mode: 'development',
|
||||||
|
|
||||||
|
target: 'electron-renderer',
|
||||||
|
|
||||||
|
externals: ['fsevents', 'crypto-browserify'],
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use `module` from `webpack.config.renderer.dev.js`
|
||||||
|
*/
|
||||||
|
module: require('./webpack.config.renderer.dev').default.module,
|
||||||
|
|
||||||
|
entry: {
|
||||||
|
renderer: Object.keys(dependencies || {}),
|
||||||
|
},
|
||||||
|
|
||||||
|
output: {
|
||||||
|
path: dist,
|
||||||
|
filename: '[name].dev.dll.js',
|
||||||
|
library: {
|
||||||
|
name: 'renderer',
|
||||||
|
type: 'var',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
plugins: [
|
||||||
|
new webpack.DllPlugin({
|
||||||
|
path: path.join(dist, '[name].json'),
|
||||||
|
name: '[name]',
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create global constants which can be configured at compile time.
|
||||||
|
*
|
||||||
|
* Useful for allowing different behaviour between development builds and
|
||||||
|
* release builds
|
||||||
|
*
|
||||||
|
* NODE_ENV should be production so that modules do not perform certain
|
||||||
|
* development checks
|
||||||
|
*/
|
||||||
|
new webpack.EnvironmentPlugin({
|
||||||
|
NODE_ENV: 'development',
|
||||||
|
}),
|
||||||
|
|
||||||
|
new webpack.LoaderOptionsPlugin({
|
||||||
|
debug: true,
|
||||||
|
options: {
|
||||||
|
context: webpackPaths.srcPath,
|
||||||
|
output: {
|
||||||
|
path: webpackPaths.dllPath,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default merge(baseConfig, configuration);
|
||||||
@@ -0,0 +1,186 @@
|
|||||||
|
import 'webpack-dev-server';
|
||||||
|
import { execSync, spawn } from 'child_process';
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';
|
||||||
|
import chalk from 'chalk';
|
||||||
|
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||||
|
import webpack from 'webpack';
|
||||||
|
import { merge } from 'webpack-merge';
|
||||||
|
|
||||||
|
import checkNodeEnv from '../scripts/check-node-env';
|
||||||
|
import baseConfig from './webpack.config.base';
|
||||||
|
import webpackPaths from './webpack.paths';
|
||||||
|
|
||||||
|
// When an ESLint server is running, we can't set the NODE_ENV so we'll check if it's
|
||||||
|
// at the dev webpack config is not accidentally run in a production environment
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
checkNodeEnv('development');
|
||||||
|
}
|
||||||
|
|
||||||
|
const port = process.env.PORT || 4343;
|
||||||
|
const manifest = path.resolve(webpackPaths.dllPath, 'renderer.json');
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
const requiredByDLLConfig = module.parent!.filename.includes('webpack.config.renderer.dev.dll');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Warn if the DLL is not built
|
||||||
|
*/
|
||||||
|
if (!requiredByDLLConfig && !(fs.existsSync(webpackPaths.dllPath) && fs.existsSync(manifest))) {
|
||||||
|
console.log(
|
||||||
|
chalk.black.bgYellow.bold(
|
||||||
|
'The DLL files are missing. Sit back while we build them for you with "npm run build-dll"',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
execSync('npm run postinstall');
|
||||||
|
}
|
||||||
|
|
||||||
|
const configuration: webpack.Configuration = {
|
||||||
|
devtool: 'inline-source-map',
|
||||||
|
|
||||||
|
mode: 'development',
|
||||||
|
|
||||||
|
target: ['web', 'electron-renderer'],
|
||||||
|
|
||||||
|
entry: [
|
||||||
|
`webpack-dev-server/client?http://localhost:${port}/dist`,
|
||||||
|
'webpack/hot/only-dev-server',
|
||||||
|
path.join(webpackPaths.srcRendererPath, 'index.tsx'),
|
||||||
|
],
|
||||||
|
|
||||||
|
output: {
|
||||||
|
path: webpackPaths.distRendererPath,
|
||||||
|
publicPath: '/',
|
||||||
|
filename: 'renderer.dev.js',
|
||||||
|
library: {
|
||||||
|
type: 'umd',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.s?css$/,
|
||||||
|
use: [
|
||||||
|
'style-loader',
|
||||||
|
{
|
||||||
|
loader: 'css-loader',
|
||||||
|
options: {
|
||||||
|
modules: true,
|
||||||
|
sourceMap: true,
|
||||||
|
importLoaders: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'sass-loader',
|
||||||
|
],
|
||||||
|
include: /\.module\.s?(c|a)ss$/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.s?css$/,
|
||||||
|
use: ['style-loader', 'css-loader', 'sass-loader'],
|
||||||
|
exclude: /\.module\.s?(c|a)ss$/,
|
||||||
|
},
|
||||||
|
// Fonts
|
||||||
|
{
|
||||||
|
test: /\.(woff|woff2|eot|ttf|otf)$/i,
|
||||||
|
type: 'asset/resource',
|
||||||
|
},
|
||||||
|
// Images
|
||||||
|
{
|
||||||
|
test: /\.(png|svg|jpg|jpeg|gif)$/i,
|
||||||
|
type: 'asset/resource',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
...(requiredByDLLConfig
|
||||||
|
? []
|
||||||
|
: [
|
||||||
|
new webpack.DllReferencePlugin({
|
||||||
|
context: webpackPaths.dllPath,
|
||||||
|
manifest: require(manifest),
|
||||||
|
sourceType: 'var',
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
|
||||||
|
new webpack.NoEmitOnErrorsPlugin(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create global constants which can be configured at compile time.
|
||||||
|
*
|
||||||
|
* Useful for allowing different behaviour between development builds and
|
||||||
|
* release builds
|
||||||
|
*
|
||||||
|
* NODE_ENV should be production so that modules do not perform certain
|
||||||
|
* development checks
|
||||||
|
*
|
||||||
|
* By default, use 'development' as NODE_ENV. This can be overriden with
|
||||||
|
* 'staging', for example, by changing the ENV variables in the npm scripts
|
||||||
|
*/
|
||||||
|
new webpack.EnvironmentPlugin({
|
||||||
|
NODE_ENV: 'development',
|
||||||
|
}),
|
||||||
|
|
||||||
|
new webpack.LoaderOptionsPlugin({
|
||||||
|
debug: true,
|
||||||
|
}),
|
||||||
|
|
||||||
|
new ReactRefreshWebpackPlugin(),
|
||||||
|
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
filename: path.join('index.html'),
|
||||||
|
template: path.join(webpackPaths.srcRendererPath, 'index.ejs'),
|
||||||
|
minify: {
|
||||||
|
collapseWhitespace: true,
|
||||||
|
removeAttributeQuotes: true,
|
||||||
|
removeComments: true,
|
||||||
|
},
|
||||||
|
isBrowser: false,
|
||||||
|
env: process.env.NODE_ENV,
|
||||||
|
isDevelopment: process.env.NODE_ENV !== 'production',
|
||||||
|
nodeModules: webpackPaths.appNodeModulesPath,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
|
||||||
|
node: {
|
||||||
|
__dirname: false,
|
||||||
|
__filename: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
devServer: {
|
||||||
|
port,
|
||||||
|
compress: true,
|
||||||
|
hot: true,
|
||||||
|
headers: { 'Access-Control-Allow-Origin': '*' },
|
||||||
|
static: {
|
||||||
|
publicPath: '/',
|
||||||
|
},
|
||||||
|
historyApiFallback: {
|
||||||
|
verbose: true,
|
||||||
|
},
|
||||||
|
setupMiddlewares(middlewares) {
|
||||||
|
console.log('Starting preload.js builder...');
|
||||||
|
const preloadProcess = spawn('npm', ['run', 'start:preload'], {
|
||||||
|
shell: true,
|
||||||
|
stdio: 'inherit',
|
||||||
|
})
|
||||||
|
.on('close', (code: number) => process.exit(code!))
|
||||||
|
.on('error', (spawnError) => console.error(spawnError));
|
||||||
|
|
||||||
|
console.log('Starting Main Process...');
|
||||||
|
spawn('npm', ['run', 'start:main'], {
|
||||||
|
shell: true,
|
||||||
|
stdio: 'inherit',
|
||||||
|
})
|
||||||
|
.on('close', (code: number) => {
|
||||||
|
preloadProcess.kill();
|
||||||
|
process.exit(code!);
|
||||||
|
})
|
||||||
|
.on('error', (spawnError) => console.error(spawnError));
|
||||||
|
return middlewares;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default merge(baseConfig, configuration);
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
/**
|
||||||
|
* Build config for electron renderer process
|
||||||
|
*/
|
||||||
|
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
|
||||||
|
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||||
|
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
|
||||||
|
import TerserPlugin from 'terser-webpack-plugin';
|
||||||
|
import webpack from 'webpack';
|
||||||
|
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
|
||||||
|
import { merge } from 'webpack-merge';
|
||||||
|
|
||||||
|
import checkNodeEnv from '../scripts/check-node-env';
|
||||||
|
import deleteSourceMaps from '../scripts/delete-source-maps';
|
||||||
|
import baseConfig from './webpack.config.base';
|
||||||
|
import webpackPaths from './webpack.paths';
|
||||||
|
|
||||||
|
checkNodeEnv('production');
|
||||||
|
deleteSourceMaps();
|
||||||
|
|
||||||
|
const devtoolsConfig =
|
||||||
|
process.env.DEBUG_PROD === 'true'
|
||||||
|
? {
|
||||||
|
devtool: 'source-map',
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
|
||||||
|
const configuration: webpack.Configuration = {
|
||||||
|
...devtoolsConfig,
|
||||||
|
|
||||||
|
mode: 'production',
|
||||||
|
|
||||||
|
target: ['web', 'electron-renderer'],
|
||||||
|
|
||||||
|
entry: [path.join(webpackPaths.srcRendererPath, 'index.tsx')],
|
||||||
|
|
||||||
|
output: {
|
||||||
|
path: webpackPaths.distRendererPath,
|
||||||
|
publicPath: './',
|
||||||
|
filename: 'renderer.js',
|
||||||
|
library: {
|
||||||
|
type: 'umd',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.s?(a|c)ss$/,
|
||||||
|
use: [
|
||||||
|
MiniCssExtractPlugin.loader,
|
||||||
|
{
|
||||||
|
loader: 'css-loader',
|
||||||
|
options: {
|
||||||
|
modules: true,
|
||||||
|
sourceMap: true,
|
||||||
|
importLoaders: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'sass-loader',
|
||||||
|
],
|
||||||
|
include: /\.module\.s?(c|a)ss$/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.s?(a|c)ss$/,
|
||||||
|
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
|
||||||
|
exclude: /\.module\.s?(c|a)ss$/,
|
||||||
|
},
|
||||||
|
// Fonts
|
||||||
|
{
|
||||||
|
test: /\.(woff|woff2|eot|ttf|otf)$/i,
|
||||||
|
type: 'asset/resource',
|
||||||
|
},
|
||||||
|
// Images
|
||||||
|
{
|
||||||
|
test: /\.(png|svg|jpg|jpeg|gif)$/i,
|
||||||
|
type: 'asset/resource',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
optimization: {
|
||||||
|
minimize: true,
|
||||||
|
minimizer: [
|
||||||
|
new TerserPlugin({
|
||||||
|
parallel: true,
|
||||||
|
}),
|
||||||
|
new CssMinimizerPlugin(),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
plugins: [
|
||||||
|
/**
|
||||||
|
* Create global constants which can be configured at compile time.
|
||||||
|
*
|
||||||
|
* Useful for allowing different behaviour between development builds and
|
||||||
|
* release builds
|
||||||
|
*
|
||||||
|
* NODE_ENV should be production so that modules do not perform certain
|
||||||
|
* development checks
|
||||||
|
*/
|
||||||
|
new webpack.EnvironmentPlugin({
|
||||||
|
NODE_ENV: 'production',
|
||||||
|
DEBUG_PROD: false,
|
||||||
|
}),
|
||||||
|
|
||||||
|
new MiniCssExtractPlugin({
|
||||||
|
filename: 'style.css',
|
||||||
|
}),
|
||||||
|
|
||||||
|
new BundleAnalyzerPlugin({
|
||||||
|
analyzerMode: process.env.ANALYZE === 'true' ? 'server' : 'disabled',
|
||||||
|
}),
|
||||||
|
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
filename: 'index.html',
|
||||||
|
template: path.join(webpackPaths.srcRendererPath, 'index.ejs'),
|
||||||
|
minify: {
|
||||||
|
collapseWhitespace: true,
|
||||||
|
removeAttributeQuotes: true,
|
||||||
|
removeComments: true,
|
||||||
|
},
|
||||||
|
isBrowser: false,
|
||||||
|
isDevelopment: process.env.NODE_ENV !== 'production',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default merge(baseConfig, configuration);
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
import 'webpack-dev-server';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';
|
||||||
|
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||||
|
import webpack from 'webpack';
|
||||||
|
import { merge } from 'webpack-merge';
|
||||||
|
|
||||||
|
import checkNodeEnv from '../scripts/check-node-env';
|
||||||
|
import baseConfig from './webpack.config.base';
|
||||||
|
import webpackPaths from './webpack.paths';
|
||||||
|
|
||||||
|
// When an ESLint server is running, we can't set the NODE_ENV so we'll check if it's
|
||||||
|
// at the dev webpack config is not accidentally run in a production environment
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
checkNodeEnv('development');
|
||||||
|
}
|
||||||
|
|
||||||
|
const port = process.env.PORT || 4343;
|
||||||
|
|
||||||
|
const configuration: webpack.Configuration = {
|
||||||
|
devtool: 'inline-source-map',
|
||||||
|
|
||||||
|
mode: 'development',
|
||||||
|
|
||||||
|
target: ['web', 'electron-renderer'],
|
||||||
|
|
||||||
|
entry: [
|
||||||
|
`webpack-dev-server/client?http://localhost:${port}/dist`,
|
||||||
|
'webpack/hot/only-dev-server',
|
||||||
|
path.join(webpackPaths.srcRendererPath, 'index.tsx'),
|
||||||
|
],
|
||||||
|
|
||||||
|
output: {
|
||||||
|
path: webpackPaths.distRendererPath,
|
||||||
|
publicPath: '/',
|
||||||
|
filename: 'renderer.dev.js',
|
||||||
|
library: {
|
||||||
|
type: 'umd',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.s?css$/,
|
||||||
|
use: [
|
||||||
|
'style-loader',
|
||||||
|
{
|
||||||
|
loader: 'css-loader',
|
||||||
|
options: {
|
||||||
|
modules: true,
|
||||||
|
sourceMap: true,
|
||||||
|
importLoaders: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'sass-loader',
|
||||||
|
],
|
||||||
|
include: /\.module\.s?(c|a)ss$/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.s?css$/,
|
||||||
|
use: ['style-loader', 'css-loader', 'sass-loader'],
|
||||||
|
exclude: /\.module\.s?(c|a)ss$/,
|
||||||
|
},
|
||||||
|
// Fonts
|
||||||
|
{
|
||||||
|
test: /\.(woff|woff2|eot|ttf|otf)$/i,
|
||||||
|
type: 'asset/resource',
|
||||||
|
},
|
||||||
|
// Images
|
||||||
|
{
|
||||||
|
test: /\.(png|svg|jpg|jpeg|gif)$/i,
|
||||||
|
type: 'asset/resource',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new webpack.NoEmitOnErrorsPlugin(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create global constants which can be configured at compile time.
|
||||||
|
*
|
||||||
|
* Useful for allowing different behaviour between development builds and
|
||||||
|
* release builds
|
||||||
|
*
|
||||||
|
* NODE_ENV should be production so that modules do not perform certain
|
||||||
|
* development checks
|
||||||
|
*
|
||||||
|
* By default, use 'development' as NODE_ENV. This can be overriden with
|
||||||
|
* 'staging', for example, by changing the ENV variables in the npm scripts
|
||||||
|
*/
|
||||||
|
new webpack.EnvironmentPlugin({
|
||||||
|
NODE_ENV: 'development',
|
||||||
|
}),
|
||||||
|
|
||||||
|
new webpack.LoaderOptionsPlugin({
|
||||||
|
debug: true,
|
||||||
|
}),
|
||||||
|
|
||||||
|
new ReactRefreshWebpackPlugin(),
|
||||||
|
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
filename: path.join('index.html'),
|
||||||
|
template: path.join(webpackPaths.srcRendererPath, 'index.ejs'),
|
||||||
|
minify: {
|
||||||
|
collapseWhitespace: true,
|
||||||
|
removeAttributeQuotes: true,
|
||||||
|
removeComments: true,
|
||||||
|
},
|
||||||
|
isBrowser: false,
|
||||||
|
env: process.env.NODE_ENV,
|
||||||
|
isDevelopment: process.env.NODE_ENV !== 'production',
|
||||||
|
nodeModules: webpackPaths.appNodeModulesPath,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
|
||||||
|
node: {
|
||||||
|
__dirname: false,
|
||||||
|
__filename: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
devServer: {
|
||||||
|
port,
|
||||||
|
compress: true,
|
||||||
|
hot: true,
|
||||||
|
headers: { 'Access-Control-Allow-Origin': '*' },
|
||||||
|
static: {
|
||||||
|
publicPath: '/',
|
||||||
|
},
|
||||||
|
historyApiFallback: {
|
||||||
|
verbose: true,
|
||||||
|
},
|
||||||
|
setupMiddlewares(middlewares) {
|
||||||
|
return middlewares;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default merge(baseConfig, configuration);
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const rootPath = path.join(__dirname, '../..');
|
||||||
|
|
||||||
|
const dllPath = path.join(__dirname, '../dll');
|
||||||
|
|
||||||
|
const srcPath = path.join(rootPath, 'src');
|
||||||
|
const srcMainPath = path.join(srcPath, 'main');
|
||||||
|
const srcRendererPath = path.join(srcPath, 'renderer');
|
||||||
|
|
||||||
|
const releasePath = path.join(rootPath, 'release');
|
||||||
|
const appPath = path.join(releasePath, 'app');
|
||||||
|
const appPackagePath = path.join(appPath, 'package.json');
|
||||||
|
const appNodeModulesPath = path.join(appPath, 'node_modules');
|
||||||
|
const srcNodeModulesPath = path.join(srcPath, 'node_modules');
|
||||||
|
|
||||||
|
const distPath = path.join(appPath, 'dist');
|
||||||
|
const distMainPath = path.join(distPath, 'main');
|
||||||
|
const distRendererPath = path.join(distPath, 'renderer');
|
||||||
|
|
||||||
|
const buildPath = path.join(releasePath, 'build');
|
||||||
|
|
||||||
|
export default {
|
||||||
|
rootPath,
|
||||||
|
dllPath,
|
||||||
|
srcPath,
|
||||||
|
srcMainPath,
|
||||||
|
srcRendererPath,
|
||||||
|
releasePath,
|
||||||
|
appPath,
|
||||||
|
appPackagePath,
|
||||||
|
appNodeModulesPath,
|
||||||
|
srcNodeModulesPath,
|
||||||
|
distPath,
|
||||||
|
distMainPath,
|
||||||
|
distRendererPath,
|
||||||
|
buildPath,
|
||||||
|
};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export default 'test-file-stub';
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"rules": {
|
||||||
|
"no-console": "off",
|
||||||
|
"global-require": "off",
|
||||||
|
"import/no-dynamic-require": "off",
|
||||||
|
"import/no-extraneous-dependencies": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
// Check if the renderer and main bundles are built
|
||||||
|
import path from 'path';
|
||||||
|
import chalk from 'chalk';
|
||||||
|
import fs from 'fs';
|
||||||
|
import webpackPaths from '../configs/webpack.paths';
|
||||||
|
|
||||||
|
const mainPath = path.join(webpackPaths.distMainPath, 'main.js');
|
||||||
|
const rendererPath = path.join(webpackPaths.distRendererPath, 'renderer.js');
|
||||||
|
|
||||||
|
if (!fs.existsSync(mainPath)) {
|
||||||
|
throw new Error(
|
||||||
|
chalk.whiteBright.bgRed.bold(
|
||||||
|
'The main process is not built yet. Build it by running "npm run build:main"'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fs.existsSync(rendererPath)) {
|
||||||
|
throw new Error(
|
||||||
|
chalk.whiteBright.bgRed.bold(
|
||||||
|
'The renderer process is not built yet. Build it by running "npm run build:renderer"'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import chalk from 'chalk';
|
||||||
|
import { execSync } from 'child_process';
|
||||||
|
import { dependencies } from '../../package.json';
|
||||||
|
|
||||||
|
if (dependencies) {
|
||||||
|
const dependenciesKeys = Object.keys(dependencies);
|
||||||
|
const nativeDeps = fs
|
||||||
|
.readdirSync('node_modules')
|
||||||
|
.filter((folder) => fs.existsSync(`node_modules/${folder}/binding.gyp`));
|
||||||
|
if (nativeDeps.length === 0) {
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// Find the reason for why the dependency is installed. If it is installed
|
||||||
|
// because of a devDependency then that is okay. Warn when it is installed
|
||||||
|
// because of a dependency
|
||||||
|
const { dependencies: dependenciesObject } = JSON.parse(
|
||||||
|
execSync(`npm ls ${nativeDeps.join(' ')} --json`).toString()
|
||||||
|
);
|
||||||
|
const rootDependencies = Object.keys(dependenciesObject);
|
||||||
|
const filteredRootDependencies = rootDependencies.filter((rootDependency) =>
|
||||||
|
dependenciesKeys.includes(rootDependency)
|
||||||
|
);
|
||||||
|
if (filteredRootDependencies.length > 0) {
|
||||||
|
const plural = filteredRootDependencies.length > 1;
|
||||||
|
console.log(`
|
||||||
|
${chalk.whiteBright.bgYellow.bold(
|
||||||
|
'Webpack does not work with native dependencies.'
|
||||||
|
)}
|
||||||
|
${chalk.bold(filteredRootDependencies.join(', '))} ${
|
||||||
|
plural ? 'are native dependencies' : 'is a native dependency'
|
||||||
|
} and should be installed inside of the "./release/app" folder.
|
||||||
|
First, uninstall the packages from "./package.json":
|
||||||
|
${chalk.whiteBright.bgGreen.bold('npm uninstall your-package')}
|
||||||
|
${chalk.bold(
|
||||||
|
'Then, instead of installing the package to the root "./package.json":'
|
||||||
|
)}
|
||||||
|
${chalk.whiteBright.bgRed.bold('npm install your-package')}
|
||||||
|
${chalk.bold('Install the package to "./release/app/package.json"')}
|
||||||
|
${chalk.whiteBright.bgGreen.bold(
|
||||||
|
'cd ./release/app && npm install your-package'
|
||||||
|
)}
|
||||||
|
Read more about native dependencies at:
|
||||||
|
${chalk.bold(
|
||||||
|
'https://electron-react-boilerplate.js.org/docs/adding-dependencies/#module-structure'
|
||||||
|
)}
|
||||||
|
`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log('Native dependencies could not be checked');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import chalk from 'chalk';
|
||||||
|
|
||||||
|
export default function checkNodeEnv(expectedEnv) {
|
||||||
|
if (!expectedEnv) {
|
||||||
|
throw new Error('"expectedEnv" not set');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV !== expectedEnv) {
|
||||||
|
console.log(
|
||||||
|
chalk.whiteBright.bgRed.bold(
|
||||||
|
`"process.env.NODE_ENV" must be "${expectedEnv}" to use this webpack config`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
process.exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import chalk from 'chalk';
|
||||||
|
import detectPort from 'detect-port';
|
||||||
|
|
||||||
|
const port = process.env.PORT || '4343';
|
||||||
|
|
||||||
|
detectPort(port, (err, availablePort) => {
|
||||||
|
if (port !== String(availablePort)) {
|
||||||
|
throw new Error(
|
||||||
|
chalk.whiteBright.bgRed.bold(
|
||||||
|
`Port "${port}" on "localhost" is already in use. Please use another port. ex: PORT=4343 npm start`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import rimraf from 'rimraf';
|
||||||
|
import process from 'process';
|
||||||
|
import webpackPaths from '../configs/webpack.paths';
|
||||||
|
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
const commandMap = {
|
||||||
|
dist: webpackPaths.distPath,
|
||||||
|
release: webpackPaths.releasePath,
|
||||||
|
dll: webpackPaths.dllPath,
|
||||||
|
};
|
||||||
|
|
||||||
|
args.forEach((x) => {
|
||||||
|
const pathToRemove = commandMap[x];
|
||||||
|
if (pathToRemove !== undefined) {
|
||||||
|
rimraf.sync(pathToRemove);
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import path from 'path';
|
||||||
|
import rimraf from 'rimraf';
|
||||||
|
import webpackPaths from '../configs/webpack.paths';
|
||||||
|
|
||||||
|
export default function deleteSourceMaps() {
|
||||||
|
rimraf.sync(path.join(webpackPaths.distMainPath, '*.js.map'));
|
||||||
|
rimraf.sync(path.join(webpackPaths.distRendererPath, '*.js.map'));
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { execSync } from 'child_process';
|
||||||
|
import fs from 'fs';
|
||||||
|
import { dependencies } from '../../release/app/package.json';
|
||||||
|
import webpackPaths from '../configs/webpack.paths';
|
||||||
|
|
||||||
|
if (
|
||||||
|
Object.keys(dependencies || {}).length > 0 &&
|
||||||
|
fs.existsSync(webpackPaths.appNodeModulesPath)
|
||||||
|
) {
|
||||||
|
const electronRebuildCmd =
|
||||||
|
'../../node_modules/.bin/electron-rebuild --force --types prod,dev,optional --module-dir .';
|
||||||
|
const cmd =
|
||||||
|
process.platform === 'win32'
|
||||||
|
? electronRebuildCmd.replace(/\//g, '\\')
|
||||||
|
: electronRebuildCmd;
|
||||||
|
execSync(cmd, {
|
||||||
|
cwd: webpackPaths.appPath,
|
||||||
|
stdio: 'inherit',
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import webpackPaths from '../configs/webpack.paths';
|
||||||
|
|
||||||
|
const { srcNodeModulesPath } = webpackPaths;
|
||||||
|
const { appNodeModulesPath } = webpackPaths;
|
||||||
|
|
||||||
|
if (!fs.existsSync(srcNodeModulesPath) && fs.existsSync(appNodeModulesPath)) {
|
||||||
|
fs.symlinkSync(appNodeModulesPath, srcNodeModulesPath, 'junction');
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
const { notarize } = require('electron-notarize');
|
||||||
|
const { build } = require('../../package.json');
|
||||||
|
|
||||||
|
exports.default = async function notarizeMacos(context) {
|
||||||
|
const { electronPlatformName, appOutDir } = context;
|
||||||
|
if (electronPlatformName !== 'darwin') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.CI !== 'true') {
|
||||||
|
console.warn('Skipping notarizing step. Packaging is not running in CI');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!('APPLE_ID' in process.env && 'APPLE_ID_PASS' in process.env)) {
|
||||||
|
console.warn(
|
||||||
|
'Skipping notarizing step. APPLE_ID and APPLE_ID_PASS env variables must be set'
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const appName = context.packager.appInfo.productFilename;
|
||||||
|
|
||||||
|
await notarize({
|
||||||
|
appBundleId: build.appId,
|
||||||
|
appPath: `${appOutDir}/${appName}.app`,
|
||||||
|
appleId: process.env.APPLE_ID,
|
||||||
|
appleIdPassword: process.env.APPLE_ID_PASS,
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Dependency directory
|
||||||
|
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# OSX
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
src/i18n
|
||||||
|
release/app/dist
|
||||||
|
release/build
|
||||||
|
.erb/dll
|
||||||
|
|
||||||
|
.idea
|
||||||
|
npm-debug.log.*
|
||||||
|
*.css.d.ts
|
||||||
|
*.sass.d.ts
|
||||||
|
*.scss.d.ts
|
||||||
|
|
||||||
|
# eslint ignores hidden directories by default:
|
||||||
|
# https://github.com/eslint/eslint/issues/8429
|
||||||
|
!.erb
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
module.exports = {
|
||||||
|
extends: ['erb', 'plugin:typescript-sort-keys/recommended'],
|
||||||
|
ignorePatterns: ['.erb/*', 'server'],
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
parserOptions: {
|
||||||
|
createDefaultProgram: true,
|
||||||
|
ecmaVersion: 12,
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
project: './tsconfig.json',
|
||||||
|
sourceType: 'module',
|
||||||
|
tsconfigRootDir: './',
|
||||||
|
},
|
||||||
|
plugins: ['@typescript-eslint', 'import', 'sort-keys-fix'],
|
||||||
|
rules: {
|
||||||
|
'@typescript-eslint/naming-convention': 'off',
|
||||||
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
|
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||||
|
'@typescript-eslint/no-shadow': ['off'],
|
||||||
|
'default-case': 'off',
|
||||||
|
'import/extensions': 'off',
|
||||||
|
'import/no-absolute-path': 'off',
|
||||||
|
// A temporary hack related to IDE not resolving correct package.json
|
||||||
|
'import/no-extraneous-dependencies': 'off',
|
||||||
|
|
||||||
|
'import/no-unresolved': 'error',
|
||||||
|
'import/order': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
alphabetize: {
|
||||||
|
caseInsensitive: true,
|
||||||
|
order: 'asc',
|
||||||
|
},
|
||||||
|
groups: ['builtin', 'external', 'internal', ['parent', 'sibling']],
|
||||||
|
'newlines-between': 'never',
|
||||||
|
pathGroups: [
|
||||||
|
{
|
||||||
|
group: 'external',
|
||||||
|
pattern: 'react',
|
||||||
|
position: 'before',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
pathGroupsExcludedImportTypes: ['react'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'import/prefer-default-export': 'off',
|
||||||
|
'jsx-a11y/click-events-have-key-events': 'off',
|
||||||
|
'jsx-a11y/interactive-supports-focus': 'off',
|
||||||
|
'jsx-a11y/media-has-caption': 'off',
|
||||||
|
'no-await-in-loop': 'off',
|
||||||
|
'no-console': 'off',
|
||||||
|
'no-nested-ternary': 'off',
|
||||||
|
'no-restricted-syntax': 'off',
|
||||||
|
'no-underscore-dangle': 'off',
|
||||||
|
'prefer-destructuring': 'off',
|
||||||
|
'react/jsx-props-no-spreading': 'off',
|
||||||
|
'react/jsx-sort-props': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
callbacksLast: true,
|
||||||
|
ignoreCase: false,
|
||||||
|
noSortAlphabetically: false,
|
||||||
|
reservedFirst: true,
|
||||||
|
shorthandFirst: true,
|
||||||
|
shorthandLast: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'react/no-array-index-key': 'off',
|
||||||
|
'react/react-in-jsx-scope': 'off',
|
||||||
|
'react/require-default-props': 'off',
|
||||||
|
'sort-keys-fix/sort-keys-fix': 'warn',
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
'import/parsers': {
|
||||||
|
'@typescript-eslint/parser': ['.ts', '.tsx'],
|
||||||
|
},
|
||||||
|
'import/resolver': {
|
||||||
|
// See https://github.com/benmosher/eslint-plugin-import/issues/1396#issuecomment-575727774 for line below
|
||||||
|
node: {
|
||||||
|
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||||
|
},
|
||||||
|
typescript: {
|
||||||
|
alwaysTryTypes: true,
|
||||||
|
project: './tsconfig.json',
|
||||||
|
},
|
||||||
|
webpack: {
|
||||||
|
config: require.resolve('./.erb/configs/webpack.config.eslint.ts'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
{
|
|
||||||
"env": {
|
|
||||||
"browser": true,
|
|
||||||
"es2021": true
|
|
||||||
},
|
|
||||||
"ignorePatterns": [
|
|
||||||
"node_modules/*",
|
|
||||||
"dist/*",
|
|
||||||
"electron/preload/*",
|
|
||||||
"vite.config.ts",
|
|
||||||
"post-install.js"
|
|
||||||
],
|
|
||||||
"extends": [
|
|
||||||
"plugin:react/recommended",
|
|
||||||
"plugin:react-hooks/recommended",
|
|
||||||
"eslint:recommended",
|
|
||||||
"plugin:@typescript-eslint/eslint-recommended",
|
|
||||||
"plugin:@typescript-eslint/recommended",
|
|
||||||
"plugin:typescript-sort-keys/recommended",
|
|
||||||
"prettier"
|
|
||||||
],
|
|
||||||
"parser": "@typescript-eslint/parser",
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaFeatures": {
|
|
||||||
"jsx": true
|
|
||||||
},
|
|
||||||
"ecmaVersion": "latest",
|
|
||||||
"sourceType": "module"
|
|
||||||
},
|
|
||||||
"plugins": [
|
|
||||||
"react",
|
|
||||||
"@typescript-eslint",
|
|
||||||
"import",
|
|
||||||
"sort-keys-fix",
|
|
||||||
"promise"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"react-hooks/exhaustive-deps": [
|
|
||||||
"warn",
|
|
||||||
{ "enableDangerousAutofixThisMayCauseInfiniteLoops": true }
|
|
||||||
],
|
|
||||||
"react/jsx-sort-props": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"callbacksLast": true,
|
|
||||||
"ignoreCase": false,
|
|
||||||
"noSortAlphabetically": false,
|
|
||||||
"reservedFirst": true,
|
|
||||||
"shorthandFirst": true,
|
|
||||||
"shorthandLast": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"import/order": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"groups": ["builtin", "external", "internal", ["parent", "sibling"]],
|
|
||||||
"pathGroups": [
|
|
||||||
{
|
|
||||||
"pattern": "react",
|
|
||||||
"group": "external",
|
|
||||||
"position": "before"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"pathGroupsExcludedImportTypes": ["react"],
|
|
||||||
"newlines-between": "never",
|
|
||||||
"alphabetize": {
|
|
||||||
"order": "asc",
|
|
||||||
"caseInsensitive": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"sort-keys-fix/sort-keys-fix": "warn",
|
|
||||||
"@typescript-eslint/no-explicit-any": "off",
|
|
||||||
"consistent-return": "off",
|
|
||||||
"object-curly-newline": "off",
|
|
||||||
"indent": "off",
|
|
||||||
"no-tabs": "off",
|
|
||||||
"react/jsx-indent": "off",
|
|
||||||
"react/jsx-indent-props": "off",
|
|
||||||
"react/react-in-jsx-scope": "off"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
* text eol=lf
|
||||||
|
*.exe binary
|
||||||
|
*.png binary
|
||||||
|
*.jpg binary
|
||||||
|
*.jpeg binary
|
||||||
|
*.ico binary
|
||||||
|
*.icns binary
|
||||||
|
*.eot binary
|
||||||
|
*.otf binary
|
||||||
|
*.ttf binary
|
||||||
|
*.woff binary
|
||||||
|
*.woff2 binary
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
ko_fi: jeffvli
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: You're having technical issues. 🐞
|
||||||
|
labels: 'bug'
|
||||||
|
---
|
||||||
|
|
||||||
|
## Expected Behavior
|
||||||
|
|
||||||
|
<!--- What should have happened? -->
|
||||||
|
|
||||||
|
## Current Behavior
|
||||||
|
|
||||||
|
<!--- What went wrong? -->
|
||||||
|
<!-- Add screenshots to help explain your problem -->
|
||||||
|
<!-- (Open the browser dev tools in the menu or using CTRL + SHIFT + I) -->
|
||||||
|
|
||||||
|
## Steps to Reproduce
|
||||||
|
|
||||||
|
<!-- Add relevant code and/or a live example -->
|
||||||
|
<!-- Add stack traces -->
|
||||||
|
|
||||||
|
1.
|
||||||
|
|
||||||
|
2.
|
||||||
|
|
||||||
|
3.
|
||||||
|
|
||||||
|
4.
|
||||||
|
|
||||||
|
## Possible Solution (Not obligatory)
|
||||||
|
|
||||||
|
<!--- Suggest a reason for the bug or how to fix it. -->
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
<!--- How has this issue affected you? What are you trying to accomplish? -->
|
||||||
|
|
||||||
|
## Your Environment
|
||||||
|
|
||||||
|
<!--- Include as many relevant details about the environment you experienced the bug in -->
|
||||||
|
|
||||||
|
- Application version (e.g. v0.1.0) :
|
||||||
|
- Operating System and version (e.g. Windows 10) :
|
||||||
|
- Server and version (e.g. Navidrome v0.48.0) :
|
||||||
|
- Node version (if developing locally) :
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
name: Question
|
||||||
|
about: Ask a question.❓
|
||||||
|
labels: 'question'
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- Question issues will be closed. -->
|
||||||
|
<!-- Ask questions in the discussions tab: Please use discussions https://github.com/jeffvli/feishin/discussions -->
|
||||||
|
<!-- Or join the Discord/Matrix servers: https://discord.gg/FVKpcMDy5f https://matrix.to/#/#sonixd:matrix.org -->
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Request a feature to be added to Feishin 🎉
|
||||||
|
labels: 'enhancement'
|
||||||
|
---
|
||||||
|
|
||||||
|
## What do you want to be added?
|
||||||
|
|
||||||
|
## Additional context
|
||||||
|
|
||||||
|
<!-- Is this a server-specific feature? (e.g. Jellyfin only). -->
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
requiredHeaders:
|
||||||
|
- Prerequisites
|
||||||
|
- Expected Behavior
|
||||||
|
- Current Behavior
|
||||||
|
- Possible Solution
|
||||||
|
- Your Environment
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Number of days of inactivity before an issue becomes stale
|
||||||
|
daysUntilStale: 60
|
||||||
|
# Number of days of inactivity before a stale issue is closed
|
||||||
|
daysUntilClose: 7
|
||||||
|
# Issues with these labels will never be considered stale
|
||||||
|
exemptLabels:
|
||||||
|
- discussion
|
||||||
|
- security
|
||||||
|
# Label to use when marking an issue as stale
|
||||||
|
staleLabel: wontfix
|
||||||
|
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||||
|
markComment: >
|
||||||
|
This issue has been automatically marked as stale because it has not had
|
||||||
|
recent activity. It will be closed if no further activity occurs. Thank you
|
||||||
|
for your contributions.
|
||||||
|
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||||
|
closeComment: false
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
name: Publish Linux (Manual)
|
||||||
|
|
||||||
|
on: workflow_dispatch
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout git repo
|
||||||
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
|
- name: Install Node and NPM
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: 16
|
||||||
|
cache: npm
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
npm install --legacy-peer-deps
|
||||||
|
|
||||||
|
- name: Publish releases
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
uses: nick-invision/retry@v2.8.2
|
||||||
|
with:
|
||||||
|
timeout_minutes: 30
|
||||||
|
max_attempts: 3
|
||||||
|
retry_on: error
|
||||||
|
command: |
|
||||||
|
npm run postinstall
|
||||||
|
npm run build
|
||||||
|
npm exec electron-builder -- --publish always --linux
|
||||||
|
on_retry_command: npm cache clean --force
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
name: Publish Windows and macOS (Manual)
|
||||||
|
|
||||||
|
on: workflow_dispatch
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [macos-latest]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout git repo
|
||||||
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
|
- name: Install Node and NPM
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: 16
|
||||||
|
cache: npm
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
npm install --legacy-peer-deps
|
||||||
|
|
||||||
|
- name: Publish releases
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
uses: nick-invision/retry@v2.8.2
|
||||||
|
with:
|
||||||
|
timeout_minutes: 30
|
||||||
|
max_attempts: 3
|
||||||
|
retry_on: error
|
||||||
|
command: |
|
||||||
|
npm run postinstall
|
||||||
|
npm run build
|
||||||
|
npm exec electron-builder -- --publish always --win --mac
|
||||||
|
on_retry_command: npm cache clean --force
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
name: Comment on pull request
|
||||||
|
on:
|
||||||
|
workflow_run:
|
||||||
|
workflows: ['Publish (PR)']
|
||||||
|
types: [completed]
|
||||||
|
jobs:
|
||||||
|
pr_comment:
|
||||||
|
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/github-script@v6
|
||||||
|
with:
|
||||||
|
# This snippet is public-domain, taken from
|
||||||
|
# https://github.com/oprypin/nightly.link/blob/master/.github/workflows/pr-comment.yml
|
||||||
|
script: |
|
||||||
|
async function upsertComment(owner, repo, issue_number, purpose, body) {
|
||||||
|
const {data: comments} = await github.rest.issues.listComments(
|
||||||
|
{owner, repo, issue_number});
|
||||||
|
const marker = `<!-- bot: ${purpose} -->`;
|
||||||
|
body = marker + "\n" + body;
|
||||||
|
const existing = comments.filter((c) => c.body.includes(marker));
|
||||||
|
if (existing.length > 0) {
|
||||||
|
const last = existing[existing.length - 1];
|
||||||
|
core.info(`Updating comment ${last.id}`);
|
||||||
|
await github.rest.issues.updateComment({
|
||||||
|
owner, repo,
|
||||||
|
body,
|
||||||
|
comment_id: last.id,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
core.info(`Creating a comment in issue / PR #${issue_number}`);
|
||||||
|
await github.rest.issues.createComment({issue_number, body, owner, repo});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const {owner, repo} = context.repo;
|
||||||
|
const run_id = ${{github.event.workflow_run.id}};
|
||||||
|
const pull_requests = ${{ toJSON(github.event.workflow_run.pull_requests) }};
|
||||||
|
if (!pull_requests.length) {
|
||||||
|
return core.error("This workflow doesn't match any pull requests!");
|
||||||
|
}
|
||||||
|
const artifacts = await github.paginate(
|
||||||
|
github.rest.actions.listWorkflowRunArtifacts, {owner, repo, run_id});
|
||||||
|
if (!artifacts.length) {
|
||||||
|
return core.error(`No artifacts found`);
|
||||||
|
}
|
||||||
|
let body = `Download the artifacts for this pull request:\n`;
|
||||||
|
for (const art of artifacts) {
|
||||||
|
body += `\n* [${art.name}.zip](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
||||||
|
}
|
||||||
|
core.info("Review thread message body:", body);
|
||||||
|
for (const pr of pull_requests) {
|
||||||
|
await upsertComment(owner, repo, pr.number,
|
||||||
|
"nightly-link", body);
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
name: Publish (PR)
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- development
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [macos-latest]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout git repo
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install Node and NPM
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 16
|
||||||
|
cache: npm
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
npm install --legacy-peer-deps
|
||||||
|
|
||||||
|
- name: Build releases
|
||||||
|
uses: nick-invision/retry@v2.8.2
|
||||||
|
with:
|
||||||
|
timeout_minutes: 30
|
||||||
|
max_attempts: 3
|
||||||
|
retry_on: error
|
||||||
|
command: |
|
||||||
|
npm run postinstall
|
||||||
|
npm run build
|
||||||
|
npm run package:pr
|
||||||
|
on_retry_command: npm cache clean --force
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: windows-binaries
|
||||||
|
path: |
|
||||||
|
release/build/*.exe
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: linux-binaries
|
||||||
|
path: |
|
||||||
|
release/build/*.AppImage
|
||||||
|
release/build/*.deb
|
||||||
|
release/build/*.rpm
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: macos-binaries
|
||||||
|
path: |
|
||||||
|
release/build/*.dmg
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
name: Test
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Check out Git repository
|
||||||
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
|
- name: Install Node.js and NPM
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: 16
|
||||||
|
cache: npm
|
||||||
|
|
||||||
|
- name: npm install
|
||||||
|
run: |
|
||||||
|
npm install --legacy-peer-deps
|
||||||
|
|
||||||
|
- name: npm test
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
npm run package
|
||||||
|
npm run lint
|
||||||
|
npm exec tsc
|
||||||
|
npm test
|
||||||
@@ -1,29 +1,31 @@
|
|||||||
# Logs
|
# Logs
|
||||||
logs
|
logs
|
||||||
*.log
|
*.log
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
pnpm-debug.log*
|
|
||||||
lerna-debug.log*
|
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Dependency directory
|
||||||
|
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
|
||||||
node_modules
|
node_modules
|
||||||
dist
|
|
||||||
dist-ssr
|
|
||||||
*.local
|
|
||||||
|
|
||||||
# Editor directories and files
|
# OSX
|
||||||
.idea
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.suo
|
|
||||||
*.ntvs*
|
|
||||||
*.njsproj
|
|
||||||
*.sln
|
|
||||||
*.sw?
|
|
||||||
|
|
||||||
release/app/dist
|
release/app/dist
|
||||||
release/build
|
release/build
|
||||||
.vscode/.debug.env
|
.erb/dll
|
||||||
./package-lock.json
|
|
||||||
pnpm-lock.yaml
|
.idea
|
||||||
yarn.lock
|
npm-debug.log.*
|
||||||
|
*.css.d.ts
|
||||||
|
*.sass.d.ts
|
||||||
|
*.scss.d.ts
|
||||||
|
|
||||||
|
.env*
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
npx lint-staged
|
||||||
@@ -1,12 +1,20 @@
|
|||||||
{
|
{
|
||||||
"printWidth": 120,
|
"printWidth": 100,
|
||||||
"tabWidth": 2,
|
|
||||||
"useTabs": false,
|
|
||||||
"semi": true,
|
"semi": true,
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"trailingComma": "es5",
|
"overrides": [
|
||||||
"bracketSpacing": true,
|
{
|
||||||
"jsxBracketSameLine": false,
|
"files": ["**/*.css", "**/*.scss", "**/*.html"],
|
||||||
"arrowParens": "always",
|
"options": {
|
||||||
"proseWrap": "preserve"
|
"singleQuote": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"trailingComma": "all",
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"arrowParens": "always",
|
||||||
|
"proseWrap": "never",
|
||||||
|
"htmlWhitespaceSensitivity": "strict",
|
||||||
|
"endOfLine": "lf",
|
||||||
|
"singleAttributePerLine": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"processors": ["stylelint-processor-styled-components"],
|
||||||
|
"customSyntax": "postcss-scss",
|
||||||
|
"extends": [
|
||||||
|
"stylelint-config-standard-scss",
|
||||||
|
"stylelint-config-styled-components",
|
||||||
|
"stylelint-config-rational-order"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"color-function-notation": ["legacy"],
|
||||||
|
"declaration-empty-line-before": null,
|
||||||
|
"order/properties-order": [],
|
||||||
|
"plugin/rational-order": [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
"border-in-box-model": false,
|
||||||
|
"empty-line-between-groups": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"string-quotes": "single",
|
||||||
|
"declaration-block-no-redundant-longhand-properties": null,
|
||||||
|
"selector-class-pattern": null,
|
||||||
|
"selector-type-case": ["lower", { "ignoreTypes": ["/^\\$\\w+/"] }],
|
||||||
|
"selector-type-no-unknown": [
|
||||||
|
true,
|
||||||
|
{ "ignoreTypes": ["/-styled-mixin/", "/^\\$\\w+/"] }
|
||||||
|
],
|
||||||
|
"value-keyword-case": ["lower", { "ignoreKeywords": ["dummyValue"] }],
|
||||||
|
"declaration-colon-newline-after": null
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import fs from 'fs'
|
|
||||||
import path from 'path'
|
|
||||||
import { fileURLToPath } from 'url'
|
|
||||||
import { createRequire } from 'module'
|
|
||||||
import { spawn } from 'child_process'
|
|
||||||
|
|
||||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
||||||
const require = createRequire(import.meta.url)
|
|
||||||
const pkg = require('../package.json')
|
|
||||||
|
|
||||||
// write .debug.env
|
|
||||||
const envContent = Object.entries(pkg.debug.env).map(([key, val]) => `${key}=${val}`)
|
|
||||||
fs.writeFileSync(path.join(__dirname, '.debug.env'), envContent.join('\n'))
|
|
||||||
|
|
||||||
// bootstrap
|
|
||||||
spawn(
|
|
||||||
// TODO: terminate `npm run dev` when Debug exits.
|
|
||||||
process.platform === 'win32' ? 'npm.cmd' : 'npm',
|
|
||||||
['run', 'dev'],
|
|
||||||
{
|
|
||||||
stdio: 'inherit',
|
|
||||||
env: Object.assign(process.env, { VSCODE_DEBUG: 'true' }),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
{
|
{
|
||||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
|
||||||
// for the documentation about the extensions.json format
|
|
||||||
"recommendations": [
|
"recommendations": [
|
||||||
"editorconfig.editorconfig",
|
"dbaeumer.vscode-eslint",
|
||||||
"mrmlnc.vscode-json5",
|
"EditorConfig.EditorConfig",
|
||||||
"rbbit.typescript-hero",
|
"stylelint.vscode-stylelint",
|
||||||
"syler.sass-indented",
|
"esbenp.prettier-vscode"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +1,30 @@
|
|||||||
{
|
{
|
||||||
// Use IntelliSense to learn about possible attributes.
|
|
||||||
// Hover to view descriptions of existing attributes.
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Electron: Main",
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"protocol": "inspector",
|
||||||
|
"runtimeExecutable": "npm",
|
||||||
|
"runtimeArgs": [
|
||||||
|
"run start:main --inspect=5858 --remote-debugging-port=9223"
|
||||||
|
],
|
||||||
|
"preLaunchTask": "Start Webpack Dev"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Electron: Renderer",
|
||||||
|
"type": "chrome",
|
||||||
|
"request": "attach",
|
||||||
|
"port": 9223,
|
||||||
|
"webRoot": "${workspaceFolder}",
|
||||||
|
"timeout": 15000
|
||||||
|
}
|
||||||
|
],
|
||||||
"compounds": [
|
"compounds": [
|
||||||
{
|
{
|
||||||
"name": "Debug App",
|
"name": "Electron: All",
|
||||||
"preLaunchTask": "start .debug.script.mjs",
|
"configurations": ["Electron: Main", "Electron: Renderer"]
|
||||||
"configurations": [
|
|
||||||
"Debug Main Process",
|
|
||||||
"Debug Renderer Process"
|
|
||||||
],
|
|
||||||
"presentation": {
|
|
||||||
"hidden": false,
|
|
||||||
"group": "",
|
|
||||||
"order": 1
|
|
||||||
},
|
|
||||||
"stopAll": true
|
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"name": "Debug Main Process",
|
|
||||||
"type": "pwa-node",
|
|
||||||
"request": "launch",
|
|
||||||
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",
|
|
||||||
"windows": {
|
|
||||||
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd"
|
|
||||||
},
|
|
||||||
"runtimeArgs": [
|
|
||||||
"--no-sandbox",
|
|
||||||
"--remote-debugging-port=9229",
|
|
||||||
"."
|
|
||||||
],
|
|
||||||
"envFile": "${workspaceFolder}/.vscode/.debug.env",
|
|
||||||
"console": "integratedTerminal"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Debug Renderer Process",
|
|
||||||
"port": 9229,
|
|
||||||
"request": "attach",
|
|
||||||
"type": "pwa-chrome",
|
|
||||||
"timeout": 60000
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
".eslintrc": "jsonc",
|
||||||
|
".prettierrc": "jsonc",
|
||||||
|
".eslintignore": "ignore"
|
||||||
|
},
|
||||||
|
"eslint.validate": ["typescript"],
|
||||||
|
"eslint.workingDirectories": [
|
||||||
|
{ "directory": "./", "changeProcessCWD": true },
|
||||||
|
{ "directory": "./server", "changeProcessCWD": true }
|
||||||
|
],
|
||||||
|
"typescript.tsserver.experimental.enableProjectDiagnostics": true,
|
||||||
|
"editor.tabSize": 2,
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll.eslint": true,
|
||||||
|
"source.fixAll.stylelint": false
|
||||||
|
},
|
||||||
|
"css.validate": false,
|
||||||
|
"less.validate": false,
|
||||||
|
"scss.validate": false,
|
||||||
|
"javascript.validate.enable": false,
|
||||||
|
"javascript.format.enable": false,
|
||||||
|
"typescript.format.enable": false,
|
||||||
|
"search.exclude": {
|
||||||
|
".git": true,
|
||||||
|
".eslintcache": true,
|
||||||
|
".erb/dll": true,
|
||||||
|
"release/{build,app/dist}": true,
|
||||||
|
"node_modules": true,
|
||||||
|
"npm-debug.log.*": true,
|
||||||
|
"test/**/__snapshots__": true,
|
||||||
|
"package-lock.json": true,
|
||||||
|
"*.{css,sass,scss}.d.ts": true
|
||||||
|
},
|
||||||
|
"i18n-ally.localesPaths": ["src/i18n", "src/i18n/locales"],
|
||||||
|
"typescript.tsdk": "node_modules\\typescript\\lib",
|
||||||
|
"typescript.preferences.importModuleSpecifier": "non-relative",
|
||||||
|
"stylelint.validate": ["css", "less", "postcss", "typescript", "typescriptreact", "scss"],
|
||||||
|
"typescript.updateImportsOnFileMove.enabled": "always",
|
||||||
|
"[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
|
||||||
|
"[typescriptreact]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
|
||||||
|
"typescript.format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": true
|
||||||
|
}
|
||||||
@@ -1,34 +1,25 @@
|
|||||||
{
|
{
|
||||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
|
||||||
// for the documentation about the tasks.json format
|
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"tasks": [
|
"tasks": [
|
||||||
{
|
{
|
||||||
"label": "start .debug.script.mjs",
|
"type": "npm",
|
||||||
"type": "shell",
|
"label": "Start Webpack Dev",
|
||||||
"command": "node .vscode/.debug.script.mjs",
|
"script": "start:renderer",
|
||||||
|
"options": {
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
},
|
||||||
"isBackground": true,
|
"isBackground": true,
|
||||||
"problemMatcher": {
|
"problemMatcher": {
|
||||||
"owner": "typescript",
|
"owner": "custom",
|
||||||
"fileLocation": "relative",
|
|
||||||
"pattern": {
|
"pattern": {
|
||||||
// TODO: correct "regexp"
|
"regexp": "____________"
|
||||||
"regexp": "^([a-zA-Z]\\:\/?([\\w\\-]\/?)+\\.\\w+):(\\d+):(\\d+): (ERROR|WARNING)\\: (.*)$",
|
|
||||||
"file": 1,
|
|
||||||
"line": 3,
|
|
||||||
"column": 4,
|
|
||||||
"code": 5,
|
|
||||||
"message": 6
|
|
||||||
},
|
},
|
||||||
"background": {
|
"background": {
|
||||||
"activeOnStart": true,
|
"activeOnStart": true,
|
||||||
"endsPattern": "^.*[startup] Electron App.*$",
|
"beginsPattern": "Compiling\\.\\.\\.$",
|
||||||
|
"endsPattern": "(Compiled successfully|Failed to compile)\\.$"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://code.visualstudio.com/docs/editor/tasks#_operating-system-specific-properties
|
|
||||||
// https://code.visualstudio.com/docs/editor/tasks#_background-watching-tasks
|
|
||||||
// https://code.visualstudio.com/docs/editor/tasks#_can-a-background-task-be-used-as-a-prelaunchtask-in-launchjson
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
@@ -1,15 +1,77 @@
|
|||||||
# Sonixd (rewrite)
|
# Feishin
|
||||||
|
|
||||||
Repository for the rewrite of [Sonixd](https://github.com/jeffvli/sonixd).
|
<p align="center">
|
||||||
|
<a href="https://github.com/jeffvli/feishin/blob/main/LICENSE">
|
||||||
|
<img src="https://img.shields.io/github/license/jeffvli/feishin?style=flat-square&color=brightgreen"
|
||||||
|
alt="License">
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/jeffvli/feishin/releases">
|
||||||
|
<img src="https://img.shields.io/github/v/release/jeffvli/feishin?style=flat-square&color=blue"
|
||||||
|
alt="Release">
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/jeffvli/feishin/releases">
|
||||||
|
<img src="https://img.shields.io/github/downloads/jeffvli/feishin/total?style=flat-square&color=orange"
|
||||||
|
alt="Downloads">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://discord.gg/FVKpcMDy5f">
|
||||||
|
<img src="https://img.shields.io/discord/922656312888811530?color=black&label=discord&logo=discord&logoColor=white"
|
||||||
|
alt="Discord">
|
||||||
|
</a>
|
||||||
|
<a href="https://matrix.to/#/#sonixd:matrix.org">
|
||||||
|
<img src="https://img.shields.io/matrix/sonixd:matrix.org?color=black&label=matrix&logo=matrix&logoColor=white"
|
||||||
|
alt="Matrix">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
Rewrite of [Sonixd](https://github.com/jeffvli/sonixd).
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- [x] MPV player backend
|
||||||
|
- [x] Web player backend
|
||||||
|
- [x] Modern UI
|
||||||
|
- [x] Scrobble playback to your server
|
||||||
|
- [x] Smart playlist editor (Navidrome)
|
||||||
|
- [x] Synchronized and unsynchronized lyrics support
|
||||||
|
- [ ] [Request a feature](https://github.com/jeffvli/feishin/issues) or [view taskboard](https://github.com/users/jeffvli/projects/5/views/1)
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|
<a href="https://raw.githubusercontent.com/jeffvli/feishin/development/media/preview_full_screen_player.png"><img src="https://raw.githubusercontent.com/jeffvli/feishin/development/media/preview_full_screen_player.png" width="49.5%"/></a> <a href="https://raw.githubusercontent.com/jeffvli/feishin/development/media/preview_album_artist_detail.png"><img src="https://raw.githubusercontent.com/jeffvli/feishin/development/media/preview_album_artist_detail.png" width="49.5%"/></a> <a href="https://raw.githubusercontent.com/jeffvli/feishin/development/media/preview_album_detail.png"><img src="https://raw.githubusercontent.com/jeffvli/feishin/development/media/preview_album_detail.png" width="49.5%"/></a> <a href="https://raw.githubusercontent.com/jeffvli/feishin/development/media/preview_smart_playlist.png"><img src="https://raw.githubusercontent.com/jeffvli/feishin/development/media/preview_smart_playlist.png" width="49.5%"/></a>
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
Download the [latest desktop client](https://github.com/jeffvli/feishin/releases).
|
||||||
|
|
||||||
|
If you're using an M1 macOS device, [check here](https://github.com/jeffvli/feishin/issues/104#issuecomment-1553914730) for instructions on how to remove the app from quarantine.
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
1. Upon startup you will be greeted with a prompt to select the path to your MPV binary. If you do not have MPV installed, you can download it [here](https://mpv.io/installation/) or install it using any package manager supported by your OS. After inputting the path, restart the app.
|
||||||
|
|
||||||
|
2. After restarting the app, you will be prompted to select a server. Click the `Open menu` button and select `Manage servers`. Click the `Add server` button in the popup and fill out all applicable details. You will need to enter the full URL to your server, including the protocol and port if applicable (e.g. `https://navidrome.my-server.com` or `http://192.168.0.1:4533`).
|
||||||
|
|
||||||
|
- **Navidrome** - For the best experience, select "Save password" when creating the server and configure the `SessionTimeout` setting in your Navidrome config to a larger value (e.g. 72h).
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
### What music servers does Feishin support?
|
||||||
|
|
||||||
|
Feishin supports any music server that implements a [Navidrome](https://www.navidrome.org/) or [Jellyfin](https://jellyfin.org/) API. **Subsonic API is not currently supported**. This will likely be added in [later when the new Subsonic API is decided on](https://support.symfonium.app/t/subsonic-servers-participation/1233).
|
||||||
|
|
||||||
|
- [Navidrome](https://github.com/navidrome/navidrome)
|
||||||
|
- [Jellyfin](https://github.com/jellyfin/jellyfin)
|
||||||
|
- [Funkwhale](https://funkwhale.audio/) - TBD
|
||||||
|
- Subsonic-compatible servers - TBD
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
TBD
|
Built and tested using Node `v16.15.0`.
|
||||||
|
|
||||||
### Developing with Docker Compose
|
This project is built off of [electron-react-boilerplate](https://github.com/electron-react-boilerplate/electron-react-boilerplate) v4.6.0.
|
||||||
|
|
||||||
TBD
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
[GNU General Public License v3.0 ©](https://github.com/jeffvli/sonixd-rewrite/blob/dev/LICENSE)
|
[GNU General Public License v3.0 ©](https://github.com/jeffvli/feishin/blob/dev/LICENSE)
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
type Styles = Record<string, string>;
|
||||||
|
|
||||||
|
declare module '*.svg' {
|
||||||
|
const content: string;
|
||||||
|
export default content;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '*.png' {
|
||||||
|
const content: string;
|
||||||
|
export default content;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '*.jpg' {
|
||||||
|
const content: string;
|
||||||
|
export default content;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '*.scss' {
|
||||||
|
const content: Styles;
|
||||||
|
export default content;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '*.sass' {
|
||||||
|
const content: Styles;
|
||||||
|
export default content;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '*.css' {
|
||||||
|
const content: Styles;
|
||||||
|
export default content;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.cs.allow-jit</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 139 KiB |
|
After Width: | Height: | Size: 126 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 896 B |
|
After Width: | Height: | Size: 971 B |
|
After Width: | Height: | Size: 479 B |
|
After Width: | Height: | Size: 524 B |
@@ -1,59 +0,0 @@
|
|||||||
{
|
|
||||||
"appId": "TEST",
|
|
||||||
"productName": "TEST",
|
|
||||||
"copyright": "Copyright © 2022 ${author}",
|
|
||||||
"directories": {
|
|
||||||
"app": "release/app",
|
|
||||||
"output": "release/build",
|
|
||||||
"buildResources": "electron/resources"
|
|
||||||
},
|
|
||||||
"extends": null,
|
|
||||||
"asar": true,
|
|
||||||
"asarUnpack": ["**\\*.{node,dll}", "prisma"],
|
|
||||||
"files": [
|
|
||||||
"dist",
|
|
||||||
"node_modules",
|
|
||||||
"package.json",
|
|
||||||
"prisma/**/*",
|
|
||||||
"resources/**/*",
|
|
||||||
"!**/node_modules/@prisma/engines/introspection-engine*",
|
|
||||||
"!**/node_modules/@prisma/engines/migration-engine*",
|
|
||||||
"!**/node_modules/@prisma/engines/prisma-fmt*",
|
|
||||||
"!**/node_modules/@prisma/engines/query_engine-*",
|
|
||||||
"!**/node_modules/@prisma/engines/libquery_engine*",
|
|
||||||
"!**/node_modules/prisma/query_engine*",
|
|
||||||
"!**/node_modules/prisma/libquery_engine*",
|
|
||||||
"!**/node_modules/prisma/**/*.mjs"
|
|
||||||
],
|
|
||||||
"win": {
|
|
||||||
"target": [
|
|
||||||
{
|
|
||||||
"target": "nsis",
|
|
||||||
"arch": ["x64"]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"artifactName": "${productName}-Windows-${version}-Setup.${ext}"
|
|
||||||
},
|
|
||||||
"nsis": {
|
|
||||||
"oneClick": false,
|
|
||||||
"perMachine": false,
|
|
||||||
"allowToChangeInstallationDirectory": true,
|
|
||||||
"deleteAppDataOnUninstall": false
|
|
||||||
},
|
|
||||||
"mac": {
|
|
||||||
"target": ["dmg"],
|
|
||||||
"artifactName": "${productName}-Mac-${version}-Installer.${ext}"
|
|
||||||
},
|
|
||||||
"linux": {
|
|
||||||
"icon": "electron/resources/iconset",
|
|
||||||
"target": ["AppImage", "deb"],
|
|
||||||
"artifactName": "${productName}-Linux-${version}.${ext}"
|
|
||||||
},
|
|
||||||
"extraResources": [
|
|
||||||
"./assets/**",
|
|
||||||
"prisma/**/*",
|
|
||||||
"node_modules/@prisma/engines/migration-engine*",
|
|
||||||
"node_modules/@prisma/engines/query*",
|
|
||||||
"node_modules/@prisma/engines/libquery*"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
/// <reference types="vite-electron-plugin/electron-env" />
|
|
||||||
|
|
||||||
declare namespace NodeJS {
|
|
||||||
interface ProcessEnv {
|
|
||||||
DIST: string;
|
|
||||||
DIST_ELECTRON: string;
|
|
||||||
/** /dist/ or /public/ */
|
|
||||||
PUBLIC: string;
|
|
||||||
VSCODE_DEBUG?: 'true';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
import fs from 'fs';
|
|
||||||
import path from 'path';
|
|
||||||
import { PrismaClient } from '@prisma/client';
|
|
||||||
import { app, ipcMain } from 'electron';
|
|
||||||
import isDev from 'electron-is-dev';
|
|
||||||
import './server';
|
|
||||||
|
|
||||||
const dbPath = isDev
|
|
||||||
? path.join(__dirname, '../../../../prisma/dev.db')
|
|
||||||
: path.join(app.getPath('userData'), 'database.db');
|
|
||||||
|
|
||||||
if (!isDev) {
|
|
||||||
try {
|
|
||||||
// database file does not exist, need to create
|
|
||||||
fs.copyFileSync(path.join(process.resourcesPath, 'prisma/dev.db'), dbPath, fs.constants.COPYFILE_EXCL);
|
|
||||||
console.log(`DB does not exist. Create new DB from ${path.join(process.resourcesPath, 'prisma/dev.db')}`);
|
|
||||||
} catch (err) {
|
|
||||||
if (err && 'code' in (err as { code: string }) && (err as { code: string }).code !== 'EEXIST') {
|
|
||||||
console.error(`DB creation faild. Reason:`, err);
|
|
||||||
} else {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPlatformName(): string {
|
|
||||||
const isDarwin = process.platform === 'darwin';
|
|
||||||
if (isDarwin && process.arch === 'arm64') {
|
|
||||||
return `${process.platform}Arm64`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return process.platform;
|
|
||||||
}
|
|
||||||
|
|
||||||
const platformToExecutables: Record<string, any> = {
|
|
||||||
darwin: {
|
|
||||||
migrationEngine: 'node_modules/@prisma/engines/migration-engine-darwin',
|
|
||||||
queryEngine: 'node_modules/@prisma/engines/libquery_engine-darwin.dylib.node',
|
|
||||||
},
|
|
||||||
darwinArm64: {
|
|
||||||
migrationEngine: 'node_modules/@prisma/engines/migration-engine-darwin-arm64',
|
|
||||||
queryEngine: 'node_modules/@prisma/engines/libquery_engine-darwin-arm64.dylib.node',
|
|
||||||
},
|
|
||||||
linux: {
|
|
||||||
migrationEngine: 'node_modules/@prisma/engines/migration-engine-debian-openssl-1.1.x',
|
|
||||||
queryEngine: 'node_modules/@prisma/engines/libquery_engine-debian-openssl-1.1.x.so.node',
|
|
||||||
},
|
|
||||||
win32: {
|
|
||||||
migrationEngine: 'node_modules/@prisma/engines/migration-engine-windows.exe',
|
|
||||||
queryEngine: 'node_modules/@prisma/engines/query_engine-windows.dll.node',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const extraResourcesPath = app.getAppPath().replace('app.asar', ''); // impacted by extraResources setting in electron-builder.yml
|
|
||||||
const platformName = getPlatformName();
|
|
||||||
|
|
||||||
const mePath = path.join(extraResourcesPath, platformToExecutables[platformName].migrationEngine);
|
|
||||||
const qePath = path.join(extraResourcesPath, platformToExecutables[platformName].queryEngine);
|
|
||||||
|
|
||||||
ipcMain.on('config:get-app-path', (event) => {
|
|
||||||
event.returnValue = app.getAppPath();
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on('config:get-platform-name', (event) => {
|
|
||||||
const isDarwin = process.platform === 'darwin';
|
|
||||||
event.returnValue =
|
|
||||||
isDarwin && process.arch === 'arm64' ? `${process.platform}Arm64` : (event.returnValue = process.platform);
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on('config:get-prisma-db-path', (event) => {
|
|
||||||
event.returnValue = dbPath;
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on('config:get-prisma-me-path', (event) => {
|
|
||||||
event.returnValue = mePath;
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on('config:get-prisma-qe-path', (event) => {
|
|
||||||
event.returnValue = qePath;
|
|
||||||
});
|
|
||||||
|
|
||||||
export const prisma = new PrismaClient({
|
|
||||||
datasources: {
|
|
||||||
db: {
|
|
||||||
url: `file:${dbPath}`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
errorFormat: 'minimal',
|
|
||||||
// see https://github.com/prisma/prisma/discussions/5200
|
|
||||||
// __internal: {
|
|
||||||
// engine: {
|
|
||||||
// binaryPath: qePath,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
});
|
|
||||||
|
|
||||||
prisma.server.findMany({
|
|
||||||
where: {},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const exclude = <T, Key extends keyof T>(resultSet: T, ...keys: Key[]): Omit<T, Key> => {
|
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
|
||||||
for (const key of keys) {
|
|
||||||
delete resultSet[key];
|
|
||||||
}
|
|
||||||
return resultSet;
|
|
||||||
};
|
|
||||||
|
|
||||||
function sleep(ms: number) {
|
|
||||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
||||||
}
|
|
||||||
|
|
||||||
prisma.$use(async (params, next) => {
|
|
||||||
const maxRetries = 5;
|
|
||||||
let retries = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
try {
|
|
||||||
const result = await next(params);
|
|
||||||
return result;
|
|
||||||
} catch (err) {
|
|
||||||
retries += 1;
|
|
||||||
return sleep(500);
|
|
||||||
}
|
|
||||||
} while (retries < maxRetries);
|
|
||||||
});
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import { ipcMain } from 'electron';
|
|
||||||
import { prisma } from '..';
|
|
||||||
|
|
||||||
export enum ServerApi {
|
|
||||||
GET_SERVER = 'api:server:get-server',
|
|
||||||
GET_SERVERS = 'api:server:get-servers',
|
|
||||||
}
|
|
||||||
|
|
||||||
ipcMain.handle(ServerApi.GET_SERVERS, async () => {
|
|
||||||
const result = await prisma.server.findMany();
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
import './mpv-player';
|
|
||||||
import './api';
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
import { ipcMain } from 'electron';
|
|
||||||
import MpvAPI from 'node-mpv';
|
|
||||||
import { getWindow } from '../../..';
|
|
||||||
|
|
||||||
const mpv = new MpvAPI(
|
|
||||||
{
|
|
||||||
audio_only: true,
|
|
||||||
auto_restart: true,
|
|
||||||
binary: 'C:/ProgramData/chocolatey/lib/mpv.install/tools/mpv.exe',
|
|
||||||
time_update: 1,
|
|
||||||
},
|
|
||||||
['--gapless-audio=yes', '--prefetch-playlist']
|
|
||||||
);
|
|
||||||
|
|
||||||
mpv.start().catch((error: any) => {
|
|
||||||
console.log('error', error);
|
|
||||||
});
|
|
||||||
|
|
||||||
mpv.on('status', (status: any) => {
|
|
||||||
if (status.property === 'playlist-pos') {
|
|
||||||
if (status.value !== 0) {
|
|
||||||
getWindow()?.webContents.send('renderer-player-auto-next');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Automatically updates the play button when the player is playing
|
|
||||||
mpv.on('started', () => {
|
|
||||||
getWindow()?.webContents.send('renderer-player-play');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Automatically updates the play button when the player is stopped
|
|
||||||
mpv.on('stopped', () => {
|
|
||||||
getWindow()?.webContents.send('renderer-player-stop');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Automatically updates the play button when the player is paused
|
|
||||||
mpv.on('paused', () => {
|
|
||||||
getWindow()?.webContents.send('renderer-player-pause');
|
|
||||||
});
|
|
||||||
|
|
||||||
mpv.on('quit', () => {
|
|
||||||
console.log('mpv quit');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Event output every interval set by time_update, used to update the current time
|
|
||||||
mpv.on('timeposition', (time: number) => {
|
|
||||||
getWindow()?.webContents.send('renderer-player-current-time', time);
|
|
||||||
});
|
|
||||||
|
|
||||||
mpv.on('seek', () => {
|
|
||||||
console.log('mpv seek');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Starts the player
|
|
||||||
ipcMain.on('player-play', async () => {
|
|
||||||
await mpv.play();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Pauses the player
|
|
||||||
ipcMain.on('player-pause', async () => {
|
|
||||||
await mpv.pause();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Stops the player
|
|
||||||
ipcMain.on('player-stop', async () => {
|
|
||||||
await mpv.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Stops the player
|
|
||||||
ipcMain.on('player-next', async () => {
|
|
||||||
await mpv.next();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Stops the player
|
|
||||||
ipcMain.on('player-previous', async () => {
|
|
||||||
await mpv.prev();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Seeks forward or backward by the given amount of seconds
|
|
||||||
ipcMain.on('player-seek', async (_event, time: number) => {
|
|
||||||
await mpv.seek(time);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Seeks to the given time in seconds
|
|
||||||
ipcMain.on('player-seek-to', async (_event, time: number) => {
|
|
||||||
await mpv.goToPosition(time);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Sets the queue in position 0 and 1 to the given data. Used when manually starting a song or using the next/prev buttons
|
|
||||||
ipcMain.on('player-set-queue', async (_event, data: any) => {
|
|
||||||
if (data.queue.current) {
|
|
||||||
await mpv.load(data.queue.current.streamUrl, 'replace');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.queue.next) {
|
|
||||||
await mpv.load(data.queue.next.streamUrl, 'append');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Replaces the queue in position 1 to the given data
|
|
||||||
ipcMain.on('player-set-queue-next', async (_event, data: any) => {
|
|
||||||
const size = await mpv.getPlaylistSize();
|
|
||||||
|
|
||||||
if (size > 1) {
|
|
||||||
await mpv.playlistRemove(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.queue.next) {
|
|
||||||
await mpv.load(data.queue.next.streamUrl, 'append');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Sets the next song in the queue when reaching the end of the queue
|
|
||||||
ipcMain.on('player-auto-next', async (_event, data: any) => {
|
|
||||||
// Always keep the current song as position 0 in the mpv queue
|
|
||||||
// This allows us to easily set update the next song in the queue without
|
|
||||||
// disturbing the currently playing song
|
|
||||||
await mpv.playlistRemove(0);
|
|
||||||
|
|
||||||
if (data.queue.next) {
|
|
||||||
await mpv.load(data.queue.next.streamUrl, 'append');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Sets the volume to the given value (0-100)
|
|
||||||
ipcMain.on('player-volume', async (_event, value: number) => {
|
|
||||||
mpv.volume(value);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Toggles the mute status
|
|
||||||
ipcMain.on('player-mute', async () => {
|
|
||||||
mpv.mute();
|
|
||||||
});
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
import './core';
|
|
||||||
|
|
||||||
require(`./${process.platform}`);
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
// The built directory structure
|
|
||||||
//
|
|
||||||
// ├─┬ dist-electron
|
|
||||||
// │ ├─┬ main
|
|
||||||
// │ │ └── index.js > Electron-Main
|
|
||||||
// │ └─┬ preload
|
|
||||||
// │ └── index.js > Preload-Scripts
|
|
||||||
// ├─┬ dist
|
|
||||||
// │ └── index.html > Electron-Renderer
|
|
||||||
//
|
|
||||||
process.env.DIST_ELECTRON = join(__dirname, '..');
|
|
||||||
process.env.DIST = join(process.env.DIST_ELECTRON, '../dist');
|
|
||||||
process.env.PUBLIC = app.isPackaged ? process.env.DIST : join(process.env.DIST_ELECTRON, '../public');
|
|
||||||
|
|
||||||
import { release } from 'os';
|
|
||||||
import { join } from 'path';
|
|
||||||
import { app, BrowserWindow, shell, ipcMain } from 'electron';
|
|
||||||
import './features';
|
|
||||||
|
|
||||||
// Disable GPU Acceleration for Windows 7
|
|
||||||
if (release().startsWith('6.1')) app.disableHardwareAcceleration();
|
|
||||||
|
|
||||||
// Set application name for Windows 10+ notifications
|
|
||||||
if (process.platform === 'win32') app.setAppUserModelId(app.getName());
|
|
||||||
|
|
||||||
if (!app.requestSingleInstanceLock()) {
|
|
||||||
app.quit();
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
let win: BrowserWindow | null = null;
|
|
||||||
// Here, you can also use other preload
|
|
||||||
const preload = join(__dirname, '../preload/index.js');
|
|
||||||
const url = process.env.VITE_DEV_SERVER_URL as string;
|
|
||||||
const indexHtml = join(process.env.DIST, 'index.html');
|
|
||||||
|
|
||||||
async function createWindow() {
|
|
||||||
win = new BrowserWindow({
|
|
||||||
icon: join(process.env.PUBLIC as string, 'favicon.svg'),
|
|
||||||
title: 'Main window',
|
|
||||||
webPreferences: {
|
|
||||||
contextIsolation: true,
|
|
||||||
nodeIntegration: false,
|
|
||||||
preload,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (app.isPackaged) {
|
|
||||||
win.loadFile(indexHtml);
|
|
||||||
} else {
|
|
||||||
win.loadURL(url);
|
|
||||||
// win.webContents.openDevTools()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test actively push message to the Electron-Renderer
|
|
||||||
win.webContents.on('did-finish-load', () => {
|
|
||||||
win?.webContents.send('main-process-message', new Date().toLocaleString());
|
|
||||||
});
|
|
||||||
|
|
||||||
// Make all links open with the browser, not with the application
|
|
||||||
win.webContents.setWindowOpenHandler(({ url }) => {
|
|
||||||
if (url.startsWith('https:')) shell.openExternal(url);
|
|
||||||
return { action: 'deny' };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
app.whenReady().then(createWindow);
|
|
||||||
|
|
||||||
app.on('window-all-closed', () => {
|
|
||||||
win = null;
|
|
||||||
if (process.platform !== 'darwin') app.quit();
|
|
||||||
});
|
|
||||||
|
|
||||||
app.on('second-instance', () => {
|
|
||||||
if (win) {
|
|
||||||
// Focus on the main window if the user tried to open another
|
|
||||||
if (win.isMinimized()) win.restore();
|
|
||||||
win.focus();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.on('activate', () => {
|
|
||||||
const allWindows = BrowserWindow.getAllWindows();
|
|
||||||
if (allWindows.length) {
|
|
||||||
allWindows[0].focus();
|
|
||||||
} else {
|
|
||||||
createWindow();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// new window example arg: new windows url
|
|
||||||
ipcMain.handle('open-win', (event, arg) => {
|
|
||||||
const childWindow = new BrowserWindow({
|
|
||||||
webPreferences: {
|
|
||||||
preload,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (app.isPackaged) {
|
|
||||||
childWindow.loadFile(indexHtml, { hash: arg });
|
|
||||||
} else {
|
|
||||||
childWindow.loadURL(`${url}/#${arg}`);
|
|
||||||
// childWindow.webContents.openDevTools({ mode: "undocked", activate: true })
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const getWindow = () => {
|
|
||||||
return win;
|
|
||||||
};
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
import { contextBridge, ipcRenderer } from 'electron';
|
|
||||||
|
|
||||||
function domReady(condition: DocumentReadyState[] = ['complete', 'interactive']) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
if (condition.includes(document.readyState)) {
|
|
||||||
resolve(true);
|
|
||||||
} else {
|
|
||||||
document.addEventListener('readystatechange', () => {
|
|
||||||
if (condition.includes(document.readyState)) {
|
|
||||||
resolve(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const safeDOM = {
|
|
||||||
append(parent: HTMLElement, child: HTMLElement) {
|
|
||||||
if (!Array.from(parent.children).find((e) => e === child)) {
|
|
||||||
return parent.appendChild(child);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
remove(parent: HTMLElement, child: HTMLElement) {
|
|
||||||
if (Array.from(parent.children).find((e) => e === child)) {
|
|
||||||
return parent.removeChild(child);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://tobiasahlin.com/spinkit
|
|
||||||
* https://connoratherton.com/loaders
|
|
||||||
* https://projects.lukehaas.me/css-loaders
|
|
||||||
* https://matejkustec.github.io/SpinThatShit
|
|
||||||
*/
|
|
||||||
function useLoading() {
|
|
||||||
const className = `loaders-css__square-spin`;
|
|
||||||
const styleContent = `
|
|
||||||
@keyframes square-spin {
|
|
||||||
25% { transform: perspective(100px) rotateX(180deg) rotateY(0); }
|
|
||||||
50% { transform: perspective(100px) rotateX(180deg) rotateY(180deg); }
|
|
||||||
75% { transform: perspective(100px) rotateX(0) rotateY(180deg); }
|
|
||||||
100% { transform: perspective(100px) rotateX(0) rotateY(0); }
|
|
||||||
}
|
|
||||||
.${className} > div {
|
|
||||||
animation-fill-mode: both;
|
|
||||||
width: 50px;
|
|
||||||
height: 50px;
|
|
||||||
background: #fff;
|
|
||||||
animation: square-spin 3s 0s cubic-bezier(0.09, 0.57, 0.49, 0.9) infinite;
|
|
||||||
}
|
|
||||||
.app-loading-wrap {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100vw;
|
|
||||||
height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
background: #282c34;
|
|
||||||
z-index: 9;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
const oStyle = document.createElement('style');
|
|
||||||
const oDiv = document.createElement('div');
|
|
||||||
|
|
||||||
oStyle.id = 'app-loading-style';
|
|
||||||
oStyle.innerHTML = styleContent;
|
|
||||||
oDiv.className = 'app-loading-wrap';
|
|
||||||
oDiv.innerHTML = `<div class="${className}"><div></div></div>`;
|
|
||||||
|
|
||||||
return {
|
|
||||||
appendLoading() {
|
|
||||||
safeDOM.append(document.head, oStyle);
|
|
||||||
safeDOM.append(document.body, oDiv);
|
|
||||||
},
|
|
||||||
removeLoading() {
|
|
||||||
safeDOM.remove(document.head, oStyle);
|
|
||||||
safeDOM.remove(document.body, oDiv);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
|
||||||
|
|
||||||
const { appendLoading, removeLoading } = useLoading();
|
|
||||||
domReady().then(appendLoading);
|
|
||||||
|
|
||||||
window.onmessage = (ev) => {
|
|
||||||
ev.data.payload === 'removeLoading' && removeLoading();
|
|
||||||
};
|
|
||||||
|
|
||||||
setTimeout(removeLoading, 4999);
|
|
||||||
|
|
||||||
const serverApi = {
|
|
||||||
getServer: () => ipcRenderer.invoke('api:server:get-server'), // ServerApi.GET_SERVER
|
|
||||||
getServers: () => ipcRenderer.invoke('api:server:get-servers'), // ServerApi.GET_SERVERS
|
|
||||||
};
|
|
||||||
|
|
||||||
const api = {
|
|
||||||
prisma: {
|
|
||||||
server: serverApi,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('electron', api);
|
|
||||||
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 36 KiB |
@@ -1,14 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<link rel="icon" type="image/svg+xml" href="/src/assets/favicon.svg" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
|
||||||
<title>Vite App</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="root"></div>
|
|
||||||
<script type="module" src="/src/main.tsx"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
After Width: | Height: | Size: 644 KiB |
|
After Width: | Height: | Size: 186 KiB |
|
After Width: | Height: | Size: 465 KiB |
|
After Width: | Height: | Size: 887 KiB |
|
After Width: | Height: | Size: 396 KiB |
@@ -1,86 +1,320 @@
|
|||||||
{
|
{
|
||||||
"name": "sonixd-rewrite",
|
"name": "feishin",
|
||||||
"productName": "sonixd-rewrite",
|
"productName": "Feishin",
|
||||||
"private": true,
|
"description": "Feishin music server",
|
||||||
"version": "0.0.0",
|
"version": "0.2.0",
|
||||||
"description": "",
|
|
||||||
"author": "jeffvli",
|
|
||||||
"license": "GPL-3.0",
|
|
||||||
"main": "release/app/dist/main/index.js",
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"build": "concurrently \"npm run build:main\" \"npm run build:renderer\"",
|
||||||
"build": "tsc && vite build && electron-builder",
|
"build:main": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.main.prod.ts",
|
||||||
"postinstall": "node post-install.js && electron-builder install-app-deps",
|
"build:renderer": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.prod.ts",
|
||||||
"prisma:init": "npx prisma migrate dev",
|
"rebuild": "electron-rebuild --parallel --types prod,dev,optional --module-dir release/app",
|
||||||
"prisma:dev": "npx prisma db push",
|
"lint": "cross-env NODE_ENV=development eslint . --ext .js,.jsx,.ts,.tsx",
|
||||||
"prisma:migrate": ""
|
"lint:styles": "npx stylelint **/*.tsx",
|
||||||
|
"package": "ts-node ./.erb/scripts/clean.js dist && npm run build && electron-builder build --publish never",
|
||||||
|
"package:pr": "ts-node ./.erb/scripts/clean.js dist && npm run build && electron-builder build --publish never --win --mac --linux",
|
||||||
|
"package:dev": "ts-node ./.erb/scripts/clean.js dist && npm run build && electron-builder build --publish never --dir",
|
||||||
|
"postinstall": "ts-node .erb/scripts/check-native-dep.js && electron-builder install-app-deps && cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.dev.dll.ts",
|
||||||
|
"start": "ts-node ./.erb/scripts/check-port-in-use.js && npm run start:renderer",
|
||||||
|
"start:main": "cross-env NODE_ENV=development electron -r ts-node/register/transpile-only ./src/main/main.ts",
|
||||||
|
"start:preload": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.preload.dev.ts",
|
||||||
|
"start:renderer": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack serve --config ./.erb/configs/webpack.config.renderer.dev.ts",
|
||||||
|
"start:web": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack serve --config ./.erb/configs/webpack.config.renderer.web.ts",
|
||||||
|
"test": "jest",
|
||||||
|
"prepare": "husky install",
|
||||||
|
"i18next": "i18next -c src/renderer/i18n/i18next-parser.config.js",
|
||||||
|
"prod:buildserver": "pwsh -c \"./scripts/server-build.ps1\"",
|
||||||
|
"prod:publishserver": "pwsh -c \"./scripts/server-publish.ps1\""
|
||||||
},
|
},
|
||||||
"engines": {
|
"lint-staged": {
|
||||||
"node": "^14.18.0 || >=16.0.0"
|
"*.{js,jsx,ts,tsx}": [
|
||||||
|
"cross-env NODE_ENV=development eslint --cache"
|
||||||
|
],
|
||||||
|
"*.json,.{eslintrc,prettierrc}": [
|
||||||
|
"prettier --ignore-path .eslintignore --parser json --write"
|
||||||
|
],
|
||||||
|
"*.{css,scss}": [
|
||||||
|
"prettier --ignore-path .eslintignore --single-quote --write"
|
||||||
|
],
|
||||||
|
"*.{html,md,yml}": [
|
||||||
|
"prettier --ignore-path .eslintignore --single-quote --write"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"build": {
|
||||||
"@prisma/client": "^4.4.0",
|
"productName": "Feishin",
|
||||||
"node-mpv": "^2.0.0-beta.2"
|
"appId": "org.jeffvli.feishin",
|
||||||
|
"artifactName": "${productName}-${version}-${os}-${arch}.${ext}",
|
||||||
|
"asar": true,
|
||||||
|
"asarUnpack": "**\\*.{node,dll}",
|
||||||
|
"files": [
|
||||||
|
"dist",
|
||||||
|
"node_modules",
|
||||||
|
"package.json"
|
||||||
|
],
|
||||||
|
"afterSign": ".erb/scripts/notarize.js",
|
||||||
|
"electronVersion": "22.3.1",
|
||||||
|
"mac": {
|
||||||
|
"target": {
|
||||||
|
"target": "default",
|
||||||
|
"arch": [
|
||||||
|
"arm64",
|
||||||
|
"x64"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"type": "distribution",
|
||||||
|
"hardenedRuntime": true,
|
||||||
|
"entitlements": "assets/entitlements.mac.plist",
|
||||||
|
"entitlementsInherit": "assets/entitlements.mac.plist",
|
||||||
|
"gatekeeperAssess": false
|
||||||
|
},
|
||||||
|
"dmg": {
|
||||||
|
"contents": [
|
||||||
|
{
|
||||||
|
"x": 130,
|
||||||
|
"y": 220
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 410,
|
||||||
|
"y": 220,
|
||||||
|
"type": "link",
|
||||||
|
"path": "/Applications"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"win": {
|
||||||
|
"target": [
|
||||||
|
"nsis",
|
||||||
|
"zip"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"linux": {
|
||||||
|
"target": [
|
||||||
|
"AppImage",
|
||||||
|
"tar.xz"
|
||||||
|
],
|
||||||
|
"icon": "assets/icons/placeholder.png",
|
||||||
|
"category": "Development"
|
||||||
|
},
|
||||||
|
"directories": {
|
||||||
|
"app": "release/app",
|
||||||
|
"buildResources": "assets",
|
||||||
|
"output": "release/build"
|
||||||
|
},
|
||||||
|
"extraResources": [
|
||||||
|
"./assets/**"
|
||||||
|
],
|
||||||
|
"publish": {
|
||||||
|
"provider": "github",
|
||||||
|
"owner": "jeffvli",
|
||||||
|
"repo": "feishin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/jeffvli/feishin.git"
|
||||||
|
},
|
||||||
|
"author": {
|
||||||
|
"name": "jeffvli",
|
||||||
|
"url": "https://github.com/jeffvli/"
|
||||||
|
},
|
||||||
|
"contributors": [],
|
||||||
|
"license": "GPL-3.0",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/jeffvli/feishin/issues"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"subsonic",
|
||||||
|
"navidrome",
|
||||||
|
"airsonic",
|
||||||
|
"jellyfin",
|
||||||
|
"react",
|
||||||
|
"electron"
|
||||||
|
],
|
||||||
|
"homepage": "https://github.com/jeffvli/feishin",
|
||||||
|
"jest": {
|
||||||
|
"testURL": "http://localhost/",
|
||||||
|
"testEnvironment": "jsdom",
|
||||||
|
"transform": {
|
||||||
|
"\\.(ts|tsx|js|jsx)$": "ts-jest"
|
||||||
|
},
|
||||||
|
"moduleNameMapper": {
|
||||||
|
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/.erb/mocks/fileMock.js",
|
||||||
|
"\\.(css|less|sass|scss)$": "identity-obj-proxy"
|
||||||
|
},
|
||||||
|
"moduleFileExtensions": [
|
||||||
|
"js",
|
||||||
|
"jsx",
|
||||||
|
"ts",
|
||||||
|
"tsx",
|
||||||
|
"json"
|
||||||
|
],
|
||||||
|
"moduleDirectories": [
|
||||||
|
"node_modules",
|
||||||
|
"release/app/node_modules"
|
||||||
|
],
|
||||||
|
"testPathIgnorePatterns": [
|
||||||
|
"release/app/dist"
|
||||||
|
],
|
||||||
|
"setupFiles": [
|
||||||
|
"./.erb/scripts/check-build-exists.ts"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^18.0.21",
|
"@electron/rebuild": "^3.2.10",
|
||||||
"@types/react-dom": "^18.0.6",
|
"@pmmmwh/react-refresh-webpack-plugin": "0.5.5",
|
||||||
"@vitejs/plugin-react": "^2.1.0",
|
"@stylelint/postcss-css-in-js": "^0.38.0",
|
||||||
"electron": "^21.1.0",
|
"@teamsupercell/typings-for-css-modules-loader": "^2.5.1",
|
||||||
"electron-builder": "^23.3.3",
|
"@testing-library/jest-dom": "^5.16.4",
|
||||||
"react": "^18.2.0",
|
"@testing-library/react": "^13.0.0",
|
||||||
"react-dom": "^18.2.0",
|
"@types/electron-localshortcut": "^3.1.0",
|
||||||
"sass": "^1.55.0",
|
"@types/jest": "^27.4.1",
|
||||||
"typescript": "^4.8.4",
|
"@types/lodash": "^4.14.188",
|
||||||
"vite": "^3.1.4",
|
"@types/md5": "^2.3.2",
|
||||||
"vite-electron-plugin": "^0.4.4",
|
"@types/node": "^17.0.23",
|
||||||
"@emotion/react": "^11.10.4",
|
"@types/react": "^18.0.25",
|
||||||
"@emotion/styled": "^11.10.4",
|
"@types/react-dom": "^18.0.8",
|
||||||
"@mantine/carousel": "^5.5.4",
|
"@types/react-test-renderer": "^17.0.1",
|
||||||
"@mantine/core": "^5.5.4",
|
"@types/react-virtualized-auto-sizer": "^1.0.1",
|
||||||
"@mantine/dates": "^5.5.4",
|
"@types/react-window": "^1.8.5",
|
||||||
"@mantine/form": "^5.5.4",
|
"@types/react-window-infinite-loader": "^1.0.6",
|
||||||
"@mantine/hooks": "^5.5.4",
|
"@types/styled-components": "^5.1.26",
|
||||||
"@mantine/modals": "^5.5.4",
|
"@types/terser-webpack-plugin": "^5.0.4",
|
||||||
"@mantine/notifications": "^5.5.4",
|
"@types/webpack-bundle-analyzer": "^4.4.1",
|
||||||
"@mantine/spotlight": "^5.5.4",
|
"@types/webpack-env": "^1.16.3",
|
||||||
"@tanstack/react-query": "^4.10.1",
|
"@typescript-eslint/eslint-plugin": "^5.47.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.39.0",
|
"@typescript-eslint/parser": "^5.47.0",
|
||||||
"@typescript-eslint/parser": "^5.39.0",
|
"browserslist-config-erb": "^0.0.3",
|
||||||
"ag-grid-community": "^28.2.0",
|
"chalk": "^4.1.2",
|
||||||
"ag-grid-react": "^28.2.0",
|
"concurrently": "^7.1.0",
|
||||||
"axios": "^1.0.0",
|
"core-js": "^3.21.1",
|
||||||
"dayjs": "^1.11.5",
|
"cross-env": "^7.0.3",
|
||||||
"electron-is-dev": "^2.0.0",
|
"css-loader": "^6.7.1",
|
||||||
"electron-rebuild": "^3.2.9",
|
"css-minimizer-webpack-plugin": "^3.4.1",
|
||||||
"embla-carousel-react": "^7.0.3",
|
"detect-port": "^1.3.0",
|
||||||
"eslint": "^8.24.0",
|
"electron": "^22.3.1",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"electron-builder": "^24.0.0-alpha.13",
|
||||||
"eslint-import-resolver-typescript": "^3.5.1",
|
"electron-devtools-installer": "^3.2.0",
|
||||||
|
"electron-notarize": "^1.2.1",
|
||||||
|
"electronmon": "^2.0.2",
|
||||||
|
"eslint": "^8.30.0",
|
||||||
|
"eslint-config-airbnb-base": "^15.0.0",
|
||||||
|
"eslint-config-erb": "^4.0.3",
|
||||||
|
"eslint-import-resolver-typescript": "^2.7.1",
|
||||||
|
"eslint-import-resolver-webpack": "^0.13.2",
|
||||||
|
"eslint-plugin-compat": "^4.0.2",
|
||||||
"eslint-plugin-import": "^2.26.0",
|
"eslint-plugin-import": "^2.26.0",
|
||||||
"eslint-plugin-jsx-a11y": "^6.6.1",
|
"eslint-plugin-jest": "^26.1.3",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||||
"eslint-plugin-promise": "^6.0.1",
|
"eslint-plugin-promise": "^6.0.0",
|
||||||
"eslint-plugin-react": "^7.31.8",
|
"eslint-plugin-react": "^7.29.4",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.4.0",
|
||||||
"eslint-plugin-sort-keys-fix": "^1.1.2",
|
"eslint-plugin-sort-keys-fix": "^1.1.2",
|
||||||
"eslint-plugin-typescript-sort-keys": "^2.1.0",
|
"eslint-plugin-typescript-sort-keys": "^2.1.0",
|
||||||
"immer": "^9.0.15",
|
"file-loader": "^6.2.0",
|
||||||
"nanoid": "^4.0.0",
|
"html-webpack-plugin": "^5.5.0",
|
||||||
"prettier": "^2.7.1",
|
"husky": "^7.0.4",
|
||||||
"prisma": "^4.4.0",
|
"i18next-parser": "^6.3.0",
|
||||||
"react-virtualized-auto-sizer": "^1.0.7",
|
"identity-obj-proxy": "^3.0.0",
|
||||||
"react-window": "^1.8.7",
|
"jest": "^27.5.1",
|
||||||
"react-window-infinite-loader": "^1.0.8",
|
"lint-staged": "^12.3.7",
|
||||||
"replace-in-file": "^6.3.5",
|
"mini-css-extract-plugin": "^2.6.0",
|
||||||
"ts-node": "^10.9.1",
|
"postcss-scss": "^4.0.4",
|
||||||
"vite-plugin-electron": "^0.9.2",
|
"postcss-syntax": "^0.36.2",
|
||||||
"vite-plugin-electron-renderer": "^0.9.3",
|
"prettier": "^2.6.2",
|
||||||
"zustand": "^4.1.1"
|
"react-refresh": "^0.12.0",
|
||||||
|
"react-refresh-typescript": "^2.0.4",
|
||||||
|
"react-test-renderer": "^18.0.0",
|
||||||
|
"rimraf": "^3.0.2",
|
||||||
|
"sass": "^1.49.11",
|
||||||
|
"sass-loader": "^12.6.0",
|
||||||
|
"style-loader": "^3.3.1",
|
||||||
|
"stylelint": "^14.9.1",
|
||||||
|
"stylelint-config-rational-order": "^0.1.2",
|
||||||
|
"stylelint-config-standard-scss": "^4.0.0",
|
||||||
|
"stylelint-config-styled-components": "^0.1.1",
|
||||||
|
"stylelint-order": "^5.0.0",
|
||||||
|
"stylelint-processor-styled-components": "^1.10.0",
|
||||||
|
"terser-webpack-plugin": "^5.3.1",
|
||||||
|
"ts-jest": "^27.1.4",
|
||||||
|
"ts-loader": "^9.2.8",
|
||||||
|
"ts-node": "^10.7.0",
|
||||||
|
"tsconfig-paths-webpack-plugin": "^4.0.0",
|
||||||
|
"typescript": "^4.8.4",
|
||||||
|
"typescript-plugin-styled-components": "^2.0.0",
|
||||||
|
"url-loader": "^4.1.1",
|
||||||
|
"webpack": "^5.71.0",
|
||||||
|
"webpack-bundle-analyzer": "^4.5.0",
|
||||||
|
"webpack-cli": "^4.9.2",
|
||||||
|
"webpack-dev-server": "^4.8.0",
|
||||||
|
"webpack-merge": "^5.8.0"
|
||||||
},
|
},
|
||||||
"debug": {
|
"dependencies": {
|
||||||
"env": {
|
"@ag-grid-community/client-side-row-model": "^28.2.1",
|
||||||
"VITE_DEV_SERVER_URL": "http://127.0.0.1:7777"
|
"@ag-grid-community/core": "^28.2.1",
|
||||||
}
|
"@ag-grid-community/infinite-row-model": "^28.2.1",
|
||||||
|
"@ag-grid-community/react": "^28.2.1",
|
||||||
|
"@ag-grid-community/styles": "^28.2.1",
|
||||||
|
"@emotion/react": "^11.10.4",
|
||||||
|
"@mantine/core": "^6.0.13",
|
||||||
|
"@mantine/dates": "^6.0.13",
|
||||||
|
"@mantine/form": "^6.0.13",
|
||||||
|
"@mantine/hooks": "^6.0.13",
|
||||||
|
"@mantine/modals": "^6.0.13",
|
||||||
|
"@mantine/notifications": "^6.0.13",
|
||||||
|
"@mantine/utils": "^6.0.13",
|
||||||
|
"@tanstack/react-query": "^4.29.5",
|
||||||
|
"@tanstack/react-query-devtools": "^4.29.6",
|
||||||
|
"@ts-rest/core": "^3.23.0",
|
||||||
|
"axios": "^1.4.0",
|
||||||
|
"cmdk": "^0.2.0",
|
||||||
|
"dayjs": "^1.11.6",
|
||||||
|
"electron-debug": "^3.2.0",
|
||||||
|
"electron-localshortcut": "^3.2.1",
|
||||||
|
"electron-log": "^4.4.6",
|
||||||
|
"electron-store": "^8.1.0",
|
||||||
|
"electron-updater": "^4.6.5",
|
||||||
|
"fast-average-color": "^9.3.0",
|
||||||
|
"format-duration": "^2.0.0",
|
||||||
|
"framer-motion": "^9.1.7",
|
||||||
|
"fuse.js": "^6.6.2",
|
||||||
|
"history": "^5.3.0",
|
||||||
|
"i18next": "^21.6.16",
|
||||||
|
"immer": "^9.0.21",
|
||||||
|
"is-electron": "^2.2.2",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"md5": "^2.3.0",
|
||||||
|
"memoize-one": "^6.0.0",
|
||||||
|
"nanoid": "^3.3.3",
|
||||||
|
"net": "^1.0.2",
|
||||||
|
"node-mpv": "github:jeffvli/Node-MPV",
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0",
|
||||||
|
"react-error-boundary": "^3.1.4",
|
||||||
|
"react-i18next": "^11.16.7",
|
||||||
|
"react-icons": "^4.8.0",
|
||||||
|
"react-player": "^2.11.0",
|
||||||
|
"react-router": "^6.5.0",
|
||||||
|
"react-router-dom": "^6.5.0",
|
||||||
|
"react-simple-img": "^3.0.0",
|
||||||
|
"react-virtualized-auto-sizer": "^1.0.17",
|
||||||
|
"react-window": "^1.8.9",
|
||||||
|
"react-window-infinite-loader": "^1.0.9",
|
||||||
|
"styled-components": "^5.3.11",
|
||||||
|
"swiper": "^9.3.1",
|
||||||
|
"zod": "^3.21.4",
|
||||||
|
"zustand": "^4.3.8"
|
||||||
|
},
|
||||||
|
"resolutions": {
|
||||||
|
"styled-components": "^5"
|
||||||
|
},
|
||||||
|
"devEngines": {
|
||||||
|
"node": ">=14.x",
|
||||||
|
"npm": ">=7.x"
|
||||||
|
},
|
||||||
|
"browserslist": [],
|
||||||
|
"electronmon": {
|
||||||
|
"patterns": [
|
||||||
|
"!server",
|
||||||
|
"!src/renderer"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
const path = require('path');
|
|
||||||
const replace = require('replace-in-file');
|
|
||||||
|
|
||||||
// fix long prisma loading times caused by scanning from process.cwd(), which returns "/" when run in electron
|
|
||||||
// (thus it scans all files on the computer.) See https://github.com/prisma/prisma/issues/8484
|
|
||||||
// solution: we get the app path from main process via sync IPC
|
|
||||||
const options = {
|
|
||||||
files: path.join(__dirname, '../release/app/node_modules/', '@prisma', 'client', 'index.js'),
|
|
||||||
from: 'findSync(process.cwd()',
|
|
||||||
to: `findSync(require("electron").ipcRenderer.sendSync('config:get-app-path')`,
|
|
||||||
};
|
|
||||||
|
|
||||||
const results = replace.sync(options);
|
|
||||||
console.log('build script: prisma fix', results);
|
|
||||||
@@ -1,272 +0,0 @@
|
|||||||
generator client {
|
|
||||||
provider = "prisma-client-js"
|
|
||||||
engineType = "library"
|
|
||||||
binaryTargets = ["native", "windows"]
|
|
||||||
// output = "../release/app/node_modules/.prisma/client"
|
|
||||||
}
|
|
||||||
|
|
||||||
datasource db {
|
|
||||||
provider = "sqlite"
|
|
||||||
url = "file:../release/app/prisma/dev.db"
|
|
||||||
}
|
|
||||||
|
|
||||||
model User {
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
name String
|
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
|
||||||
|
|
||||||
favorites Favorite[]
|
|
||||||
albumArtistRatings AlbumArtistRating[]
|
|
||||||
artistRatings ArtistRating[]
|
|
||||||
albumRatings AlbumRating[]
|
|
||||||
songRatings SongRating[]
|
|
||||||
}
|
|
||||||
|
|
||||||
model Server {
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
nickname String @unique
|
|
||||||
url String @unique
|
|
||||||
remoteId String @map("remote_id")
|
|
||||||
authUsername String @map("auth_username")
|
|
||||||
authCredential String @map("auth_credential")
|
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
|
||||||
|
|
||||||
serverType ServerType @relation(fields: [serverTypeId], references: [id])
|
|
||||||
serverTypeId Int
|
|
||||||
|
|
||||||
serverFolders ServerFolder[]
|
|
||||||
songs Song[]
|
|
||||||
albums Album[]
|
|
||||||
artists Artist[]
|
|
||||||
albumArtists AlbumArtist[]
|
|
||||||
|
|
||||||
// @@map("server")
|
|
||||||
}
|
|
||||||
|
|
||||||
model ServerType {
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
name String @unique
|
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
|
||||||
Server Server[]
|
|
||||||
|
|
||||||
// @@map("server_type")
|
|
||||||
}
|
|
||||||
|
|
||||||
model ServerFolder {
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
name String
|
|
||||||
remoteId String @map("remote_id")
|
|
||||||
enabled Boolean @default(true)
|
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
|
||||||
|
|
||||||
server Server @relation(fields: [serverId], references: [id])
|
|
||||||
serverId Int
|
|
||||||
|
|
||||||
// @@map("server_folder")
|
|
||||||
}
|
|
||||||
|
|
||||||
model Genre {
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
name String @unique
|
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
|
||||||
|
|
||||||
artists Artist[]
|
|
||||||
albumArtists AlbumArtist[]
|
|
||||||
albums Album[]
|
|
||||||
songs Song[]
|
|
||||||
|
|
||||||
// @@map("genre")
|
|
||||||
}
|
|
||||||
|
|
||||||
model Favorite {
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
|
||||||
|
|
||||||
albumArtists AlbumArtist[]
|
|
||||||
artists Artist[]
|
|
||||||
albums Album[]
|
|
||||||
songs Song[]
|
|
||||||
|
|
||||||
User User? @relation(fields: [userId], references: [id])
|
|
||||||
userId Int?
|
|
||||||
|
|
||||||
// @@map("favorite")
|
|
||||||
}
|
|
||||||
|
|
||||||
model AlbumArtistRating {
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
value Float
|
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
|
||||||
|
|
||||||
user User @relation(fields: [userId], references: [id])
|
|
||||||
userId Int
|
|
||||||
|
|
||||||
albumArtist AlbumArtist? @relation(fields: [albumArtistId], references: [id])
|
|
||||||
albumArtistId Int
|
|
||||||
// @@map("album_artist_rating")
|
|
||||||
|
|
||||||
@@unique(fields: [albumArtistId, userId], name: "uniqueAlbumArtistRating", map: "unique_album_artist_rating")
|
|
||||||
}
|
|
||||||
|
|
||||||
model ArtistRating {
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
value Float
|
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
|
||||||
|
|
||||||
user User @relation(fields: [userId], references: [id])
|
|
||||||
userId Int
|
|
||||||
|
|
||||||
artist Artist? @relation(fields: [artistId], references: [id])
|
|
||||||
artistId Int
|
|
||||||
// @@map("artist_rating")
|
|
||||||
|
|
||||||
@@unique(fields: [artistId, userId], name: "uniqueArtistRating", map: "unique_artist_rating")
|
|
||||||
}
|
|
||||||
|
|
||||||
model AlbumRating {
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
value Float
|
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
|
||||||
|
|
||||||
user User @relation(fields: [userId], references: [id])
|
|
||||||
userId Int
|
|
||||||
|
|
||||||
album Album? @relation(fields: [albumId], references: [id])
|
|
||||||
albumId Int
|
|
||||||
// @@map("album_rating")
|
|
||||||
|
|
||||||
@@unique(fields: [albumId, userId], name: "uniqueAlbumRating", map: "unique_album_rating")
|
|
||||||
}
|
|
||||||
|
|
||||||
model SongRating {
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
value Float
|
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
|
||||||
|
|
||||||
user User @relation(fields: [userId], references: [id])
|
|
||||||
userId Int
|
|
||||||
|
|
||||||
song Song? @relation(fields: [songId], references: [id])
|
|
||||||
songId Int
|
|
||||||
// @@map("song_rating")
|
|
||||||
|
|
||||||
@@unique(fields: [songId, userId], name: "uniqueSongRating", map: "unique_song_rating")
|
|
||||||
}
|
|
||||||
|
|
||||||
model AlbumArtist {
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
name String
|
|
||||||
image String?
|
|
||||||
image_remote String? @map("image_remote")
|
|
||||||
sortName String @map("sort_name")
|
|
||||||
biography String?
|
|
||||||
remoteId String @map("remote_id")
|
|
||||||
remoteCreatedAt DateTime? @map("remote_created_at")
|
|
||||||
deleted Boolean @default(false)
|
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
|
||||||
|
|
||||||
genres Genre[]
|
|
||||||
albums Album[]
|
|
||||||
songs Song[]
|
|
||||||
favorites Favorite[]
|
|
||||||
ratings AlbumArtistRating[]
|
|
||||||
|
|
||||||
server Server @relation(fields: [serverId], references: [id])
|
|
||||||
serverId Int
|
|
||||||
// @@map("album_artist")
|
|
||||||
|
|
||||||
@@unique(fields: [serverId, remoteId], name: "uniqueAlbumArtistId", map: "unique_album_artist_id")
|
|
||||||
}
|
|
||||||
|
|
||||||
model Artist {
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
name String
|
|
||||||
image String?
|
|
||||||
image_remote String? @map("image_remote")
|
|
||||||
biography String?
|
|
||||||
remoteId String @map("remote_id")
|
|
||||||
remoteCreatedAt DateTime? @map("remote_created_at")
|
|
||||||
deleted Boolean @default(false)
|
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
|
||||||
|
|
||||||
genres Genre[]
|
|
||||||
favorites Favorite[]
|
|
||||||
ratings ArtistRating[]
|
|
||||||
|
|
||||||
server Server @relation(fields: [serverId], references: [id])
|
|
||||||
serverId Int
|
|
||||||
// @@map("artist")
|
|
||||||
|
|
||||||
@@unique(fields: [serverId, remoteId], name: "uniqueArtistId", map: "unique_artist_id")
|
|
||||||
}
|
|
||||||
|
|
||||||
model Album {
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
name String
|
|
||||||
image String?
|
|
||||||
image_remote String? @map("image_remote")
|
|
||||||
releaseDate DateTime? @map("release_date")
|
|
||||||
releaseYear Int? @map("release_year")
|
|
||||||
remoteId String
|
|
||||||
remoteCreatedAt DateTime?
|
|
||||||
deleted Boolean @default(false)
|
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
|
||||||
|
|
||||||
genres Genre[]
|
|
||||||
albumArtists AlbumArtist[]
|
|
||||||
favorites Favorite[]
|
|
||||||
ratings AlbumRating[]
|
|
||||||
|
|
||||||
server Server @relation(fields: [serverId], references: [id])
|
|
||||||
serverId Int @map("server_id")
|
|
||||||
// @@map("album")
|
|
||||||
|
|
||||||
@@unique(fields: [serverId, remoteId], name: "uniqueAlbumId", map: "unique_album_id")
|
|
||||||
}
|
|
||||||
|
|
||||||
model Song {
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
name String
|
|
||||||
image String?
|
|
||||||
remote_image String? @map("remote_image")
|
|
||||||
releaseDate DateTime? @map("release_date")
|
|
||||||
releaseYear Int? @map("release_year")
|
|
||||||
duration Float?
|
|
||||||
lyric String?
|
|
||||||
bitRate Int @map("bit_rate")
|
|
||||||
container String
|
|
||||||
size String?
|
|
||||||
channels Int?
|
|
||||||
discIndex Int @default(1) @map("disc_index")
|
|
||||||
trackIndex Int? @map("track_index")
|
|
||||||
artistName String? @map("artist_name")
|
|
||||||
remoteId String @map("remote_id")
|
|
||||||
remoteCreatedAt DateTime? @map("remote_created_at")
|
|
||||||
deleted Boolean @default(false)
|
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
|
||||||
|
|
||||||
genres Genre[]
|
|
||||||
albumArtists AlbumArtist[]
|
|
||||||
favorites Favorite[]
|
|
||||||
ratings SongRating[]
|
|
||||||
|
|
||||||
server Server @relation(fields: [serverId], references: [id])
|
|
||||||
serverId Int @map("server_id")
|
|
||||||
// @@map("song")
|
|
||||||
|
|
||||||
@@unique(fields: [serverId, remoteId], name: "uniqueSongId", map: "unique_song_id")
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 9.6 MiB |
|
Before Width: | Height: | Size: 3.4 MiB |
|
Before Width: | Height: | Size: 62 KiB |
@@ -1,15 +0,0 @@
|
|||||||
<svg width="410" height="404" viewBox="0 0 410 404" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M399.641 59.5246L215.643 388.545C211.844 395.338 202.084 395.378 198.228 388.618L10.5817 59.5563C6.38087 52.1896 12.6802 43.2665 21.0281 44.7586L205.223 77.6824C206.398 77.8924 207.601 77.8904 208.776 77.6763L389.119 44.8058C397.439 43.2894 403.768 52.1434 399.641 59.5246Z" fill="url(#paint0_linear)"/>
|
|
||||||
<path d="M292.965 1.5744L156.801 28.2552C154.563 28.6937 152.906 30.5903 152.771 32.8664L144.395 174.33C144.198 177.662 147.258 180.248 150.51 179.498L188.42 170.749C191.967 169.931 195.172 173.055 194.443 176.622L183.18 231.775C182.422 235.487 185.907 238.661 189.532 237.56L212.947 230.446C216.577 229.344 220.065 232.527 219.297 236.242L201.398 322.875C200.278 328.294 207.486 331.249 210.492 326.603L212.5 323.5L323.454 102.072C325.312 98.3645 322.108 94.137 318.036 94.9228L279.014 102.454C275.347 103.161 272.227 99.746 273.262 96.1583L298.731 7.86689C299.767 4.27314 296.636 0.855181 292.965 1.5744Z" fill="url(#paint1_linear)"/>
|
|
||||||
<defs>
|
|
||||||
<linearGradient id="paint0_linear" x1="6.00017" y1="32.9999" x2="235" y2="344" gradientUnits="userSpaceOnUse">
|
|
||||||
<stop stop-color="#41D1FF"/>
|
|
||||||
<stop offset="1" stop-color="#BD34FE"/>
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient id="paint1_linear" x1="194.651" y1="8.81818" x2="236.076" y2="292.989" gradientUnits="userSpaceOnUse">
|
|
||||||
<stop stop-color="#FFEA83"/>
|
|
||||||
<stop offset="0.0833333" stop-color="#FFDD35"/>
|
|
||||||
<stop offset="1" stop-color="#FFA800"/>
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 16 KiB |
@@ -1,7 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3">
|
|
||||||
<g fill="#61DAFB">
|
|
||||||
<path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/>
|
|
||||||
<circle cx="420.9" cy="296.5" r="45.7"/>
|
|
||||||
<path d="M520.5 78.1z"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 2.6 KiB |
@@ -1,15 +0,0 @@
|
|||||||
<svg width="410" height="404" viewBox="0 0 410 404" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M399.641 59.5246L215.643 388.545C211.844 395.338 202.084 395.378 198.228 388.618L10.5817 59.5563C6.38087 52.1896 12.6802 43.2665 21.0281 44.7586L205.223 77.6824C206.398 77.8924 207.601 77.8904 208.776 77.6763L389.119 44.8058C397.439 43.2894 403.768 52.1434 399.641 59.5246Z" fill="url(#paint0_linear)"/>
|
|
||||||
<path d="M292.965 1.5744L156.801 28.2552C154.563 28.6937 152.906 30.5903 152.771 32.8664L144.395 174.33C144.198 177.662 147.258 180.248 150.51 179.498L188.42 170.749C191.967 169.931 195.172 173.055 194.443 176.622L183.18 231.775C182.422 235.487 185.907 238.661 189.532 237.56L212.947 230.446C216.577 229.344 220.065 232.527 219.297 236.242L201.398 322.875C200.278 328.294 207.486 331.249 210.492 326.603L212.5 323.5L323.454 102.072C325.312 98.3645 322.108 94.137 318.036 94.9228L279.014 102.454C275.347 103.161 272.227 99.746 273.262 96.1583L298.731 7.86689C299.767 4.27314 296.636 0.855181 292.965 1.5744Z" fill="url(#paint1_linear)"/>
|
|
||||||
<defs>
|
|
||||||
<linearGradient id="paint0_linear" x1="6.00017" y1="32.9999" x2="235" y2="344" gradientUnits="userSpaceOnUse">
|
|
||||||
<stop stop-color="#41D1FF"/>
|
|
||||||
<stop offset="1" stop-color="#BD34FE"/>
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient id="paint1_linear" x1="194.651" y1="8.81818" x2="236.076" y2="292.989" gradientUnits="userSpaceOnUse">
|
|
||||||
<stop stop-color="#FFEA83"/>
|
|
||||||
<stop offset="0.0833333" stop-color="#FFDD35"/>
|
|
||||||
<stop offset="1" stop-color="#FFA800"/>
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1,19 +1,23 @@
|
|||||||
{
|
{
|
||||||
"name": "sonixd-rewrite",
|
"name": "feishin",
|
||||||
"version": "0.0.0",
|
"version": "0.2.0",
|
||||||
"description": "A foundation for scalable desktop apps",
|
"description": "",
|
||||||
"main": "./dist/main/main.js",
|
"main": "./dist/main/main.js",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Electron React Boilerplate Maintainers",
|
"name": "jeffvli",
|
||||||
"email": "electronreactboilerplate@gmail.com",
|
"url": "https://github.com/jeffvli/"
|
||||||
"url": "https://github.com/electron-react-boilerplate"
|
},
|
||||||
|
"scripts": {
|
||||||
|
"electron-rebuild": "node -r ts-node/register ../../.erb/scripts/electron-rebuild.js",
|
||||||
|
"link-modules": "node -r ts-node/register ../../.erb/scripts/link-modules.ts",
|
||||||
|
"postinstall": "npm run electron-rebuild && npm run link-modules"
|
||||||
},
|
},
|
||||||
"scripts": {},
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/client": "4.4.0"
|
"cheerio": "^1.0.0-rc.12",
|
||||||
|
"mpris-service": "^2.1.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"prisma": "4.4.0"
|
"electron": "22.3.1"
|
||||||
},
|
},
|
||||||
"license": "MIT"
|
"license": "GPL-3.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
import { useState } from "react";
|
|
||||||
import electron from "/electron.png";
|
|
||||||
import react from "/react.svg";
|
|
||||||
import vite from "/vite.svg";
|
|
||||||
import styles from "styles/app.module.scss";
|
|
||||||
|
|
||||||
const App: React.FC = () => {
|
|
||||||
const [count, setCount] = useState(0);
|
|
||||||
|
|
||||||
window.electron.doThing();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={styles.app}>
|
|
||||||
<header className={styles.appHeader}>
|
|
||||||
<div className={styles.logos}>
|
|
||||||
<div className={styles.imgBox}>
|
|
||||||
<img
|
|
||||||
src={electron}
|
|
||||||
style={{ height: "24vw" }}
|
|
||||||
className={styles.appLogo}
|
|
||||||
alt="electron"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className={styles.imgBox}>
|
|
||||||
<img src={vite} style={{ height: "19vw" }} alt="vite" />
|
|
||||||
</div>
|
|
||||||
<div className={styles.imgBox}>
|
|
||||||
<img
|
|
||||||
src={react}
|
|
||||||
style={{ maxWidth: "100%" }}
|
|
||||||
className={styles.appLogo}
|
|
||||||
alt="logo"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p>Hello Electron + Vite + React!</p>
|
|
||||||
<p>
|
|
||||||
<button onClick={() => setCount((count) => count + 1)}>
|
|
||||||
count is: {count}
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Edit <code>App.tsx</code> and save to test HMR updates.
|
|
||||||
</p>
|
|
||||||
<div>
|
|
||||||
<a
|
|
||||||
className={styles.appLink}
|
|
||||||
href="https://reactjs.org"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
Learn React
|
|
||||||
</a>
|
|
||||||
{" | "}
|
|
||||||
<a
|
|
||||||
className={styles.appLink}
|
|
||||||
href="https://vitejs.dev/guide/features.html"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
Vite Docs
|
|
||||||
</a>
|
|
||||||
<div className={styles.staticPublic}>
|
|
||||||
Place static files into the <code>/public</code> folder
|
|
||||||
<img style={{ width: 77 }} src="./node.png" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default App;
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import '@testing-library/jest-dom';
|
||||||
|
import { render } from '@testing-library/react';
|
||||||
|
import { App } from '../renderer/app';
|
||||||
|
|
||||||
|
describe('App', () => {
|
||||||
|
it('should render', () => {
|
||||||
|
expect(render(<App />)).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
.app {
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
.appHeader {
|
|
||||||
background-color: #282c34;
|
|
||||||
min-height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: calc(10px + 2vmin);
|
|
||||||
color: white;
|
|
||||||
|
|
||||||
.logos {
|
|
||||||
display: flex;
|
|
||||||
box-sizing: border-box;
|
|
||||||
align-items: center;
|
|
||||||
padding: 0 5vw;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.imgBox {
|
|
||||||
width: 33.33%;
|
|
||||||
|
|
||||||
.appLogo {
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
|
||||||
.appLogo {
|
|
||||||
animation: App-logo-spin infinite 20s linear;
|
|
||||||
}
|
|
||||||
@keyframes App-logo-spin {
|
|
||||||
from {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
font-size: calc(10px + 2vmin);
|
|
||||||
}
|
|
||||||
|
|
||||||
.appLink {
|
|
||||||
color: #61dafb;
|
|
||||||
}
|
|
||||||
|
|
||||||
.staticPublic {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
code {
|
|
||||||
padding: 4px 7px;
|
|
||||||
margin: 0 4px;
|
|
||||||
border-radius: 4px;
|
|
||||||
background-color: rgb(30, 30, 30, .7);
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
||||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
|
||||||
sans-serif;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
|
||||||
monospace;
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import { Prisma } from '@prisma/client';
|
|
||||||
|
|
||||||
type ApiSurface = {
|
|
||||||
prisma: {
|
|
||||||
server: {
|
|
||||||
getServer: () => Promise<Prisma.ServerSelect>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface Window {
|
|
||||||
electron: ApiSurface;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import i18n from 'i18next';
|
||||||
|
import { initReactI18next } from 'react-i18next';
|
||||||
|
const en = require('./locales/en.json');
|
||||||
|
|
||||||
|
const resources = {
|
||||||
|
en: { translation: en },
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Languages = [
|
||||||
|
{
|
||||||
|
label: 'English',
|
||||||
|
value: 'en',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
i18n
|
||||||
|
.use(initReactI18next) // passes i18n down to react-i18next
|
||||||
|
.init({
|
||||||
|
fallbackLng: 'en',
|
||||||
|
// language to use, more information here: https://www.i18next.com/overview/configuration-options#languages-namespaces-resources
|
||||||
|
// you can use the i18n.changeLanguage function to change the language manually: https://www.i18next.com/overview/api#changelanguage
|
||||||
|
// if you're using a language detector, do not define the lng option
|
||||||
|
interpolation: {
|
||||||
|
escapeValue: false, // react already safes from xss
|
||||||
|
},
|
||||||
|
|
||||||
|
lng: 'en',
|
||||||
|
|
||||||
|
resources,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default i18n;
|
||||||