Compare commits

..

291 Commits

Author SHA1 Message Date
jeffvli 68b1134da5 Fix formatting and typos 2022-11-21 14:45:59 -08:00
jeffvli 46187acadc Fix typos 2022-11-21 14:42:00 -08:00
jeffvli 69c79f0620 Update README instructions 2022-11-21 14:40:30 -08:00
jeffvli 234c9546c4 Add server release scripts 2022-11-21 13:12:29 -08:00
jeffvli edc80bc3b4 Fix subsonic scanner 2022-11-21 11:27:39 -08:00
jeffvli 1d05966127 Add wait script to prod build 2022-11-21 11:23:47 -08:00
jeffvli 2013c46991 Schema fixes 2022-11-21 09:58:00 -08:00
jeffvli eb7e259c86 Prevent replacement of identical username fields 2022-11-21 09:57:32 -08:00
jeffvli 20cd34a38f Fix publish errors 2022-11-20 19:49:36 -08:00
jeffvli 154de4147c Bump retry version and remove shell 2022-11-20 19:39:41 -08:00
jeffvli 4215e0e1f1 Set workflow dispatch on publish 2022-11-20 19:36:20 -08:00
jeffvli b89fd340e7 Fix publish workflow 2022-11-20 19:33:19 -08:00
jeffvli 19792bc8d8 Update appid 2022-11-20 19:28:50 -08:00
jeffvli 118f416066 Split prod and public builds 2022-11-20 19:28:15 -08:00
jeffvli 693286a6a1 Enable publish 2022-11-20 19:21:13 -08:00
jeffvli c273dd9753 Set default repo settings for i18n and typescript 2022-11-20 17:11:26 -08:00
jeffvli 9c98f8aa01 Remove unused 2022-11-20 17:10:47 -08:00
jeffvli ad39919f3f Change default port 2022-11-20 17:10:25 -08:00
jeffvli 0a89e35a3e Fix credential required 2022-11-20 17:09:13 -08:00
jeffvli de1e6c16c0 Add logout to error fallback 2022-11-20 17:01:52 -08:00
jeffvli b0f031bedc Reject when connection failed 2022-11-20 17:01:18 -08:00
jeffvli 079a400e74 Optimize docker build 2022-11-20 16:07:54 -08:00
jeffvli 2cb54a068a Hide electron-only settings 2022-11-20 05:20:19 -08:00
jeffvli 44ffe1984b Increase default size of sidebar queue 2022-11-20 05:16:37 -08:00
jeffvli d5d0c29280 Move fonts to settings 2022-11-20 05:16:13 -08:00
jeffvli 96dc79a527 Remove unused mpv state set 2022-11-20 04:56:03 -08:00
jeffvli 9b2f9f6326 Align setting title to start 2022-11-20 04:46:47 -08:00
jeffvli 1c130e6c58 Add customizzable mpv parameters 2022-11-20 04:46:25 -08:00
jeffvli 01d327f9f1 Remove tab border 2022-11-20 04:45:25 -08:00
jeffvli 99f9e67500 Add Textarea and JsonInput components 2022-11-20 04:45:10 -08:00
jeffvli 892fa0e7b8 Reset default state on server change 2022-11-20 03:42:26 -08:00
jeffvli 9d7b595e41 Add shortcut for devtools in production build 2022-11-20 03:37:09 -08:00
jeffvli b1d06581ab Move login mutation 2022-11-20 02:03:21 -08:00
jeffvli 0cb2e40f2b Disable artist filters for subsonic 2022-11-20 02:02:05 -08:00
jeffvli 6f0c523559 Persist album list config 2022-11-20 01:53:20 -08:00
jeffvli b51a79c3cd Add scroll events to grid 2022-11-20 01:52:34 -08:00
jeffvli cf9187f548 Add sockets path 2022-11-19 20:51:19 -08:00
jeffvli 25f6c940bb Adjust default themes 2022-11-19 20:51:11 -08:00
jeffvli 449e11c2d4 Adjust object fit 2022-11-19 20:50:35 -08:00
jeffvli 9f4a58352d Use song type instead of server 2022-11-19 20:50:25 -08:00
jeffvli 4f3bd8f44a Scroll to row on grid ready 2022-11-19 20:50:12 -08:00
jeffvli 5811069a0a Add prop type 2022-11-19 20:49:47 -08:00
jeffvli 24b0d37bd1 Adjust grid card rows 2022-11-19 20:49:28 -08:00
jeffvli d66c756af5 Add playqueue table 2022-11-19 20:30:57 -08:00
jeffvli 4cb78bb656 Add multiselect component 2022-11-19 20:26:24 -08:00
jeffvli fe678b546e Update login styles 2022-11-17 02:51:58 -08:00
jeffvli 2a6167441a Add queue drawer 2022-11-17 01:42:53 -08:00
jeffvli b4825c35b5 Various fixes 2022-11-16 20:01:52 -08:00
jeffvli c89808fd14 Update socket api 2022-11-16 19:52:55 -08:00
jeffvli 04b45e26cd Bump packages 2022-11-16 19:52:42 -08:00
jeffvli 3827953b59 Update react-query implementation 2022-11-16 19:52:25 -08:00
jeffvli 82d4ad5502 Add empty placeholder 2022-11-16 10:42:29 -08:00
jeffvli b411ab13ac Prevent null value for skip 2022-11-15 15:54:18 -08:00
jeffvli 67e3a00b26 Base component fixes 2022-11-15 15:54:03 -08:00
jeffvli f40c3838a1 Add border for sidebar items 2022-11-15 15:53:42 -08:00
jeffvli da2ad0ac2e Animate activity song change 2022-11-15 15:53:27 -08:00
jeffvli bf5f464712 Adjust play status 2022-11-15 15:53:05 -08:00
jeffvli f83368874f Adjust skeleton height 2022-11-15 13:37:25 -08:00
jeffvli 2be651ed56 Set popover defaults 2022-11-15 13:36:56 -08:00
jeffvli d120057c8d Fix loading transient prop 2022-11-15 13:36:50 -08:00
jeffvli 99398d5675 Set player to web automatically if not electron 2022-11-15 13:36:35 -08:00
jeffvli f62aacf9d8 Remove unused util 2022-11-15 13:36:14 -08:00
jeffvli a8f0a20602 Export server map function 2022-11-15 13:35:42 -08:00
jeffvli f9c5e6f9fb Add user activity 2022-11-15 13:35:26 -08:00
jeffvli e76267be06 Fix spinner color on queue 2022-11-15 13:33:20 -08:00
jeffvli 2a29f33352 Remove required generic for query options 2022-11-15 13:33:04 -08:00
jeffvli 758e9d4d2c Add server map route 2022-11-15 13:31:11 -08:00
jeffvli 8d5a05c329 Update look and feel 2022-11-14 18:12:24 -08:00
jeffvli 8dad9a8109 Require link prop for styles 2022-11-14 14:25:50 -08:00
jeffvli 7061e16fb4 Add custom spinner to button 2022-11-14 14:25:38 -08:00
jeffvli 4029b149ee Update tab styles 2022-11-14 14:25:24 -08:00
jeffvli 5ee5a089c5 Add spinner component 2022-11-14 14:25:15 -08:00
jeffvli 9e6e8d7fd6 Re-enable navidrome scanner items 2022-11-14 14:24:54 -08:00
jeffvli 28cc1f9c30 Set max width for container 2022-11-14 03:03:58 -08:00
jeffvli 38993f3352 Reduce fade in duration 2022-11-14 03:03:49 -08:00
jeffvli 1bd538b6b4 Update text for link styles 2022-11-14 03:00:05 -08:00
jeffvli 295eb82f20 Adjust default themes 2022-11-14 02:59:51 -08:00
jeffvli 1cc40348cb Remove default staleTime for user detail 2022-11-14 01:15:49 -08:00
jeffvli 85e80be08b Fix overflow 2022-11-14 01:15:02 -08:00
jeffvli 420d4835be Update base components 2022-11-14 01:14:39 -08:00
jeffvli c54eea4382 Add server permission management 2022-11-14 01:13:54 -08:00
jeffvli 1babcc40ee Add user profile image 2022-11-13 20:18:23 -08:00
jeffvli 14c22c63a0 Add server permission routes 2022-11-13 12:35:26 -08:00
jeffvli 1a6c4af5df Fix album permissions by role 2022-11-13 04:56:36 -08:00
jeffvli 4e2325f05d Fix server folder permissions by role 2022-11-13 03:06:24 -08:00
jeffvli 135a8d7a45 Retrieve serverfolders by permission 2022-11-13 02:41:42 -08:00
jeffvli 74170185a2 Add max width to tooltip 2022-11-13 02:41:08 -08:00
jeffvli 3a8665fded Add info tooltips to server options 2022-11-13 02:34:55 -08:00
jeffvli d028af5ff0 Add mpv path option 2022-11-13 02:08:12 -08:00
jeffvli ab7787484c Move localSettings utility to different file 2022-11-13 02:08:02 -08:00
jeffvli c469e2e5cc Adjust paper styles 2022-11-13 02:07:43 -08:00
jeffvli 5de5b34ecf Add accordion component 2022-11-13 02:07:14 -08:00
jeffvli ec59d27c1d Fix password input styles 2022-11-13 01:58:56 -08:00
jeffvli 9a079ef263 Adjust placeholder input color 2022-11-13 01:54:18 -08:00
jeffvli 372fc7c1f6 Add edit profile form 2022-11-13 01:54:02 -08:00
jeffvli 1686005792 Change dropdown position 2022-11-13 01:53:43 -08:00
jeffvli b9c0b62cf8 Add link to mpv site 2022-11-13 01:53:16 -08:00
jeffvli 797e3eab3b Set maxWidth for required container 2022-11-13 01:53:08 -08:00
jeffvli b100f4f790 Add shadow to tooltip 2022-11-13 01:52:52 -08:00
jeffvli 6c5a70c03e Add styles to fileinput 2022-11-13 01:52:47 -08:00
jeffvli 353168ad4e Add light/dark type to theme 2022-11-13 01:52:39 -08:00
jeffvli a03f41b76d Bump mantine to v5.7.2 2022-11-12 18:45:49 -08:00
jeffvli 81fafd20d3 Web player fixes 2022-11-12 18:45:25 -08:00
jeffvli 8353640d05 Update various components 2022-11-12 18:44:51 -08:00
jeffvli 79fae63aaf Add theme selector / update defaults 2022-11-12 18:43:47 -08:00
jeffvli 544fd25f6b Add error boundary package 2022-11-12 12:39:23 -08:00
jeffvli 0e9953be13 Remove unused 2022-11-12 01:22:44 -08:00
jeffvli 258e5bb8f6 Init simple-img in main app 2022-11-12 01:22:29 -08:00
jeffvli 5c6cd2410e Set user profile in server state 2022-11-12 01:22:12 -08:00
jeffvli b08c7dfaf1 Set web volume to be logarithmic 2022-11-12 01:20:23 -08:00
jeffvli 46145fd3aa Adjust playerbar 2022-11-12 01:20:09 -08:00
jeffvli 0b5cea16e9 Handle shuffle/repeat playback for web 2022-11-12 01:19:17 -08:00
jeffvli 34f4458733 Add crossfade style setting 2022-11-12 01:08:20 -08:00
jeffvli d3d6db03d7 Add error boundary 2022-11-11 12:51:08 -08:00
jeffvli f7839d6ed6 Handle shuffle/repeat playback for mpv 2022-11-11 04:40:20 -08:00
jeffvli 581ef32845 Add per-server permissions 2022-11-09 01:52:08 -08:00
jeffvli 73e6002cc7 Fix toast types 2022-11-08 19:01:05 -08:00
jeffvli 048b5898b9 Set center loader 2022-11-08 19:01:00 -08:00
jeffvli ddc0355b1e Update forms 2022-11-08 19:00:48 -08:00
jeffvli 30a7bac59a Add prop to permissions 2022-11-08 19:00:22 -08:00
jeffvli 445e4b56b7 Add initial users manager 2022-11-08 18:46:56 -08:00
jeffvli df8e38cedd Add isSuperAdmin account 2022-11-08 18:40:44 -08:00
jeffvli 3bc0ea16bc Wrap queue handler in callback 2022-11-08 15:16:22 -08:00
jeffvli 84b031f126 Move add server form inside of server list 2022-11-08 15:16:05 -08:00
jeffvli 8357941bfa Add context modal 2022-11-08 15:13:59 -08:00
jeffvli 187ccad15b Add user routes 2022-11-08 15:13:47 -08:00
jeffvli a326355576 Add song skip/displayname to schema 2022-11-08 14:32:01 -08:00
jeffvli e6bf71dcfe Add state merge 2022-11-08 12:17:18 -08:00
jeffvli a964662ad4 Add albumartists to related album 2022-11-08 12:04:10 -08:00
jeffvli 2652ab927f Add playButtonBehavior type 2022-11-08 12:03:36 -08:00
jeffvli 30e9543544 Remove select on sidebar 2022-11-08 04:00:36 -08:00
jeffvli d6fe3038e0 Update server forms 2022-11-08 04:00:22 -08:00
jeffvli d3e4c7d975 Display album artist for subsonic servers 2022-11-08 03:58:52 -08:00
jeffvli 1df07dd12a Adjust component styles 2022-11-08 03:58:23 -08:00
jeffvli 49eb78b03c Add configurable web audio device 2022-11-08 03:58:13 -08:00
jeffvli 7b1940e1f5 Add configurable play button behavior 2022-11-08 03:57:56 -08:00
jeffvli b2cc85d368 Settings fixes 2022-11-08 03:56:59 -08:00
jeffvli dbba5f9f95 Fix skip forward 2022-11-08 03:55:37 -08:00
jeffvli 03278d2624 Fix action required for mpv 2022-11-08 01:36:57 -08:00
jeffvli 9022f05463 Move handlers to separate functions 2022-11-08 01:36:26 -08:00
jeffvli 3cdd08fe89 Add slider component 2022-11-08 01:36:08 -08:00
jeffvli f7ea6c45f5 Add lazy image component 2022-11-08 01:35:21 -08:00
jeffvli ecb090d324 Add modal transitions 2022-11-08 00:23:16 -08:00
jeffvli 587fa2422a Handle web player 2022-11-08 00:20:39 -08:00
jeffvli e774cdf031 Add tabs component 2022-11-07 04:04:32 -08:00
jeffvli cd56783c96 Add media keys 2022-11-07 03:46:55 -08:00
jeffvli 6ac949bf88 Replace @emotion/styled with styled-components 2022-11-06 01:53:31 -08:00
jeffvli de91f75203 Fix card keys 2022-11-06 01:25:53 -08:00
jeffvli d69221f8a4 Fix styles 2022-11-06 00:52:03 -07:00
jeffvli 39d98c5066 Remove checkbox folder 2022-11-06 00:51:48 -07:00
jeffvli 4304a2ae84 Various updates 2022-11-06 00:46:51 -07:00
jeffvli fc1ab03118 Fix props 2022-11-06 00:12:04 -07:00
jeffvli f76cc2f230 Adjust skeleton row width 2022-11-06 00:11:48 -07:00
jeffvli 70ce493f5e Add menu styles 2022-11-06 00:11:37 -07:00
jeffvli 633c6416df Album list updates 2022-11-06 00:08:22 -07:00
jeffvli 07123615ca Move fadein directly to component 2022-11-05 12:00:46 -07:00
jeffvli 385ec5f856 Remove disabled cursor styles 2022-11-05 03:25:59 -07:00
jeffvli 608518ac1c Add link text styles 2022-11-05 03:25:42 -07:00
jeffvli cee6ff4df5 Misc fixes 2022-11-05 03:25:30 -07:00
jeffvli c8da4f8146 Fix action item check if not authenticated 2022-11-05 03:24:38 -07:00
jeffvli 63dba7b379 Increase dropdown size 2022-11-05 03:12:04 -07:00
jeffvli e014ac0a4b Update grid card styles and props 2022-11-05 03:11:51 -07:00
jeffvli ae53b17214 Fix null imageUrl on credential 2022-11-04 19:18:35 -07:00
jeffvli fd53f90db2 Order genres by name 2022-11-04 18:38:00 -07:00
jeffvli d88e99e38c Adjust placeholder defaults 2022-11-04 18:37:42 -07:00
jeffvli 096a7713da Add placeholder images 2022-11-04 18:21:22 -07:00
jeffvli 7aa89e8ad2 Add genres api 2022-11-03 14:45:43 -07:00
jeffvli f284b29052 Add default ops, handle releaseDate 2022-11-03 14:45:00 -07:00
jeffvli 5908554f38 Set all popovers withinPortal by default 2022-11-03 14:41:34 -07:00
jeffvli 53a7d728b3 Progress on advanced filters 2022-11-03 03:25:10 -07:00
jeffvli be05c1df79 Update base components 2022-11-03 03:19:15 -07:00
jeffvli e9142ffaa5 Add paper component 2022-11-03 03:17:27 -07:00
jeffvli aeefbf8f7f Add scroll area component 2022-11-03 02:26:01 -07:00
jeffvli 061e61b7d3 Add packages 2022-11-02 22:05:40 -07:00
jeffvli a888007bfa Update base components 2022-11-02 22:05:16 -07:00
jeffvli 94b40178aa Progress on advanced filters 2022-11-02 22:04:46 -07:00
jeffvli 73fff64a75 Add genres route 2022-11-01 11:30:40 -07:00
jeffvli 97486b23ee Use img tag instead of background-image 2022-11-01 03:47:28 -07:00
jeffvli 005a30e0f4 Add advanced filters base component 2022-11-01 02:56:35 -07:00
jeffvli 1cdcde010c Add shell layout 2022-10-30 20:21:55 -07:00
jeffvli 895356701f Update server list 2022-10-30 20:21:31 -07:00
jeffvli 689560a7a5 Adjust playerbar 2022-10-30 20:20:04 -07:00
jeffvli bc9e6a9a73 Add animated page 2022-10-30 20:19:11 -07:00
jeffvli eb73c87933 Add specific toast types in export 2022-10-30 20:18:50 -07:00
jeffvli 7725d3dfbb Add fileinput, popover 2022-10-30 20:18:38 -07:00
jeffvli 659a9b949b Set as polymorphic 2022-10-30 20:18:16 -07:00
jeffvli 04afa13eae Fix year data 2022-10-30 20:17:06 -07:00
jeffvli df1844b74c Adjust styling and add links 2022-10-30 20:16:53 -07:00
jeffvli b2fc76203d Add 404 route 2022-10-30 15:00:54 -07:00
jeffvli a60a053b6b Add action-required route 2022-10-30 01:43:32 -07:00
jeffvli 699ed268e6 Set MPV path from local settings file 2022-10-30 01:37:05 -07:00
jeffvli e4f797debc Fix type 2022-10-30 01:34:09 -07:00
jeffvli 852a4297a3 Fix names 2022-10-29 19:14:40 -07:00
jeffvli 2489622d90 Rename 2022-10-29 19:14:13 -07:00
jeffvli 19090a0ed8 Update scanner (frontend) 2022-10-29 19:13:40 -07:00
jeffvli 0200b92860 Update scanner (server) 2022-10-29 19:12:02 -07:00
jeffvli ff6882a6cd Handle logout on invalid token 2022-10-29 18:57:23 -07:00
jeffvli 97b383ff0b Fix scripts based on new server path 2022-10-28 16:01:37 -07:00
jeffvli 4fb963d689 Add initial queue/album list routes 2022-10-28 13:11:29 -07:00
jeffvli c6d80831f8 Add ND type 2022-10-28 13:10:07 -07:00
jeffvli 32fe11d3de Handle right sidebar 2022-10-28 13:09:42 -07:00
jeffvli 5bcb0a3824 Add hook to fetch current server cred 2022-10-28 13:07:56 -07:00
jeffvli 91536f1bc9 Add isAdmin to permission set 2022-10-28 13:04:36 -07:00
jeffvli 4fb8d4ebd9 Handle album add with local creds 2022-10-28 13:04:09 -07:00
jeffvli b3f4cfee5d Add switch component 2022-10-28 13:03:10 -07:00
jeffvli 00710125d3 Improve grid 2022-10-28 13:02:55 -07:00
jeffvli 2352c136a1 Add fadeIn style 2022-10-28 13:02:00 -07:00
jeffvli ee8cc14e7e Fix missing song album details 2022-10-28 13:00:31 -07:00
jeffvli ca664d9430 Add server-side credential requirement 2022-10-27 20:33:42 -07:00
jeffvli cbbf3087ff Update serverfolder enable/disable 2022-10-27 00:58:59 -07:00
jeffvli 88e716b970 Add sidebar image option 2022-10-26 21:44:25 -07:00
jeffvli 17258e950e Update frontend linter 2022-10-26 16:28:07 -07:00
jeffvli 5b349083c9 Remove old file 2022-10-26 16:26:24 -07:00
jeffvli 1130006f0f Set min sidebar width to 200 2022-10-26 16:26:01 -07:00
jeffvli e31d8c1cc4 Fix types reference 2022-10-26 16:25:48 -07:00
jeffvli 834e311253 Remove sidebar index 2022-10-26 16:25:37 -07:00
jeffvli 82a47c42b8 Add sidebar state to app store 2022-10-26 16:24:28 -07:00
jeffvli 46eb5e4e5d Fix import 2022-10-26 16:24:16 -07:00
jeffvli 9204cdbe6a Fix casing 2 2022-10-26 16:23:57 -07:00
jeffvli 8258bbe5b3 Fix casing 2022-10-26 16:22:29 -07:00
jeffvli 8f82d001f0 Move types up 2022-10-26 16:21:51 -07:00
jeffvli 6763f4439d Update package name references 2022-10-26 16:13:32 -07:00
jeffvli 1622c12dfa Update server management 2022-10-26 16:12:57 -07:00
jeffvli 02e3b96384 Update titlebar 2022-10-26 16:12:18 -07:00
jeffvli c4765ba2d1 Add permissions check hook 2022-10-26 16:06:22 -07:00
jeffvli 1f261a95ad Update default routing 2022-10-26 16:05:58 -07:00
jeffvli cf17ce6e9d Update login flow 2022-10-26 16:04:39 -07:00
jeffvli 146a03cb3c Update package name 2022-10-26 15:59:33 -07:00
jeffvli f8e1a7d79e Update base components 2022-10-26 15:59:18 -07:00
jeffvli dc891e1b79 Set project name to feishin 2022-10-25 16:54:23 -07:00
jeffvli 0438f2d5f2 Move server directory outside of frontend src 2022-10-25 16:52:45 -07:00
jeffvli 863dce88b7 Add local settings 2022-10-24 22:38:06 -07:00
jeffvli f09abdb4c6 Update styles 2022-10-24 22:34:13 -07:00
jeffvli 781adb7c4d Update libs 2022-10-24 22:30:49 -07:00
jeffvli dd3de66232 Update player/shared components 2022-10-24 22:30:16 -07:00
jeffvli 8973571147 Update store/routes 2022-10-24 22:20:35 -07:00
jeffvli f8e7d02daf Update frontend base 2022-10-24 22:19:52 -07:00
jeffvli 921c688c94 Update utils 2022-10-24 22:09:58 -07:00
jeffvli 663b951cd7 Set jsxImportSource 2022-10-24 22:01:34 -07:00
jeffvli d4e4bdb858 Add lint rules 2022-10-24 22:01:23 -07:00
jeffvli 33e4526caa Update packages 2022-10-24 22:01:02 -07:00
jeffvli df3418120a Update base components 2022-10-24 21:56:58 -07:00
jeffvli dfdf53f6ee Update login 2022-10-24 21:47:18 -07:00
jeffvli d5bbff5eb6 Update frontend API structure 2022-10-24 21:47:03 -07:00
jeffvli 76b6eed4bb Update scanner imports 2022-10-24 21:42:15 -07:00
jeffvli 4a3ce02805 Redo server functionality 2022-10-24 21:41:47 -07:00
jeffvli db8a7d6a63 Update passport/prisma libs 2022-10-24 21:28:22 -07:00
jeffvli c09e9b6583 Add tsconfig-paths 2022-10-24 21:27:00 -07:00
jeffvli 730b72e64f Update initial schema 2022-10-24 21:25:51 -07:00
jeffvli 3aab920c71 Cleanup packages and structure
- Remove unused packages
- Swap styled-components for emotion/styled
- Add tsconfig baseUrl and src path
- Upgrade and add mantine packages
2022-10-19 21:23:31 -07:00
jeffvli 9675fd1d8e Remove unused packages 2022-10-19 21:21:09 -07:00
jeffvli 3e80f71833 Remove unused utils 2022-10-18 18:52:40 -07:00
jeffvli 9424203960 Add serverCredentials to passport user output 2022-10-18 01:46:41 -07:00
jeffvli 27b4b36cbf Add validations, req.authUser 2022-10-18 01:45:46 -07:00
jeffvli 238c90478e Reset schema and migrations 2022-10-17 20:02:29 -07:00
jeffvli a0c634da2f Update validation middleware
- Move to separate directory
- Add TypedRequest utility fn
- Utilize as middleware instead of function
2022-10-16 02:29:28 -07:00
jeffvli 7b55ca2fa8 Remove unused 2022-10-14 20:34:23 -07:00
jeffvli e2808e0bd4 Update scanners 2022-10-14 20:26:53 -07:00
jeffvli 5f844ef975 Set many album artists 2022-10-14 19:57:08 -07:00
jeffvli 968e80a6d8 Update subsonic scanner for new schema 2022-10-12 20:47:23 -07:00
jeffvli 0772566637 Set size to int 2022-10-12 18:21:51 -07:00
jeffvli 99f30439e1 Add server scripts 2022-10-12 13:52:50 -07:00
jeffvli 6433ccd750 Set error message optional 2022-10-12 13:52:44 -07:00
jeffvli ea2d3ea8f1 Adjust route structure
- Items now accessed through servers/:serverId
- Auth middleware blanketly applied on routes
- Merge params on routes
2022-10-12 13:52:35 -07:00
jeffvli 21bf5ce523 Bump server packages 2022-10-12 13:52:29 -07:00
jeffvli 95421698da Remove hard-coded types
- Use auto-generated prisma types
2022-10-12 13:52:22 -07:00
jeffvli 02ef79dcb2 Optimize jellyfin scanner
- Include changes / unfinished subsonic scanner
2022-10-12 13:52:16 -07:00
jeffvli 8aedd94033 Update auth object and middleware 2022-10-12 13:52:08 -07:00
jeffvli b5c7abb566 Update schema and add initial migration 2022-10-12 13:52:00 -07:00
jeffvli 9d09b830f9 Add initial rest client files 2022-10-12 13:51:16 -07:00
jeffvli dd6b80795e Normalize types 2022-08-20 02:06:00 -07:00
jeffvli a087dbdea3 Add ag-grid package 2022-08-02 10:53:56 -07:00
jeffvli 3d677188b5 Fix initial volume 2022-08-02 10:47:12 -07:00
jeffvli d11051bbc1 Adjust album/song types 2022-08-02 10:45:27 -07:00
jeffvli e1bc6ecf30 Add queue handler
Initial support for play "now", "next", and "last"
2022-07-31 05:24:33 -07:00
jeffvli 9c9cf3a978 Add dnd-kit package 2022-07-31 02:14:54 -07:00
jeffvli e1977b291e Add basic development instructions 2022-07-30 19:31:32 -07:00
jeffvli c100bbb341 Linting, misc fixes 2022-07-30 19:31:14 -07:00
jeffvli bb4576390d Change TS import baseUrl 2022-07-30 17:44:57 -07:00
jeffvli df5f8c08f3 Remove boilerplate file 2022-07-30 16:57:30 -07:00
jeffvli 95ff874702 Swap tabler-icons for react-icons 2022-07-30 16:57:16 -07:00
jeffvli 1eed976747 Remove isScrolling 2022-07-30 16:27:47 -07:00
jeffvli fe422897ab Update dev docker deployment
Rename environment variables, add tokens
2022-07-30 15:47:06 -07:00
jeffvli bc86da7762 Update pagination request on client 2022-07-30 15:41:18 -07:00
jeffvli aa673ac854 Use skip/take cursors instead of page number 2022-07-30 15:28:30 -07:00
jeffvli b8cf1d8283 Disable no-shadow rule
Resolves a conflict with typescript enum values
2022-07-30 07:04:01 -07:00
jeffvli b9a171b096 Add filter functionality for infinite album list 2022-07-30 07:03:10 -07:00
jeffvli fa9cf2efda Migrate Mantine components to v5 2022-07-27 21:20:41 -07:00
jeffvli 34ee3222f4 Bump react to 18.2.0 2022-07-27 21:19:49 -07:00
jeffvli f13427022e add mantine dependency 2022-07-25 19:53:26 -07:00
jeffvli e8b612c974 add initial files 2022-07-25 19:40:16 -07:00
1035 changed files with 90053 additions and 94300 deletions
+3 -2
View File
@@ -1,3 +1,4 @@
node_modules
Dockerfile
docker-compose.*
release/app/node_modules
release/app/dist
server/node_modules
+6 -3
View File
@@ -1,9 +1,12 @@
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 4
indent_size = 2
end_of_line = lf
insert_final_newline = true
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
+7
View File
@@ -0,0 +1,7 @@
{
"rules": {
"no-console": "off",
"global-require": "off",
"import/no-dynamic-require": "off"
}
}
+59
View File
@@ -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;
+3
View File
@@ -0,0 +1,3 @@
/* eslint import/no-unresolved: off, import/no-self-import: off */
module.exports = require('./webpack.config.renderer.dev').default;
+84
View File
@@ -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);
+191
View File
@@ -0,0 +1,191 @@
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);
+140
View File
@@ -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);
+38
View File
@@ -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,
};
+1
View File
@@ -0,0 +1 @@
export default 'test-file-stub';
+8
View File
@@ -0,0 +1,8 @@
{
"rules": {
"no-console": "off",
"global-require": "off",
"import/no-dynamic-require": "off",
"import/no-extraneous-dependencies": "off"
}
}
+24
View File
@@ -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"'
)
);
}
+54
View File
@@ -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');
}
}
+16
View File
@@ -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);
}
}
+16
View File
@@ -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);
}
});
+17
View File
@@ -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);
}
});
+8
View File
@@ -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'));
}
+20
View File
@@ -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',
});
}
+9
View File
@@ -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');
}
+30
View File
@@ -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,
});
};
+34
View File
@@ -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
+82
View File
@@ -0,0 +1,82 @@
module.exports = {
extends: ['erb', 'plugin:typescript-sort-keys/recommended'],
ignorePatterns: ['.erb/*', 'server'],
parser: '@typescript-eslint/parser',
parserOptions: {
createDefaultProgram: true,
ecmaVersion: 2020,
project: './tsconfig.json',
sourceType: 'module',
tsconfigRootDir: __dirname,
},
plugins: ['@typescript-eslint', 'import', 'sort-keys-fix'],
root: true,
rules: {
'@typescript-eslint/naming-convention': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-shadow': ['off'],
'import/extensions': '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',
'react/jsx-props-no-spreading': 'off',
'react/jsx-sort-props': [
'error',
{
callbacksLast: true,
ignoreCase: false,
noSortAlphabetically: false,
reservedFirst: true,
shorthandFirst: true,
shorthandLast: false,
},
],
// Since React 17 and typescript 4.1 you can safely disable the rule
'react/react-in-jsx-scope': '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: {},
webpack: {
config: require.resolve('./.erb/configs/webpack.config.eslint.ts'),
},
},
},
};
-2
View File
@@ -1,3 +1 @@
# These are supported funding model platforms
ko_fi: jeffvli
@@ -1,33 +0,0 @@
name: Feature request
description: Request a feature to be added to Feishin
title: '[Feature]: '
labels: ['enhancement']
body:
- type: checkboxes
id: check-duplicate
attributes:
label: I have already checked through the existing feature requests and found no duplicates
options:
- label: 'Yes'
required: true
- type: dropdown
id: server-specific
attributes:
label: Is this a server-specific feature?
options:
- Not server-specific
- OpenSubsonic
- Jellyfin
- Navidrome
default: 0
validations:
required: true
- type: textarea
id: solution
attributes:
label: What do you want to be added?
placeholder: I would like to see [...]
validations:
required: true
-74
View File
@@ -1,74 +0,0 @@
name: Bug report
description: You're having technical issues.
title: '[Bug]: '
labels: ['bug']
body:
- type: checkboxes
id: check-duplicate
attributes:
label: I have already checked through the existing bug reports and found no duplicates
options:
- label: 'Yes'
required: true
- type: input
id: version
attributes:
label: App Version
description: What version of the app are you running?
placeholder: ex. 1.0.0
validations:
required: true
- type: input
id: server-version
attributes:
label: Music Server and Version
description: What music server are you using?
placeholder: ex. Navidrome v0.55.0, LMS v3.67.0, Jellyfin v10.10.7, etc.
validations:
required: true
- type: dropdown
id: environments
attributes:
label: What local environments are you seeing the problem on?
multiple: true
options:
- Desktop Windows
- Desktop macOS
- Desktop Linux
- Web Firefox
- Web Chrome
- Web Safari
- Web Microsoft Edge
- Other (please specify in the next field)
- type: textarea
id: what-happened
attributes:
label: What happened?
description: Also tell us, what did you expect to happen?
placeholder: Include screenshots and error logs if possible. The browser devtools can be opened using CTRL + SHIFT + I (Windows/Linux) or CMD + SHIFT + I (macOS).
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: Steps to reproduce
description: How can we reproduce this issue? Are there any specific settings that are enabled that could be the cause?
placeholder: |
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
validations:
required: true
- type: textarea
id: logs
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output. This will be automatically formatted into code.
render: shell
+67
View File
@@ -0,0 +1,67 @@
---
name: Bug report
about: You're having technical issues. 🐞
labels: 'bug'
---
<!-- Please use the following issue template or your issue will be closed -->
## Prerequisites
<!-- If the following boxes are not ALL checked, your issue is likely to be closed -->
- [ ] Using npm
- [ ] Using an up-to-date [`main` branch](https://github.com/electron-react-boilerplate/electron-react-boilerplate/tree/main)
- [ ] Using latest version of devtools. [Check the docs for how to update](https://electron-react-boilerplate.js.org/docs/dev-tools/)
- [ ] Tried solutions mentioned in [#400](https://github.com/electron-react-boilerplate/electron-react-boilerplate/issues/400)
- [ ] For issue in production release, add devtools output of `DEBUG_PROD=true npm run build && npm start`
## Expected Behavior
<!--- What should have happened? -->
## Current Behavior
<!--- What went wrong? -->
## 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? -->
<!--- Did you make any changes to the boilerplate after cloning it? -->
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
## Your Environment
<!--- Include as many relevant details about the environment you experienced the bug in -->
- Node version :
- electron-react-boilerplate version or branch :
- Operating System and version :
- Link to your project :
<!---
❗️❗️ Also, please consider donating (https://opencollective.com/electron-react-boilerplate-594) ❗️❗️
Donations will ensure the following:
🔨 Long term maintenance of the project
🛣 Progress on the roadmap
🐛 Quick responses to bug reports and help requests
-->
+19
View File
@@ -0,0 +1,19 @@
---
name: Question
about: Ask a question.❓
labels: 'question'
---
## Summary
<!-- What do you need help with? -->
<!---
❗️❗️ Also, please consider donating (https://opencollective.com/electron-react-boilerplate-594) ❗️❗️
Donations will ensure the following:
🔨 Long term maintenance of the project
🛣 Progress on the roadmap
🐛 Quick responses to bug reports and help requests
-->
@@ -0,0 +1,15 @@
---
name: Feature request
about: You want something added to the boilerplate. 🎉
labels: 'enhancement'
---
<!---
❗️❗️ Also, please consider donating (https://opencollective.com/electron-react-boilerplate-594) ❗️❗️
Donations will ensure the following:
🔨 Long term maintenance of the project
🛣 Progress on the roadmap
🐛 Quick responses to bug reports and help requests
-->
-11
View File
@@ -1,11 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Questions or help
url: https://github.com/jeffvli/feishin/discussions
about: Ask questions or get help in the discussions section
- name: Discord Community
url: https://discord.gg/FVKpcMDy5f
about: The discord/matrix servers are bridged so you can join whichever you prefer
- name: Matrix Community
url: https://matrix.to/#/#sonixd:matrix.org
about: The discord/matrix servers are bridged so you can join whichever you prefer
+5 -5
View File
@@ -1,6 +1,6 @@
requiredHeaders:
- Prerequisites
- Expected Behavior
- Current Behavior
- Possible Solution
- Your Environment
- Prerequisites
- Expected Behavior
- Current Behavior
- Possible Solution
- Your Environment
+5 -5
View File
@@ -4,14 +4,14 @@ daysUntilStale: 60
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- discussion
- security
- 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.
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
-55
View File
@@ -1,55 +0,0 @@
# Referenced from: https://docs.github.com/en/actions/publishing-packages/publishing-docker-images#introduction
name: Publish Docker to GHCR
permissions: write-all
on:
workflow_dispatch:
push:
tags:
- 'v*.*.*'
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push-image:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v3
- name: Build and push Docker image
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: |
linux/amd64
linux/arm/v7
linux/arm64/v8
-44
View File
@@ -1,44 +0,0 @@
# Referenced from: https://docs.github.com/en/actions/publishing-packages/publishing-docker-images#introduction
name: Publish Docker to GHCR (Manual)
on: workflow_dispatch
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push-image:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v3
- name: Build and push Docker image
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: |
linux/amd64
linux/arm/v7
linux/arm64/v8
-49
View File
@@ -1,49 +0,0 @@
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 PNPM
uses: pnpm/action-setup@v4
with:
version: 9
- name: Install dependencies
run: pnpm install
- name: Build and 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: |
pnpm run package:linux
pnpm run publish:linux
on_retry_command: pnpm cache delete
- name: Build and Publish releases (arm64)
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
uses: nick-invision/retry@v2.8.2
with:
timeout_minutes: 30
max_attempts: 3
retry_on: error
command: |
pnpm run package:linux-arm64
pnpm run publish:linux-arm64
on_retry_command: pnpm cache delete
-36
View File
@@ -1,36 +0,0 @@
name: Publish 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 PNPM
uses: pnpm/action-setup@v4
with:
version: 9
- name: Install dependencies
run: pnpm install
- name: Build and 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: |
pnpm run package:mac
pnpm run publish:mac
on_retry_command: pnpm cache delete
-54
View File
@@ -1,54 +0,0 @@
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);
}
-93
View File
@@ -1,93 +0,0 @@
name: Publish (PR)
on:
pull_request:
branches:
- development
jobs:
publish:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
steps:
- name: Checkout git repo
uses: actions/checkout@v3
- name: Install Node and PNPM
uses: pnpm/action-setup@v4
with:
version: 9
- name: Install dependencies
run: pnpm install
- name: Build for Windows
if: ${{ matrix.os == 'windows-latest' }}
uses: nick-invision/retry@v2.8.2
with:
timeout_minutes: 30
max_attempts: 3
retry_on: error
command: |
pnpm run package:win:pr
- name: Build for Linux
if: ${{ matrix.os == 'ubuntu-latest' }}
uses: nick-invision/retry@v2.8.2
with:
timeout_minutes: 30
max_attempts: 3
retry_on: error
command: |
pnpm run package:linux:pr
- name: Build for MacOS
if: ${{ matrix.os == 'macos-latest' }}
uses: nick-invision/retry@v2.8.2
with:
timeout_minutes: 30
max_attempts: 3
retry_on: error
command: |
pnpm run package:mac:pr
- name: Zip Windows Binaries
if: ${{ matrix.os == 'windows-latest' }}
shell: pwsh
run: |
Compress-Archive -Path "dist/*.exe" -DestinationPath "dist/windows-binaries.zip" -Force
- name: Zip Linux Binaries
if: ${{ matrix.os == 'ubuntu-latest' }}
run: |
zip -r dist/linux-binaries.zip dist/*.{AppImage,deb,rpm}
- name: Zip MacOS Binaries
if: ${{ matrix.os == 'macos-latest' }}
run: |
zip -r dist/macos-binaries.zip dist/*.dmg
- name: Upload Windows Binaries
if: ${{ matrix.os == 'windows-latest' }}
uses: actions/upload-artifact@v4
with:
name: windows-binaries
path: dist/windows-binaries.zip
- name: Upload Linux Binaries
if: ${{ matrix.os == 'ubuntu-latest' }}
uses: actions/upload-artifact@v4
with:
name: linux-binaries
path: dist/linux-binaries.zip
- name: Upload MacOS Binaries
if: ${{ matrix.os == 'macos-latest' }}
uses: actions/upload-artifact@v4
with:
name: macos-binaries
path: dist/macos-binaries.zip
-36
View File
@@ -1,36 +0,0 @@
name: Publish Windows (Manual)
on: workflow_dispatch
jobs:
publish:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [windows-latest]
steps:
- name: Checkout git repo
uses: actions/checkout@v1
- name: Install Node and PNPM
uses: pnpm/action-setup@v4
with:
version: 9
- name: Install dependencies
run: pnpm install
- name: Build and 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: |
pnpm run package:win
pnpm run publish:win
on_retry_command: pnpm cache delete
+39
View File
@@ -0,0 +1,39 @@
name: Publish (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 --linux
on_retry_command: npm cache clean --force
-47
View File
@@ -1,47 +0,0 @@
name: 'Close stale issues and PRs'
on:
workflow_dispatch:
schedule:
- cron: '30 1 * * *'
permissions:
contents: read
jobs:
stale:
permissions:
issues: write
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v5
with:
process-only: 'issues, prs'
issue-inactive-days: 120
pr-inactive-days: 120
log-output: true
add-issue-labels: 'frozen-due-to-age'
add-pr-labels: 'frozen-due-to-age'
- uses: actions/stale@v9
with:
operations-per-run: 999
days-before-issue-stale: 180
days-before-pr-stale: 180
days-before-issue-close: 30
days-before-pr-close: 30
stale-issue-message: >
This issue has been automatically marked as stale because it has not had recent activity. The resources of the Feishin team are limited, and so we are asking for your help.
If this is a **bug** and you can still reproduce this error on the <code>development</code> branch, please reply with all of the information you have about it in order to keep the issue open.
This issue will automatically be closed in the near future if no further activity occurs. Thank you for all your contributions.
stale-pr-message: >
This PR has been automatically marked as stale because it has not had recent activity. The resources of the Feishin team are limited, and so we are asking for your help.
This PR will automatically be closed in the near future if no further activity occurs. Thank you for all your contributions.
stale-issue-label: 'stale'
exempt-issue-labels: 'enhancement,keep,security'
stale-pr-label: 'stale'
exempt-pr-labels: 'keep,security'
+24 -16
View File
@@ -3,24 +3,32 @@ name: Test
on: [push, pull_request]
jobs:
release:
runs-on: ${{ matrix.os }}
release:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
strategy:
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
steps:
- name: Check out Git repository
uses: actions/checkout@v1
steps:
- name: Check out Git repository
uses: actions/checkout@v1
- name: Install Node.js and PNPM
uses: pnpm/action-setup@v4
with:
version: 9
- name: Install Node.js and NPM
uses: actions/setup-node@v2
with:
node-version: 16
cache: npm
- name: Install dependencies
run: pnpm install
- name: npm install
run: |
npm install --legacy-peer-deps
- name: Lint Files
run: pnpm run lint
- name: npm test
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
npm run package
npm run lint
npm exec tsc
npm test
+30 -6
View File
@@ -1,7 +1,31 @@
node_modules
dist
out
.DS_Store
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
# Coverage directory used by tools like istanbul
coverage
.eslintcache
*.log*
release
# 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
release/app/dist
release/build
.erb/dll
.idea
npm-debug.log.*
*.css.d.ts
*.sass.d.ts
*.scss.d.ts
.env*
+4
View File
@@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx lint-staged
-2
View File
@@ -1,2 +0,0 @@
legacy-peer-deps=true
only-built-dependencies=electron,esbuild
-6
View File
@@ -1,6 +0,0 @@
out
dist
pnpm-lock.yaml
LICENSE.md
tsconfig.json
tsconfig.*.json
+8
View File
@@ -0,0 +1,8 @@
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"printWidth": 100,
"arrowParens": "always"
}
-14
View File
@@ -1,14 +0,0 @@
singleQuote: true
semi: true
printWidth: 100
tabWidth: 4
trailingComma: all
useTabs: false
arrowParens: always
proseWrap: never
htmlWhitespaceSensitivity: strict
endOfLine: lf
singleAttributePerLine: false
bracketSpacing: true
plugins:
- prettier-plugin-packagejson
+28 -16
View File
@@ -1,19 +1,31 @@
{
"extends": [
"stylelint-config-standard",
"stylelint-config-css-modules",
"stylelint-config-recess-order"
"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
}
],
"rules": {
"block-no-empty": null,
"selector-type-case": ["lower", { "ignoreTypes": ["/^\\$\\w+/"] }],
"selector-type-no-unknown": [true, { "ignoreTypes": ["/-styled-mixin/", "/^\\$\\w+/"] }],
"declaration-block-no-shorthand-property-overrides": null,
"declaration-block-no-redundant-longhand-properties": null,
"at-rule-no-unknown": [true, { "ignoreAtRules": ["mixin", "value"] }],
"function-no-unknown": [true, { "ignoreFunctions": ["darken", "alpha", "lighten"] }],
"declaration-property-value-no-unknown": null,
"no-descending-specificity": null,
"no-empty-source": null
}
"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
}
}
+6 -1
View File
@@ -1,3 +1,8 @@
{
"recommendations": ["dbaeumer.vscode-eslint"]
"recommendations": [
"dbaeumer.vscode-eslint",
"EditorConfig.EditorConfig",
"stylelint.vscode-stylelint",
"esbenp.prettier-vscode"
]
}
+14 -23
View File
@@ -2,38 +2,29 @@
"version": "0.2.0",
"configurations": [
{
"name": "Debug Main Process",
"name": "Electron: Main",
"type": "node",
"request": "launch",
"cwd": "${workspaceRoot}",
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite",
"windows": {
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite.cmd"
},
"runtimeArgs": ["--sourcemap"],
"env": {
"REMOTE_DEBUGGING_PORT": "9222"
}
"protocol": "inspector",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run start:main --inspect=5858 --remote-debugging-port=9223"
],
"preLaunchTask": "Start Webpack Dev"
},
{
"name": "Debug Renderer Process",
"port": 9222,
"request": "attach",
"name": "Electron: Renderer",
"type": "chrome",
"webRoot": "${workspaceFolder}/src/renderer",
"timeout": 60000,
"presentation": {
"hidden": true
}
"request": "attach",
"port": 9223,
"webRoot": "${workspaceFolder}",
"timeout": 15000
}
],
"compounds": [
{
"name": "Debug All",
"configurations": ["Debug Main Process", "Debug Renderer Process"],
"presentation": {
"order": 1
}
"name": "Electron: All",
"configurations": ["Electron: Main", "Electron: Renderer"]
}
]
}
+49 -78
View File
@@ -1,83 +1,54 @@
{
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
"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
},
"rest-client.environmentVariables": {
"$shared": {
"host": "http://localhost:9321"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
"dev-user": {
"token": "",
"refreshToken": "",
"authUsername": "user",
"authPassword": "user"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"files.associations": {
".eslintrc": "jsonc",
".prettierrc": "jsonc",
".eslintignore": "ignore"
},
"eslint.validate": ["typescript", "typescriptreact"],
"eslint.workingDirectories": [
{ "directory": "./", "changeProcessCWD": true },
],
"typescript.tsserver.experimental.enableProjectDiagnostics": false,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.fixAll.stylelint": "explicit",
"source.organizeImports": "never",
"source.formatDocument": "explicit"
},
"css.validate": true,
"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,
"out/**/*": true,
"dist/**/*": true
},
"i18n-ally.localesPaths": ["src/i18n", "src/i18n/locales"],
"typescript.tsdk": "node_modules\\typescript\\lib",
"typescript.preferences.importModuleSpecifier": "non-relative",
"stylelint.config": null,
"stylelint.validate": ["css", "postcss"],
"typescript.updateImportsOnFileMove.enabled": "always",
"typescript.preferences.autoImportFileExcludePatterns": [
"@mantine/core",
"@mantine/modals",
"@mantine/dates"
],
"[typescriptreact]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
"typescript.format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": true,
"folderTemplates.structures": [
{
"name": "TypeScript Feature Component With CSS Modules",
"omitParentDirectory": true,
"structure": [
{
"fileName": "<FTName | kebabcase>.tsx",
"template": "Functional Component with CSS Modules"
},
{
"fileName": "<FTName | kebabcase>.module.css"
}
]
}
],
"folderTemplates.fileTemplates": {
"Functional Component with CSS Modules": [
"import styles from './<FTName | kebabcase>.module.css';",
"",
"interface <FTName | pascalcase>Props {}",
"",
"export const <FTName | pascalcase> = ({}: <FTName | pascalcase>Props) => {",
" return <div></div>;",
"};"
]
"dev-admin": {
"token": "",
"refreshToken": "",
"authUsername": "admin",
"authPassword": "admin"
}
},
"i18n-ally.localesPaths": ["src/i18n", "src/i18n/locales"],
"typescript.tsdk": "node_modules\\typescript\\lib"
}
+25
View File
@@ -0,0 +1,25 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"label": "Start Webpack Dev",
"script": "start:renderer",
"options": {
"cwd": "${workspaceFolder}"
},
"isBackground": true,
"problemMatcher": {
"owner": "custom",
"pattern": {
"regexp": "____________"
},
"background": {
"activeOnStart": true,
"beginsPattern": "Compiling\\.\\.\\.$",
"endsPattern": "(Compiled successfully|Failed to compile)\\.$"
}
}
}
]
}
+582 -1
View File
@@ -2,4 +2,585 @@
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).
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).
[0.15.0] - 2022-04-13
### Added
- Added setting to save and resume the current queue between sessions (#130) (Thanks @kgarner7)
- Added a simple "play random" button to the player bar (#276)
- Added new seek/volume sliders (#272)
- Seeking/dragging is now more responsive
- Added improved discord rich presence (#286)
- Added download button on the playlist view (#266)
- (Jellyfin) Added "genre" column to the artist list
### Changed
- Swapped the order of "Seek Forward/Backward" and "Next/Prev Track" buttons on the player bar
- Global volume is now calculated logarithmically (#275) (Thanks @gelaechter)
- "Auto playlist" is now named "Play Random" (#276)
- "Now playing" option is now available on the "Start page" setting
### Fixed
- Playing songs by double clicking on a list should now play in the proper order (#279)
- (Linux) Fixed MPRIS metadata not updating when player automatically increments (#263)
- Application fonts now loaded locally instead of from Google CDN (#284)
- Enabling "Default to Album List on Artist Page" no longer performs a double redirect when entering the artist page (#271)
- Stop button is no longer disabled when playback is stopped (#273)
- Various package updates (#288) (Thanks @kgarner7)
- Top control bar show no longer be accessible when not logged in (#267)
[0.14.0] - 2022-03-12
### Added
- Added zoom options via hotkeys (#252)
- Zoom in: CTRL + SHIFT + =
- Zoom out: CTRL + SHIFT + -
- Added PLAY context menu options to the Genre view (#239)
- Added STOP button to the main player controls (#252)
- Added "System Notifications" option to display native notifications when the song automatically changes (#245)
- Added arm64 build (#238)
- New languages
- Spanish (Thanks @ami-sc) (#250)
- Sinhala (Thanks @hirusha-adi) (#254)
### Fixed
- (Jellyfin) Fixed the order of returned songs when playing from the Folder view using the context menu (#240)
- (Linux) Reset MPRIS position to 0 when using "previous track" resets the song 0 (#249)
- Fixed JavaScript error when removing all songs from the queue using the context menu (#248)
- Fixed Ampache server support by adding .view to all Subsonic API endpoints (#253)
### Removed
- (Windows) Removed the cover art display when hovering Sonixd on the taskbar (due to new sidebar position) (#242)
[0.13.1] - 2022-02-16
### Fixed
- Fixed startup crash on all OS if the default settings file is not present (#237)
[0.13.0] - 2022-02-16
### Added
- Added new searchbar and search UI (#227, #228)
- Added playback controls to the Sonixd tray menu (#225)
- Added playlist selections to the `Start Page` config option
### Changed
- Sidebar changes (#206)
- Allow resizing of the sidebar when expanded
- Allow a toggle of the playerbar's cover art to the sidebar when expanded
- Display playlist list on the sidebar under the navigation
- Allow configuration of the display of sidebar elements
- Changed the `Artist` row on the playerbar to use a comma delimited list of the song's artists rather than the album artist (#218)
### Fixed
- Fixed the player volume not resetting to its default value when resetting a song while crossfading (#228)
- (Jellyfin) Fixed artist list not displaying user favorites
- (Jellyfin) Fixed `bitrate` column not properly by its numeric value (#220)
- Fixed javascript exception when incrementing/decrementing the queue (#230)
- Fixed popups/tooltips not using the configured font
[0.12.1] - 2022-02-02
### Fixed
- Fixed translation syntax error causing application to crash when deleting playlists from the context menu (#216)
- Fixed Player behavior (#217)
- No longer scrobbles an additional time after the last song ends when repeat is off
- (Jellyfin) Properly handles scrobbling the player's pause/resume and time position
[0.12.0] - 2022-01-31
### Added
- Added support for language/translations (#146) (Thanks @gelaechter)
- German translation added (Thanks @gelaechter)
- Simplified Chinese translation added (Thanks @fangxx3863)
- (Windows) Added media keys with desktop overlay (#79) (Thanks @GermanDarknes)
- (Subsonic) Added support for `/getLyrics` to display the current song's lyrics in a popup (#151)
- (Jellyfin) Added song list page
- Added config to choose the default Album/Song list sort on startup (#169)
- Added config to choose the application start page (#176) (Thanks @GermanDarknes)
- Added config for pagination for Album/Song list pages
- (Windows) Added option to set custom directory on installation (#184)
- Added config to set the default artist page to the album list (#199)
- Added info mode for the Now Playing page (#160)
- Added release notes popup
### Changed
- Player behavior
- `Media Stop` now stops the track and resets it instead of clearing the queue (#200)
- `Media Prev` now resets to the start of the song if pressed after 5 seconds (#207)
- `Media Prev` now resets to the start of the song if repeat is off and is the first song of the queue (#207)
- `Media Next` now does nothing if repeat is off and is the last song of the queue (#207)
- Playing a single track in the queue without repeat no longer plays the track twice (#205)
- Scrobbling
- (Jellyfin) Scrobbling has been reverted to use the `/sessions/playing` endpoint to support the Playback Reporting plugin (#187)
- Scrobbling occurs after 5 seconds has elapsed for the current track as to not instantly mark the song as played
- Pressing `CTRL + F` or the search button now focuses the text in the searchbar (#203) (Thanks @WeekendWarrior1)
- Changed loading indicators for all pages
- OBS scrobble now outputs an image.txt file instead of the downloading the cover image (#136)
- Player Bar
- Album name now appears under the artist
- (Subsonic) 5-star rating is available
- Clicking on the cover art now displays a full-size image
- Clicking on the song name now redirects to the Now Playing queue
- (Jellyfin) Removed track limit for "Auto Playlist"
### Fixed
- (macOS) Fixed macOS exit behavior (#198) (Thanks @zackslash)
- (Linux) Fixed MPRIS `position` result (#162)
- (Subsonic) Fixed artist page crashing the application if server does not support `/getArtistInfo2` (#170)
- (Jellyfin) Fixed `View all songs` returning songs out of their album track order
- (Jellyfin) Fixed the "Latest Albums" on the album artist page displaying no albums
- Fixed card overlay button color on click
- Fixed buttons on the Album page to work better with light mode
- Fixed unfavorite button on Album page
[0.11.0] - 2022-01-01
### Added
- Added external integrations
- Added Discord rich presence to display the currently playing song (#155)
- Added OBS (Open Broadcaster Software) scrobbling to send current track metadata to desktop or the Tuna plugin (#136)
- Added a `Native` option for Titlebar Style (#148) (Thanks @gelaechter)
- (Jellyfin) Added toggle to allow transcoding for non-directplay compatible filetypes (#158)
- Additional MPRIS support
- Added metadata:
- `albumArtist`, `discNumber`, `trackNumber`, `useCount`, `genre`
- Added events:
- `seek`, `position`, `volume`, `repeat`, `shuffle`
### Changed
- Overhauled the Artist page
- (Jellyfin) Split albums by album artist OR compilation
- (Jellyfin) Added artist genres
- (Subsonic) Added Top Songs section
- Moved related artists to the main page scrolling menu
- Added `View All Songs` button to view all songs by the artist
- Added artist radio (mix) button
- Horizontal scrolling menu no longer displays scrollbar
- Changed button styling on Playlist/Album/Artist pages
- Changed page image styling to use the card on Playlist/Album/Artist pages
### Fixed
- Fixed various MPRIS features
- Synchronized the play/pause state between the player and MPRIS client when pausing from Sonixd (#152)
- Fixed the identity of Sonixd to use the app name instead of description (#163)
- Fixed various submenus opening in the right-click context menu when the option is disabled (#164)
- Fixed compatibility with older Subsonic API servers (now targets Subsonic v1.13.0) (#144)
- Fixed playback causing heavily increased CPU/Power usage #145)
[0.10.0] - 2021-12-15
### Added
- Added 2 new default themes
- City Lights
- One Dark
- Added additional album filters (#66)
- Genres (AND/OR)
- Artists (AND/OR)
- Years (FROM/TO)
- Added external column sort filters for multiple pages (#66)
- Added item counter to page titles
- `Play Count` column has been added to albums (only works for Navidrome)
### Changed
- Config page has been fully refreshed to a new look
- Config popover on the action bar now includes all config tabs
- Tooltips
- Increased default tooltip delay from 250ms -> 500ms
- Increased tooltip delay on card overlay buttons to 1000ms
- Grid view
- Placeholder images for playlists, albums, and artists have been updated (inspired from Jellyfin Web UI)
- Card title/subtitle width decreased from 100% to default length
- Separate card info section from image/overlay buttons on hover
- Popovers (config, auto playlist, etc)
- Now have decreased opacity
- Enabling/disabling global media keys no longer requires app restart
### Fixed
- (Jellyfin) Fixed `Recently Played` and `Most Played` filters on the Dashboard page (#114)
- (Jellyfin) Fixed server scrobble (#126)
- No longer sends the `/playing` request on song start (prevents song being marked as played when it starts)
- Fixed song play count increasing multiple times per play
- (Jellyfin) Fixed tracks without embedded art displaying placeholder (#128)
- (Jellyfin) Fixed song `Path` property not displaying data
- (Subsonic) Fixed login check for Funkwhale servers (#135)
- Fixed persistent grid-view scroll position
- Fixed list-view columns
- `Visibility` column now properly displays data
- Selected media folder is now cleared from settings on disconnect (prevents errors when signing into a new server)
- Fixed adding/removing artist as favorite on the Artist page not updating
- Fixed search bar not properly handling Asian keyboard inputs
## [0.9.1] - 2021-12-07
### Changed
- List-view scroll position is now persistent for the following:
- Now Playing
- Playlist list
- Favorites (all)
- Album list
- Artist list
- Genre list
- Grid-view scroll position is now persistent for the following:
- Playlist list
- Favorites (album/artist)
- Album list
- Artist list
- (Jellyfin) Changed audio stream URL to force transcoding off (#108)
### Fixed
- (Jellyfin) Fixed the player not sending the "finish" condition when the song meets the scrobble condition (unresolved from 0.9.0) (#111)
## [0.9.0] - 2021-12-06
### Added
- Added 2 new default themes
- Plex-like
- Spotify-like
- Added volume control improvements
- Volume value tooltip while hovering the slider
- Mouse scroll wheel controls volume while hovering the slider
- Clicking the volume icon will mute/unmute
### Changed
- Overhauled all default themes
- Rounded buttons, inputs, etc.
- Changed grid card hover effects
- Removed hover scale
- Removed default background on overlay buttons
- Moved border to only the image instead of full card
- Album page
- Genre(s) are now listed on a line separate from the artists
- Album artist is now distinct from track artists
- Increased length of the genre/artist line from 70% -> 80%
- The genre/artist line is now scrollable using the mouse wheel
- (Jellyfin) List view
- `Artist` column now uses the album artist property
- `Title (Combined)` column now displays all track artists, comma-delimited instead of the album artist
- `Genre` column now displays all genres, comma-delimited, left-aligned
### Fixed
- (Jellyfin) Fixed the player not sending the "finish" condition when the song meets the scrobble condition
- (Jellyfin) Fixed album lists not sorting by the `genre` column
- (Jellyfin)(API) Fixed the A-Z(Artist) not sorting by Album Artist on the album list
- (Jellyfin)(API) Fixed auto playlist not respecting the selected music folder
- (Jellyfin)(API) Fixed the artist page not respecting the selected music folder
## [0.8.5] - 2021-11-25
### Fixed
- Fixed default (OOBE) title column not display data (#104)
## [0.8.4] - 2021-11-25
### Fixed
- (Jellyfin)(Linux) Fixed JS MPRIS error when switching tracks due to unrounded song duration
- (Linux) Fixed MPRIS artist, genre, and coverart not updating on track change
## [0.8.3] - 2021-11-25
### Fixed
- (Subsonic) Fixed playing a folder from the folder view
- Fixed rating context menu option available from the Genre page
## [0.8.2] - 2021-11-25
### Added
- Added option to disable auto updates
### Fixed
- Fixed gapless playback on certain \*sonic servers (#100)
- Fixed playerbar coverart not redirecting to `Now Playing` page
## [0.8.1] - 2021-11-24
### Fixed
- (Subsonic) Fixed errors blocking playlists from being deleted
## [0.8.0] - 2021-11-24
### Added
- Added Jellyfin server support (#87)
- Supports full Sonixd feature-set (except ratings)
- Added a mini config popover to change list/grid view options on the top action bar
- Added system audio device selector (#96)
- Added context menu option `Set rating` to bulk set ratings for songs (and albums/artists on Navidrome) (#95)
### Changed
- Reduced cached image from 500px -> 350px (to match max grid size)
- Grid/header images now respect image aspect ratio returned by the server
- Playback filter input now uses a regex validation before allowing you to add
- Renamed all `Name` columns to `Title`
- Search bar now clears after pressing enter to globally search
- Added borders to popovers
### Fixed
- Fixed application performance issues when player is crossfading to the next track
- Fixed null entries showing at the beginning of descending sort on playlist/now playing lists
- Tooltips no longer pop up on the artist/playlist description when null
## [0.7.0] - 2021-11-15
### Added
- Added download buttons on the Album and Artist pages (#29)
- Allows you to download (via browser) or copy download links to your clipboard (to use with a download manager)
### Changed
- Changed default tooltip delay from `500ms` -> `250ms`
- Moved search bar from page header to the main layout action bar
- Added notice for macOS media keys to require trusted accessibility in the client
### Fixed
- Fixed auto playlist and album fetch in Gonic servers
- Fixed the macOS titlebar styling to better match the original (#83)
- Fixed thumbnailclip error when resizing the application in macOS (#84)
- Fixed playlist page not using cached image
## [0.6.0] - 2021-11-09
### Added
- Added additional grid-view customization options (#74)
- Gap size (spaces between cards)
- Alignment (left-align, center-align)
### Changed
- Changed default album/artist uncached image sizes from `150px` -> `350px`
### Fixed
- (Windows) Fixed default taskbar thumbnail on Windows10 when minimized to use window instead of album cover (#73)
- Fixed playback settings unable to change via the UI
- Crossfade duration
- Polling interval
- Volume fade
- Fixed header styling on the Config page breaking at smaller window widths (#72)
- Fixed the position of the description tooltip on the Artist page
- Fixed the `Add to playlist` popover showing underneath the modal in modal-view
### Removed
- Removed unused `fonts.size.pageTitle` theme property
## [0.5.0] - 2021-11-05
### Added
- Added extensible theming (#60)
- Added playback presets (gapless, fade, normal) to the config
- Added persistence for column sort for all list-views (except playlist and search) (#47)
- Added playback filters to the config to filter out songs based on regex (#53)
- Added music folder selector in auto playlist (this may or may not work depending on your server)
- Added improved playlist, artist, and album pages
- Added dynamic images on the Playlist page for servers that don't support playlist images (e.g. Navidrome)
- Added link to open the local `settings.json` file
- Added setting to use legacy authentication (#63)
### Changed
- Improved overall application keyboard accessibility
- Playback no longer automatically starts if adding songs to the queue using `Add to queue`
- Prevent accidental page navigation when using [Ctrl/Shift + Click] when multi-selecting rows in list-view
- Standardized buttons between the Now Playing page and the mini player
- "Add random" renamed to "Auto playlist"
- Increased 'info' notification timeout from 1500ms -> 2000ms
- Changed default mini player columns to better fit
- Updated default themes to more modern standards (Default Dark, Default Light)
### Fixed
- Fixed title sort on the `Title (Combined)` column on the album list
- Fixed 2nd song in queue being skipped when using the "Play" button multiple pages (album, artist, auto playlist)
- Fixed `Title` column not showing the title on the Folder page (#69)
- Fixed context menu windows showing underneath the mini player
- Fixed `Add to queue (next)` adding songs to the wrong unshuffled index when shuffle is enabled
- Fixed local search on the root Folder page
- Fixed input picker dropdowns following the page on scroll
- Fixed the current playing song not highlighted when using `Add to queue` on an empty play queue
- Fixed artist list not using the `artistImageUrl` returned by Navidrome
## [0.4.1] - 2021-10-27
### Added
- Added links to the genre column on the list-view
- Added page forward/back buttons to main layout
### Changed
- Increase delay when completing mouse drag select in list view from `100ms` -> `200ms`
- Change casing for main application name `sonixd` -> `Sonixd`
### Fixed
- Fixed Linux media hotkey support (MPRIS)
- Added commands for additional events `play` and `pause` (used by KDE's media player overlay)
- Set status to `Playing` when initially starting a song
- Set current song metadata when track automatically changes instead of only when it manually changes
- Fixed filtered link to Album List on the Album page
- Fixed filtered link to Album List on the Dashboard page
- Fixed font color for lists/tables in panels
- Affects the search view song list and column selector list
## [0.4.0] - 2021-10-26
### Added
- Added music folder selector (#52)
- Added media hotkeys / MPRIS support for Linux (#50)
- This is due to dbus overriding the global shortcuts that electron sends
- Added advanced column selector component
- Drag-n-drop list
- Individual resizable columns
- (Windows) Added tray (Thanks @ncarmic4) (#45)
- Settings to minimize/exit to tray
### Changed
- Page selections are now persistent
- Active tab on config page
- Active tab on favorites page
- Filter selector on album list page
- Playlists can now be saved after being sorted using column filters
- Folder view
- Now shows all root folders in the list instead of in the input picker
- Now shows music folders in the input picker
- Now uses loader when switching pages
- Changed styling for various views/components
- Look & Feel setting page now split up into multiple panels
- Renamed context menu button `Remove from current` -> `Remove selected`
- Page header titles width increased from `45%` -> `80%`
- Renamed `Scan library` -> `Scan`
- All pages no longer refetch data when clicking back into the application
### Fixed
- Fixed shift-click multi select on a column-sorted list-view
- Fixed right-click context menu showing up behind all modals (#55)
- Fixed mini player showing up behind tag picker elements
- Fixed duration showing up as `NaN:NaN` when duration is null or invalid
- Fixed albums showing as a folder in Navidrome instances
## [0.3.0] - 2021-10-16
### Added
- Added folder browser (#1)
- Added context menu button `View in folder`
- Requires that your server has support for the original `/getIndexes` and `/getMusicDirectory` endpoints
- Added configurable row-hover highlight for list-view
- (Windows) Added playback controls in thumbnail toolbar (#32)
- (Windows/macOS) Added window size/position remembering on application close (#31)
### Changed
- Changed styling for various views/components
- Tooltips added on grid-view card hover buttons
- Mini-player removed rounded borders and increased opacity
- Mini-player removed animation on open/close
- Search bar now activated from button -> input on click / CTRL+F
- Page header toolbar buttons styling consistency
- Album list filter moved from right -> left
- Reordered context menu button `Move selected to [...]`
- Decreased horizontal width of expanded sidebar from 193px -> 165px
### Fixed
- Fixed duplicate scrobble requests when pause/resuming a song after the scrobble threshold (#30)
- Fixed genre column not applying in the song list-view
- Fixed default titlebar set on first run
## [0.2.1] - 2021-10-11
### Fixed
- Fixed using play buttons on the artist view not starting playback
- Fixed favoriting on horizontal scroll menu on dashboard/search views
- Fixed typo on default artist list viewtype
- Fixed artist image selection on artist view
## [0.2.0] - 2021-10-11
### Added
- Added setting to enable scrobbling playing/played tracks to your server (#17)
- Added setting to change between macOS and Windows styled titlebar (#23)
- Added app/build versions and update checker on the config page (#18)
- Added 'view in modal' button on the list-view context menu (#8)
- Added a persistent indicator on grid-view cards for favorited albums/artists (#7)
- Added buttons for 'Add to queue (next)' and 'Add to queue (later)' (#6)
- Added left/right scroll buttons to the horizontal scrolling menu (dashboard/search)
- Added last.fm link to artist page
- Added link to cache location to open in local file explorer
- Added reset to default for cache location
- Added additional tooltips
- Grid-view card title and subtitle buttons
- Cover art on the player bar
- Header titles on album/artist pages
### Changed
- Changed starring logic on grid-view card to update local cache instead of refetch
- Changed styling for various views/components
- Use dynamically sized hover buttons on grid-view cards depending on the card size
- Decreased size of buttons on album/playlist/artist pages
- Input picker text color changed from primary theme color to primary text color
- Crossfade type config changed from radio buttons to input picker
- Disconnect button color from red to default
- Tooltip styling updated to better match default theme
- Changed tag links to text links on album page
- Changed page header images to use cache (album/artist)
- Artist image now falls back to last.fm if no local image
### Fixed
- Fixed song & image caching (#16)
- Fixed set default artist list view type on first startup
## [0.1.0] - 2021-10-06
### Added
- Initial release
+46 -20
View File
@@ -1,25 +1,51 @@
# --- Builder stage
FROM node:23-alpine as builder
# Stage 1 - Build frontend
FROM node:16.5-alpine as ui-builder
WORKDIR /app
# Copy package.json first to cache node_modules
COPY package.json pnpm-lock.yaml .
RUN npm install -g pnpm
RUN pnpm install
# Copy code and build with cached modules
COPY . .
RUN pnpm run build:web
RUN npm install
RUN npm run build:renderer
RUN npm prune --production
RUN npm cache clean --force
RUN rm -rf /root/.cache
# --- Production stage
FROM nginx:alpine-slim
# Stage 2 - Build server
FROM node:16.5-alpine as server-builder
WORKDIR /app
COPY server .
RUN npm install && npx prisma generate
RUN npm run build
RUN npm prune --production
RUN npm cache clean --force
RUN rm -rf /root/.cache
COPY --chown=nginx:nginx --from=builder /app/out/web /usr/share/nginx/html
COPY ./settings.js.template /etc/nginx/templates/settings.js.template
COPY ng.conf.template /etc/nginx/templates/default.conf.template
ENV PUBLIC_PATH="/"
EXPOSE 9180
CMD ["nginx", "-g", "daemon off;"]
# Stage 3 - Deploy
FROM node:16.5-alpine
WORKDIR /root
RUN mkdir appdata
RUN mkdir feishin-server
RUN mkdir feishin-client
RUN npm cache clean --force
RUN npm prune --production
# Add server build files
COPY --from=server-builder /app/dist ./feishin-server
COPY --from=server-builder /app/node_modules ./feishin-server/node_modules
COPY --from=server-builder /app/prisma ./feishin-server/prisma
# Add client build files
COPY --from=ui-builder /app/release/app/dist/renderer ./feishin-client
COPY docker-entrypoint.sh ./feishin-server/docker-entrypoint.sh
RUN chmod +x ./feishin-server/docker-entrypoint.sh
COPY ./server/wait-for-it.sh ./feishin-server/wait-for-it.sh
RUN chmod +x ./feishin-server/wait-for-it.sh
RUN npm install pm2 -g
WORKDIR /root/feishin-server
EXPOSE 9321
CMD ["sh", "docker-entrypoint.sh"]
+115 -111
View File
@@ -1,5 +1,3 @@
<img src="assets/icons/icon.png" alt="logo" title="feishin" align="right" height="60px" width="60px" />
# Feishin
<p align="center">
@@ -7,7 +5,7 @@
<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">
<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>
@@ -15,6 +13,15 @@
<img src="https://img.shields.io/github/downloads/jeffvli/feishin/total?style=flat-square&color=orange"
alt="Downloads">
</a>
<a href="https://hub.docker.com/r/jeffvictorli/feishin">
<img src="https://img.shields.io/docker/v/jeffvictorli/feishin?style=flat-square&color=orange"
alt="Docker">
</a>
</a>
<a href="https://hub.docker.com/r/jeffvictorli/feishin">
<img src="https://img.shields.io/docker/pulls/jeffvictorli/feishin?style=flat-square&color=orange"
alt="Docker pulls">
</a>
</p>
<p align="center">
<a href="https://discord.gg/FVKpcMDy5f">
@@ -27,155 +34,152 @@
</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>
Repository for the rewrite of [Sonixd](https://github.com/jeffvli/sonixd).
## Getting Started
### Desktop (recommended)
The default credentials to login will be `admin/admin`.
Download the [latest desktop client](https://github.com/jeffvli/feishin/releases). The desktop client is the recommended way to use Feishin. It supports both the MPV and web player backends, as well as includes built-in fetching for lyrics.
Download the [latest desktop client](https://github.com/jeffvli/feishin/releases).
#### macOS Notes
### Docker Compose
If you're using a device running macOS 12 (Monterey) or higher, [check here](https://github.com/jeffvli/feishin/issues/104#issuecomment-1553914730) for instructions on how to remove the app from quarantine.
**Warning:** Check the environment variable configuration before running the commands below.
For media keys to work, you will be prompted to allow Feishin to be a Trusted Accessibility Client. After allowing, you will need to restart Feishin for the privacy settings to take effect.
1. Copy and rename [example.env](https://github.com/jeffvli/feishin/blob/dev/example.env) to `.env` and make any changes necessary
2. Run the compose file: `docker compose --file docker-compose.yml --env-file .env up`
### Web and Docker
### Docker
Visit [https://feishin.vercel.app](https://feishin.vercel.app) to use the hosted web version of Feishin. The web client only supports the web player backend.
**Warning:** Check the environment variable configuration before running the commands below.
Feishin is also available as a Docker image. The images are hosted via `ghcr.io` and are available to view [here](https://github.com/jeffvli/feishin/pkgs/container/feishin). You can run the container using the following commands:
**Run a postgres database container:**
```bash
# Run the latest version
docker run --name feishin -p 9180:9180 ghcr.io/jeffvli/feishin:latest
# Build the image locally
docker build -t feishin .
docker run --name feishin -p 9180:9180 feishin
```
docker run postgres:13 \
-p 5432:5432 \
-e POSTGRES_USER=admin \
-e POSTGRES_PASSWORD=admin \
-e POSTGRES_DB=feishin
```
#### Docker Compose
**Run the Feishin server container:**
To install via Docker Compose use the following snippit. This also works on Portainer.
```yaml
services:
feishin:
container_name: feishin
image: 'ghcr.io/jeffvli/feishin:latest'
environment:
- SERVER_NAME=jellyfin # pre defined server name
- SERVER_LOCK=true # When true AND name/type/url are set, only username/password can be toggled
- SERVER_TYPE=jellyfin # navidrome also works
- SERVER_URL= # http://address:port
- PUID=1000
- PGID=1000
- UMASK=002
- TZ=America/Los_Angeles
ports:
- 9180:9180
restart: unless-stopped
```
docker run jeffvictorli/feishin:latest \
-p 8643:9321 \
-e APP_BASE_URL=http://192.168.0.1:8643 \
-e DATABASE_PORT=5432 \
-e DATABASE_URL=postgresql://admin:admin@localhost:5432/feishin?schema=public \
-e TOKEN_SECRET=secret
```
### Configuration
**Docker Environment Variables**
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.
```
APP_BASE_URL — The URL the site will be accessible at from your server (needed for CORS)
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`).
DATABASE_PORT — The port of your running postgres container
- **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).
- **Linux users** - The default password store uses `libsecret`. `kwallet4/5/6` are also supported, but must be explicitly set in Settings > Window > Passwords/secret score.
DATABASE_URL — The connection string to your postgres instance following this format: postgresql://<DB_USERNAME>:<DB_PASSWORD>@<DB_URL>/<DB_NAME>?schema=public
3. _Optional_ - If you want to host Feishin on a subpath (not `/`), then pass in the following environment variable: `PUBLIC_PATH=PATH`. For example, to host on `/feishin`, pass in `PUBLIC_PATH=/feishin`.
Replace the following:
<DB_USERNAME> — The admin username of your postgres container (POSTGRES_USER)
<DB_PASSWORD> — The admin password of your postgres container (POSTGRES_PASSWORD)
<DB_NAME> — The name of the database created in your postgres container (POSTGRES_DB)
<DB_URL> — The URL the postgres container is reachable from
4. _Optional_ - To hard code the server url, pass the following environment variables: `SERVER_NAME`, `SERVER_TYPE` (one of `jellyfin` or `navidrome`), `SERVER_URL`. To prevent users from changing these settings, pass `SERVER_LOCK=true`. This can only be set if all three of the previous values are set.
Example: postgresql://admin:password@192.168.0.1:5432/feishin?schema=public
TOKEN_SECRET — The string used to sign auth tokens
(optional) TOKEN_EXPIRATION — The time before the auth JWT expires
(optional) TOKEN_REFRESH_EXPIRATION - The time before the auth JWT refresh token expires
```
### After installing the server and database
You can access the desktop client via the [latest release](https://github.com/jeffvli/feishin/releases), or you can visit the web client at your server URL (e.g http://192.168.0.1:8643).
## FAQ
### MPV is either not working or is rapidly switching between pause/play states
### Why is there a red lock next to the server I want to select?
First thing to do is check that your MPV binary path is correct. Navigate to the settings page and re-set the path and restart the app. If your issue still isn't resolved, try reinstalling MPV. Known working versions include `v0.35.x` and `v0.36.x`. `v0.34.x` is a known broken version.
If the server is specified to "require user credentials", you will need to add and enable your own credentials to access it. Since the songs and images aren't proxied by the Feishin backend, the server credentials would otherwise be leaked to any user that has access to it. The added credentials are stored locally in the browser and are then used to generate the audio and image URLs in the client.
### What music servers does Feishin support?
Feishin supports any music server that implements a [Navidrome](https://www.navidrome.org/), [Jellyfin](https://jellyfin.org/), or [OpenSubsonic compatible](https://opensubsonic.netlify.app/) API.
Feishin supports any music server that implements a [Subsonic](http://www.subsonic.org/pages/api.jsp), [Navidrome](https://www.navidrome.org/), or [Jellyfin](https://jellyfin.org/) API.
- [Navidrome](https://github.com/navidrome/navidrome)
- [Jellyfin](https://github.com/jellyfin/jellyfin)
- [OpenSubsonic](https://opensubsonic.netlify.app/) compatible servers, such as...
- [Airsonic-Advanced](https://github.com/airsonic-advanced/airsonic-advanced)
- [Ampache](https://ampache.org)
- [Astiga](https://asti.ga/)
- [Funkwhale](https://www.funkwhale.audio/)
- [Gonic](https://github.com/sentriz/gonic)
- [LMS](https://github.com/epoupon/lms)
- [Nextcloud Music](https://apps.nextcloud.com/apps/music)
- [Supysonic](https://github.com/spl0k/supysonic)
- [Qm-Music](https://github.com/chenqimiao/qm-music)
- More (?)
- [Navidrome](https://github.com/navidrome/navidrome)
- [Airsonic](https://github.com/airsonic/airsonic)
- [Airsonic-Advanced](https://github.com/airsonic-advanced/airsonic-advanced)
- [Gonic](https://github.com/sentriz/gonic)
- [Astiga](https://asti.ga/)
- [Supysonic](https://github.com/spl0k/supysonic)
### I have the issue "The SUID sandbox helper binary was found, but is not configured correctly" on Linux
### Why does Feishin use its own database and backend instead of just use (insert music server)'s API?
This happens when you have user (unprivileged) namespaces disabled (`sysctl kernel.unprivileged_userns_clone` returns 0). You can fix this by either enabling unprivileged namespaces, or by making the `chrome-sandbox` Setuid.
Feishin was an idea I had after I ran into usage limitations while building out [Sonixd](https://github.com/jeffvli/sonixd). Each music server has their own quirks, and I decided I wanted to consolidate and extend their features with my own backend implemntation which includes: web/desktop clients, advanced filtering, smart playlists, desktop MPV player, and more.
```bash
chmod 4755 chrome-sandbox
sudo chown root:root chrome-sandbox
```
### Can I use (insert database) instead of Postgresql?
Ubunutu 24.04 specifically introduced breaking changes that affect how namespaces work. Please see https://discourse.ubuntu.com/t/ubuntu-24-04-lts-noble-numbat-release-notes/39890#:~:text=security%20improvements%20 for possible fixes.
Due to [Prisma limitations](https://www.prisma.io/docs/concepts/components/prisma-migrate/prisma-migrate-limitations-issues#you-cannot-automatically-switch-database-providers), there is no easy way to switch to a different database provider at this time.
## Development
Built and tested using Node `v23.11.0`.
Built and tested using Node `v16.15.0`.
This project is built off of [electron-vite](https://github.com/alex8088/electron-vite)
This project is built off of [electron-react-boilerplate](https://github.com/electron-react-boilerplate/electron-react-boilerplate) v4.6.0.
- `pnpm run dev` - Start the development server
- `pnpm run dev:watch` - Start the development server in watch mode (for main / preload HMR)
- `pnpm run start` - Starts the app in production preview mode
- `pnpm run build` - Builds the app for desktop
- `pnpm run build:electron` - Build the electron app (main, preload, and renderer)
- `pnpm run build:remote` - Build the remote app (remote)
- `pnpm run build:web` - Build the standalone web app (renderer)
- `pnpm run package` - Package the project
- `pnpm run package:dev` - Package the project for development
- `pnpm run package:linux` - Package the project for Linux
- `pnpm run package:mac` - Package the project for Mac
- `pnpm run package:win` - Package the project for Windows
- `pnpm run publish:linux` - Publish the project for Linux
- `pnpm run publish:linux-arm64` - Publish the project for Linux ARM64
- `pnpm run publish:mac` - Publish the project for Mac
- `pnpm run publish:win` - Publish the project for Windows
- `pnpm run typecheck` - Type check the project
- `pnpm run typecheck:node` - Type check the project with tsconfig.node.json
- `pnpm run typecheck:web` - Type check the project with tsconfig.web.json
- `pnpm run lint` - Lint the project
- `pnpm run lint:fix` - Lint the project and fix linting errors
- `pnpm run i18next` - Generate i18n files
### Developing with Docker Compose
## Translation
1. Copy and rename the `example.env` to `.env.dev` and make any changes necessary
2. **Run the server**: Use `npm run docker:up` to build and run the dev server
1. Prisma studio available on `http://localhost:5555`
2. Server available on `http://localhost:8643`
3. Default seeded login credentials are `admin/admin`
3. **Run the client**: Use `npm run start` to run the development Electron client
1. The web version of the client is available on `http://localhost:4343`
This project uses [Weblate](https://hosted.weblate.org/projects/feishin/) for translations. If you would like to contribute, please visit the link and submit a translation.
**Docker Compose files**
```
docker-compose.yml — The public compose file for running the latest release
docker-compose.dev.yml - Build and run the development environment locally (includes Prisma studio)
docker-compose.prod.yml - Build and run the production environment locally
```
### NPM Scripts:
```
$ npm run package — Packages the application for the local system
$ npm run start — Runs the development Electron and web client
$ npm run start:web — Runs the development web client
$ npm run docker:up — Builds and starts the docker development environment using the 'docker-compose.dev.yml' file
$ npm run docker:down — Stops the running docker development environment
$ npm run docker:dbpush — Pushes any schema changes made in 'schema.prisma' to the docker development database without migrating
$ npm run docker:migrate - Migrates any schema changes made in 'schema.prisma' and creates a migration file
$ npm run docker:createmigrate - Creates a migration file for any schema changes made in 'schema.prisma' without applying the migration
$ npm run docker:reset - Resets the docker development database and applies the default seed
$ npm run prod:buildserver - Builds and tags the server docker images locally with the 'latest' and '$VERSION' tags
$ npm run prod:publishserver - Pushes the locally build server docker images to docker hub
```
## License
[GNU General Public License v3.0 ©](https://github.com/jeffvli/feishin/blob/dev/LICENSE)
[GNU General Public License v3.0 ©](https://github.com/jeffvli/sonixd-rewrite/blob/dev/LICENSE)
+12 -12
View File
@@ -1,31 +1,31 @@
type Styles = Record<string, string>;
declare module '*.svg' {
const content: string;
export default content;
const content: string;
export default content;
}
declare module '*.png' {
const content: string;
export default content;
const content: string;
export default content;
}
declare module '*.jpg' {
const content: string;
export default content;
const content: string;
export default content;
}
declare module '*.scss' {
const content: Styles;
export default content;
const content: Styles;
export default content;
}
declare module '*.sass' {
const content: Styles;
export default content;
const content: Styles;
export default content;
}
declare module '*.css' {
const content: Styles;
export default content;
const content: Styles;
export default content;
}
+1 -3
View File
@@ -2,11 +2,9 @@
<!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-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<key>com.apple.security.cs.allow-jit</key>
<true/>
</dict>
</plist>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 896 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 971 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 524 B

-3
View File
@@ -1,3 +0,0 @@
provider: generic
url: https://example.com/auto-updates
updaterCacheDirName: feishin-updater
+49
View File
@@ -0,0 +1,49 @@
version: '3'
services:
db:
container_name: feishin_db
image: postgres:13
volumes:
- ${DATABASE_PERSIST_PATH}:/var/lib/postgresql/data
environment:
- POSTGRES_USER=${DATABASE_USERNAME}
- POSTGRES_PASSWORD=${DATABASE_PASSWORD}
- POSTGRES_DB=${DATABASE_NAME}
ports:
- '${DATABASE_PORT}:5432'
restart: unless-stopped
server:
container_name: feishin_server
volumes:
- ./server:/app # Synchronise docker container with local change
- /app/node_modules # Avoid re-copying local node_modules. Cache in container.
build:
context: ./server
dockerfile: Dockerfile
depends_on:
- db
environment:
- APP_BASE_URL=${APP_BASE_URL}
- DATABASE_URL=postgresql://${DATABASE_USERNAME}:${DATABASE_PASSWORD}@db/${DATABASE_NAME}?schema=public&connection_limit=14&pool_timeout=20
- DATABASE_PORT=${DATABASE_PORT}
- TOKEN_SECRET=${TOKEN_SECRET}
- TOKEN_EXPIRATION=${TOKEN_EXPIRATION}
- TOKEN_REFRESH_EXPIRATION=${TOKEN_REFRESH_EXPIRATION}
ports:
- '8643:9321'
restart: unless-stopped
prisma:
container_name: feishin_prisma_studio
volumes:
- ./server/prisma:/app/prisma
build:
context: ./server/prisma
dockerfile: Dockerfile
depends_on:
- db
- server
environment:
- DATABASE_URL=postgresql://${DATABASE_USERNAME}:${DATABASE_PASSWORD}@db/${DATABASE_NAME}?schema=public
ports:
- '5555:5555'
restart: unless-stopped
+32
View File
@@ -0,0 +1,32 @@
version: '3'
services:
db:
container_name: feishin_db
image: postgres:13
volumes:
- ${DATABASE_PERSIST_PATH}:/var/lib/postgresql/data
environment:
- POSTGRES_USER=${DATABASE_USERNAME}
- POSTGRES_PASSWORD=${DATABASE_PASSWORD}
- POSTGRES_DB=${DATABASE_NAME}
ports:
- '${DATABASE_PORT}:5432'
restart: unless-stopped
server:
container_name: feishin
build:
context: .
dockerfile: Dockerfile
image: feishin
depends_on:
- db
environment:
- APP_BASE_URL=${APP_BASE_URL}
- DATABASE_URL=postgresql://${DATABASE_USERNAME}:${DATABASE_PASSWORD}@db/${DATABASE_NAME}?schema=public&connection_limit=14&pool_timeout=20
- DATABASE_PORT=${DATABASE_PORT}
- TOKEN_SECRET=${TOKEN_SECRET}
- TOKEN_EXPIRATION=${TOKEN_EXPIRATION}
- TOKEN_REFRESH_EXPIRATION=${TOKEN_REFRESH_EXPIRATION}
ports:
- '8643:9321'
restart: unless-stopped
-13
View File
@@ -1,13 +0,0 @@
version: '3.5'
services:
feishin:
container_name: feishin
image: ghcr.io/jeffvli/feishin:latest
restart: unless-stopped
ports:
- 9180:9180
environment:
- SERVER_NAME=jellyfin # pre defined server name
- SERVER_LOCK=true # When true AND name/type/url are set, only username/password can be toggled
- SERVER_TYPE=jellyfin # navidrome also works
- SERVER_URL= # http://address:port
+29
View File
@@ -0,0 +1,29 @@
version: '3'
services:
db:
container_name: feishin_db
image: postgres:13
volumes:
- ${DATABASE_PERSIST_PATH}:/var/lib/postgresql/data
environment:
- POSTGRES_USER=${DATABASE_USERNAME}
- POSTGRES_PASSWORD=${DATABASE_PASSWORD}
- POSTGRES_DB=${DATABASE_NAME}
ports:
- '${DATABASE_PORT}:5432'
restart: unless-stopped
server:
container_name: feishin
image: jeffvictorli/feishin:latest
depends_on:
- db
environment:
- APP_BASE_URL=${APP_BASE_URL}
- DATABASE_URL=postgresql://${DATABASE_USERNAME}:${DATABASE_PASSWORD}@db/${DATABASE_NAME}?schema=public&connection_limit=14&pool_timeout=20
- DATABASE_PORT=${DATABASE_PORT}
- TOKEN_SECRET=${TOKEN_SECRET}
- TOKEN_EXPIRATION=${TOKEN_EXPIRATION}
- TOKEN_REFRESH_EXPIRATION=${TOKEN_REFRESH_EXPIRATION}
ports:
- '8643:9321'
restart: unless-stopped
+5
View File
@@ -0,0 +1,5 @@
./wait-for-it.sh db:$1 --timeout=20 --strict -- echo "db is up"
npx prisma migrate deploy
npx ts-node prisma/seed.ts
pm2-runtime server.js
-49
View File
@@ -1,49 +0,0 @@
appId: org.jeffvli.feishin
productName: Feishin
artifactName: ${productName}-${version}-${os}-${arch}.${ext}
electronVersion: 35.1.5
directories:
buildResources: assets
files:
- 'out/**/*'
- 'package.json'
extraResources:
- assets/**
asarUnpack:
- resources/**
win:
target:
- zip
- nsis
icon: assets/icons/icon.png
nsis:
shortcutName: ${productName}
uninstallDisplayName: ${productName}
createDesktopShortcut: always
mac:
target:
target: default
arch:
- arm64
- x64
icon: assets/icons/icon.icns
type: distribution
hardenedRuntime: true
entitlements: assets/entitlements.mac.plist
entitlementsInherit: assets/entitlements.mac.plist
gatekeeperAssess: false
notarize: false
dmg:
contents: [{ x: 130, y: 220 }, { x: 410, y: 220, type: link, path: /Applications }]
linux:
target:
- AppImage
- tar.xz
category: AudioVideo;Audio;Player
icon: assets/icons/icon.png
artifactName: ${productName}-${os}-${arch}.${ext}
npmRebuild: false
publish:
provider: github
owner: jeffvli
repo: feishin
-66
View File
@@ -1,66 +0,0 @@
import react from '@vitejs/plugin-react';
import { externalizeDepsPlugin, UserConfig } from 'electron-vite';
import { resolve } from 'path';
import conditionalImportPlugin from 'vite-plugin-conditional-import';
import dynamicImportPlugin from 'vite-plugin-dynamic-import';
import { ViteEjsPlugin } from 'vite-plugin-ejs';
const currentOSEnv = process.platform;
const config: UserConfig = {
main: {
build: {
rollupOptions: {
external: ['source-map-support'],
},
sourcemap: true,
},
define: {
'import.meta.env.IS_LINUX': JSON.stringify(currentOSEnv === 'linux'),
'import.meta.env.IS_MACOS': JSON.stringify(currentOSEnv === 'darwin'),
'import.meta.env.IS_WIN': JSON.stringify(currentOSEnv === 'win32'),
},
plugins: [
externalizeDepsPlugin(),
dynamicImportPlugin(),
conditionalImportPlugin({
currentEnv: currentOSEnv,
envs: ['win32', 'linux', 'darwin'],
}),
],
resolve: {
alias: {
'/@/main': resolve('src/main'),
'/@/shared': resolve('src/shared'),
},
},
},
preload: {
plugins: [externalizeDepsPlugin()],
resolve: {
alias: {
'/@/preload': resolve('src/preload'),
'/@/shared': resolve('src/shared'),
},
},
},
renderer: {
css: {
modules: {
generateScopedName: 'fs-[name]-[local]',
localsConvention: 'camelCase',
},
},
plugins: [react(), ViteEjsPlugin({ web: false })],
resolve: {
alias: {
'/@/i18n': resolve('src/i18n'),
'/@/remote': resolve('src/remote'),
'/@/renderer': resolve('src/renderer'),
'/@/shared': resolve('src/shared'),
},
},
},
};
export default config;
-53
View File
@@ -1,53 +0,0 @@
import eslintConfigPrettier from '@electron-toolkit/eslint-config-prettier';
import tseslint from '@electron-toolkit/eslint-config-ts';
import perfectionist from 'eslint-plugin-perfectionist';
import eslintPluginReact from 'eslint-plugin-react';
import eslintPluginReactHooks from 'eslint-plugin-react-hooks';
import eslintPluginReactRefresh from 'eslint-plugin-react-refresh';
export default tseslint.config(
{ ignores: ['**/node_modules', '**/dist', '**/out'] },
tseslint.configs.recommended,
perfectionist.configs['recommended-natural'],
eslintPluginReact.configs.flat.recommended,
eslintPluginReact.configs.flat['jsx-runtime'],
{
settings: {
react: {
version: 'detect',
},
},
},
{
files: ['**/*.{ts,tsx}'],
plugins: {
'react-hooks': eslintPluginReactHooks,
'react-refresh': eslintPluginReactRefresh,
},
rules: {
...eslintPluginReactHooks.configs.recommended.rules,
...eslintPluginReactRefresh.configs.vite.rules,
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-duplicate-enum-values': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unused-vars': 'warn',
curly: ['error', 'all'],
indent: [
'error',
'tab',
{
offsetTernaryExpressions: true,
SwitchCase: 1,
},
],
'no-unused-vars': 'off',
'no-use-before-define': 'off',
quotes: ['error', 'single'],
'react-refresh/only-export-components': 'off',
'react/display-name': 'off',
semi: ['error', 'always'],
'single-attribute-per-line': 'off',
},
},
eslintConfigPrettier,
);
+9
View File
@@ -0,0 +1,9 @@
DATABASE_USERNAME=admin
DATABASE_PASSWORD=admin
DATABASE_NAME=feishin
DATABASE_PORT=5432
DATABASE_PERSIST_PATH=C:/docker/feishin/db
TOKEN_SECRET=SUPERSECRET
TOKEN_EXPIRATION=30m
TOKEN_REFRESH_EXPIRATION=90d
APP_BASE_URL=http://localhost:8643
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More