karaoke-eternal 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +5 -0
- package/README.md +49 -0
- package/assets/app.ico +0 -0
- package/assets/app.png +0 -0
- package/assets/favicon.ico +0 -0
- package/assets/mic-blackTemplate.png +0 -0
- package/assets/mic-blackTemplate@2x.png +0 -0
- package/assets/mic-white.png +0 -0
- package/assets/mic-white@2x.png +0 -0
- package/assets/robots.txt +2 -0
- package/build/267.4be526e3a94d53aeceae.js +1 -0
- package/build/591.4be526e3a94d53aeceae.js +1 -0
- package/build/598.4be526e3a94d53aeceae.css +5 -0
- package/build/598.4be526e3a94d53aeceae.js +1 -0
- package/build/799.4be526e3a94d53aeceae.js +1 -0
- package/build/7ce9eb3fe454f54745a4.woff2 +0 -0
- package/build/845.4be526e3a94d53aeceae.css +132 -0
- package/build/845.4be526e3a94d53aeceae.js +1 -0
- package/build/a35814dd9eb496e3d7cc.woff2 +0 -0
- package/build/e419b95dccb58b362811.woff2 +0 -0
- package/build/index.html +1 -0
- package/build/licenses.txt +1400 -0
- package/build/main.4be526e3a94d53aeceae.css +2034 -0
- package/build/main.4be526e3a94d53aeceae.js +1 -0
- package/package.json +144 -0
- package/server/Library/Library.js +340 -0
- package/server/Library/index.js +3 -0
- package/server/Library/ipc.js +18 -0
- package/server/Library/router.js +27 -0
- package/server/Library/socket.js +47 -0
- package/server/Media/Media.js +207 -0
- package/server/Media/index.js +3 -0
- package/server/Media/ipc.js +19 -0
- package/server/Media/router.js +99 -0
- package/server/Player/socket.js +78 -0
- package/server/Prefs/Prefs.js +165 -0
- package/server/Prefs/index.js +3 -0
- package/server/Prefs/router.js +124 -0
- package/server/Prefs/socket.js +68 -0
- package/server/Queue/Queue.js +208 -0
- package/server/Queue/index.js +3 -0
- package/server/Queue/socket.js +99 -0
- package/server/Rooms/Rooms.js +114 -0
- package/server/Rooms/index.js +3 -0
- package/server/Rooms/router.js +146 -0
- package/server/Scanner/FileScanner/FileScanner.js +225 -0
- package/server/Scanner/FileScanner/getConfig.js +35 -0
- package/server/Scanner/FileScanner/getFiles.js +63 -0
- package/server/Scanner/FileScanner/index.js +3 -0
- package/server/Scanner/MetaParser/MetaParser.js +49 -0
- package/server/Scanner/MetaParser/defaultMiddleware.js +197 -0
- package/server/Scanner/MetaParser/index.js +3 -0
- package/server/Scanner/Scanner.js +33 -0
- package/server/User/User.js +139 -0
- package/server/User/index.js +3 -0
- package/server/User/router.js +442 -0
- package/server/lib/Database.js +55 -0
- package/server/lib/IPCBridge.js +115 -0
- package/server/lib/Log.js +71 -0
- package/server/lib/bcrypt.js +24 -0
- package/server/lib/cli.js +136 -0
- package/server/lib/electron.js +81 -0
- package/server/lib/getCdgName.js +20 -0
- package/server/lib/getDevMiddleware.js +51 -0
- package/server/lib/getFolders.js +10 -0
- package/server/lib/getHotMiddleware.js +27 -0
- package/server/lib/getIPAddress.js +16 -0
- package/server/lib/getPermutations.js +21 -0
- package/server/lib/getWindowsDrives.js +30 -0
- package/server/lib/parseCookie.js +12 -0
- package/server/lib/pushQueuesAndLibrary.js +29 -0
- package/server/lib/schemas/001-initial-schema.sql +98 -0
- package/server/lib/schemas/002-replaygain.sql +9 -0
- package/server/lib/schemas/003-queue-linked-list.sql +16 -0
- package/server/main.js +135 -0
- package/server/scannerWorker.js +58 -0
- package/server/serverWorker.js +242 -0
- package/server/socket.js +173 -0
- package/shared/actionTypes.js +103 -0
package/server/socket.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
const log = require('./lib/Log')('server')
|
|
2
|
+
const jwtVerify = require('jsonwebtoken').verify
|
|
3
|
+
|
|
4
|
+
const parseCookie = require('./lib/parseCookie')
|
|
5
|
+
const Library = require('./Library')
|
|
6
|
+
const LibrarySocket = require('./Library/socket')
|
|
7
|
+
const PlayerSocket = require('./Player/socket')
|
|
8
|
+
const Prefs = require('./Prefs')
|
|
9
|
+
const PrefsSocket = require('./Prefs/socket')
|
|
10
|
+
const Rooms = require('./Rooms')
|
|
11
|
+
const Queue = require('./Queue')
|
|
12
|
+
const QueueSocket = require('./Queue/socket')
|
|
13
|
+
const {
|
|
14
|
+
LIBRARY_PUSH,
|
|
15
|
+
QUEUE_PUSH,
|
|
16
|
+
STARS_PUSH,
|
|
17
|
+
STAR_COUNTS_PUSH,
|
|
18
|
+
PLAYER_STATUS,
|
|
19
|
+
PLAYER_LEAVE,
|
|
20
|
+
PREFS_PUSH,
|
|
21
|
+
SOCKET_AUTH_ERROR,
|
|
22
|
+
_ERROR,
|
|
23
|
+
} = require('../shared/actionTypes')
|
|
24
|
+
|
|
25
|
+
const handlers = {
|
|
26
|
+
...LibrarySocket,
|
|
27
|
+
...QueueSocket,
|
|
28
|
+
...PlayerSocket,
|
|
29
|
+
...PrefsSocket,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = function (io, jwtKey) {
|
|
33
|
+
io.on('connection', async (sock) => {
|
|
34
|
+
const { keToken } = parseCookie(sock.handshake.headers.cookie)
|
|
35
|
+
const clientLibraryVersion = parseInt(sock.handshake.query.library, 10)
|
|
36
|
+
const clientStarsVersion = parseInt(sock.handshake.query.stars, 10)
|
|
37
|
+
|
|
38
|
+
// authenticate the JWT sent via cookie in http handshake
|
|
39
|
+
try {
|
|
40
|
+
sock.user = jwtVerify(keToken, jwtKey)
|
|
41
|
+
|
|
42
|
+
// success
|
|
43
|
+
log.verbose('%s (%s) connected from %s', sock.user.name, sock.id, sock.handshake.address)
|
|
44
|
+
} catch (err) {
|
|
45
|
+
io.to(sock.id).emit('action', {
|
|
46
|
+
type: SOCKET_AUTH_ERROR,
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
sock.user = null
|
|
50
|
+
sock.disconnect()
|
|
51
|
+
log.verbose('disconnected %s (%s)', sock.handshake.address, err.message)
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// attach disconnect handler
|
|
56
|
+
sock.on('disconnect', reason => {
|
|
57
|
+
log.verbose('%s (%s) disconnected (%s)',
|
|
58
|
+
sock.user.name, sock.id, reason
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
if (typeof sock.user.roomId !== 'number') return
|
|
62
|
+
|
|
63
|
+
// beyond this point assumes there is a room
|
|
64
|
+
|
|
65
|
+
log.verbose('%s (%s) left room %s (%s; %s in room)',
|
|
66
|
+
sock.user.name, sock.id, sock.user.roomId, reason, sock.adapter.rooms.size
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
// any players left in room?
|
|
70
|
+
if (!Rooms.isPlayerPresent(io, sock.user.roomId)) {
|
|
71
|
+
io.to(Rooms.prefix(sock.user.roomId)).emit('action', {
|
|
72
|
+
type: PLAYER_LEAVE,
|
|
73
|
+
payload: { socketId: sock.id },
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
// attach action handler
|
|
79
|
+
sock.on('action', async (action, acknowledge) => {
|
|
80
|
+
const { type } = action
|
|
81
|
+
|
|
82
|
+
if (!sock.user) {
|
|
83
|
+
return acknowledge({
|
|
84
|
+
type: SOCKET_AUTH_ERROR,
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (typeof handlers[type] !== 'function') {
|
|
89
|
+
log.error('No handler for socket action: %s', type)
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
await handlers[type](sock, action, acknowledge)
|
|
95
|
+
} catch (err) {
|
|
96
|
+
log.error(err)
|
|
97
|
+
|
|
98
|
+
return acknowledge({
|
|
99
|
+
type: type + _ERROR,
|
|
100
|
+
error: `Error in ${type}: ${err.message}`,
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
// push prefs (admin only)
|
|
106
|
+
if (sock.user.isAdmin) {
|
|
107
|
+
log.verbose('pushing prefs to %s (%s)', sock.user.name, sock.id)
|
|
108
|
+
io.to(sock.id).emit('action', {
|
|
109
|
+
type: PREFS_PUSH,
|
|
110
|
+
payload: await Prefs.get(),
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// push library (only if client's is outdated)
|
|
115
|
+
if (clientLibraryVersion !== Library.cache.version) {
|
|
116
|
+
log.verbose('pushing library to %s (%s) (client=%s, server=%s)',
|
|
117
|
+
sock.user.name, sock.id, clientLibraryVersion, Library.cache.version)
|
|
118
|
+
|
|
119
|
+
io.to(sock.id).emit('action', {
|
|
120
|
+
type: LIBRARY_PUSH,
|
|
121
|
+
payload: await Library.get(),
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// push user's stars
|
|
126
|
+
io.to(sock.id).emit('action', {
|
|
127
|
+
type: STARS_PUSH,
|
|
128
|
+
payload: await Library.getUserStars(sock.user.userId),
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
// push star counts (only if client's is outdated)
|
|
132
|
+
if (clientStarsVersion !== Library.starCountsCache.version) {
|
|
133
|
+
log.verbose('pushing star counts to %s (%s) (client=%s, server=%s)',
|
|
134
|
+
sock.user.name, sock.id, clientStarsVersion, Library.starCountsCache.version)
|
|
135
|
+
|
|
136
|
+
io.to(sock.id).emit('action', {
|
|
137
|
+
type: STAR_COUNTS_PUSH,
|
|
138
|
+
payload: await Library.getStarCounts(),
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// it's possible for an admin to not be in a room
|
|
143
|
+
if (typeof sock.user.roomId !== 'number') return
|
|
144
|
+
|
|
145
|
+
// beyond this point assumes there is a room
|
|
146
|
+
|
|
147
|
+
// add user to room
|
|
148
|
+
sock.join(Rooms.prefix(sock.user.roomId))
|
|
149
|
+
|
|
150
|
+
// if there's a player in room, emit its last known status
|
|
151
|
+
// @todo this just emits the first status found
|
|
152
|
+
for (const s of io.of('/').sockets.values()) {
|
|
153
|
+
if (s.user && s.user.roomId === sock.user.roomId && s._lastPlayerStatus) {
|
|
154
|
+
io.to(sock.id).emit('action', {
|
|
155
|
+
type: PLAYER_STATUS,
|
|
156
|
+
payload: s._lastPlayerStatus,
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
break
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
log.verbose('%s (%s) joined room %s (%s in room)',
|
|
164
|
+
sock.user.name, sock.id, sock.user.roomId, sock.adapter.rooms.size
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
// send room's queue
|
|
168
|
+
io.to(sock.id).emit('action', {
|
|
169
|
+
type: QUEUE_PUSH,
|
|
170
|
+
payload: await Queue.get(sock.user.roomId),
|
|
171
|
+
})
|
|
172
|
+
})
|
|
173
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
// sockets
|
|
3
|
+
SOCKET_REQUEST_CONNECT: 'user/SOCKET_REQUEST_CONNECT',
|
|
4
|
+
SOCKET_AUTH_ERROR: 'user/SOCKET_AUTH_ERROR',
|
|
5
|
+
// library
|
|
6
|
+
LIBRARY_FILTER_STRING: 'library/FILTER_KEYWORD',
|
|
7
|
+
LIBRARY_FILTER_STRING_RESET: 'library/FILTER_KEYWORD_CLEAR',
|
|
8
|
+
LIBRARY_FILTER_TOGGLE_STARRED: 'library/TOGGLE_FILTER_STARRED',
|
|
9
|
+
TOGGLE_ARTIST_EXPANDED: 'library/TOGGLE_ARTIST_EXPANDED',
|
|
10
|
+
TOGGLE_ARTIST_RESULT_EXPANDED: 'library/TOGGLE_ARTIST_RESULT_EXPANDED',
|
|
11
|
+
SCROLL_ARTISTS: 'library/SCROLL_ARTISTS',
|
|
12
|
+
SONG_STARRED: 'library/SONG_STARRED',
|
|
13
|
+
SONG_UNSTARRED: 'library/SONG_UNSTARRED',
|
|
14
|
+
STAR_COUNTS_PUSH: 'library/STAR_COUNTS_PUSH',
|
|
15
|
+
LIBRARY_PUSH: 'library/PUSH',
|
|
16
|
+
LIBRARY_PUSH_SONG: 'library/PUSH_SONG',
|
|
17
|
+
// queue
|
|
18
|
+
QUEUE_ADD: 'server/QUEUE_ADD',
|
|
19
|
+
QUEUE_MOVE: 'server/QUEUE_MOVE',
|
|
20
|
+
QUEUE_PUSH: 'queue/PUSH',
|
|
21
|
+
QUEUE_REMOVE: 'server/QUEUE_REMOVE',
|
|
22
|
+
// player internal
|
|
23
|
+
PLAYER_UPDATE: 'player/UPDATE',
|
|
24
|
+
// player room commands
|
|
25
|
+
PLAYER_CMD_OPTIONS: 'player/CMD_OPTIONS',
|
|
26
|
+
PLAYER_CMD_NEXT: 'player/CMD_NEXT',
|
|
27
|
+
PLAYER_CMD_PAUSE: 'player/CMD_PAUSE',
|
|
28
|
+
PLAYER_CMD_PLAY: 'player/CMD_PLAY',
|
|
29
|
+
PLAYER_CMD_VOLUME: 'player/CMD_VOLUME',
|
|
30
|
+
PLAYER_REQ_OPTIONS: 'server/PLAYER_REQ_OPTIONS',
|
|
31
|
+
PLAYER_REQ_PLAY: 'server/PLAYER_REQ_PLAY',
|
|
32
|
+
PLAYER_REQ_PAUSE: 'server/PLAYER_REQ_PAUSE',
|
|
33
|
+
PLAYER_REQ_NEXT: 'server/PLAYER_REQ_NEXT',
|
|
34
|
+
PLAYER_REQ_VOLUME: 'server/PLAYER_REQ_VOLUME',
|
|
35
|
+
PLAYER_EMIT_STATUS: 'server/PLAYER_EMIT_STATUS',
|
|
36
|
+
PLAYER_EMIT_LEAVE: 'server/PLAYER_EMIT_LEAVE',
|
|
37
|
+
// player events
|
|
38
|
+
PLAYER_STATUS: 'status/PLAYER_STATUS',
|
|
39
|
+
PLAYER_ERROR: 'status/PLAYER_ERROR',
|
|
40
|
+
PLAYER_LEAVE: 'status/PLAYER_LEAVE',
|
|
41
|
+
PLAYER_LOAD: 'status/PLAYER_LOAD',
|
|
42
|
+
PLAYER_PLAY: 'status/PLAYER_PLAY',
|
|
43
|
+
PLAYER_VISUALIZER_ERROR: 'status/PLAYER_VISUALIZER_ERROR',
|
|
44
|
+
// user
|
|
45
|
+
LOGIN: 'user/LOGIN',
|
|
46
|
+
LOGOUT: 'user/LOGOUT',
|
|
47
|
+
CREATE_ACCOUNT: 'user/CREATE_ACCOUNT',
|
|
48
|
+
UPDATE_ACCOUNT: 'user/UPDATE_ACCOUNT',
|
|
49
|
+
REQUEST_ACCOUNT: 'user/REQUEST_ACCOUNT',
|
|
50
|
+
REQUEST_ROOMS: 'rooms/REQUEST_ROOMS',
|
|
51
|
+
ROOM_UPDATE: 'rooms/UPDATE',
|
|
52
|
+
ROOM_CREATE: 'rooms/CREATE',
|
|
53
|
+
ROOM_REMOVE: 'rooms/REMOVE',
|
|
54
|
+
ROOM_EDITOR_OPEN: 'rooms/EDITOR_OPEN',
|
|
55
|
+
ROOM_EDITOR_CLOSE: 'rooms/EDITOR_CLOSE',
|
|
56
|
+
ROOM_FILTER_STATUS: 'rooms/TOGGLE_SHOW_ALL',
|
|
57
|
+
STAR_SONG: 'server/STAR_SONG',
|
|
58
|
+
UNSTAR_SONG: 'server/UNSTAR_SONG',
|
|
59
|
+
STARS_PUSH: 'user/STARS_PUSH',
|
|
60
|
+
// prefs
|
|
61
|
+
PREFS_RECEIVE: 'prefs/RECEIVE',
|
|
62
|
+
PREFS_REQUEST: 'prefs/REQUEST',
|
|
63
|
+
PREFS_SET: 'server/PREFS_SET',
|
|
64
|
+
PREFS_SET_PATH_PRIORITY: 'server/PREFS_SET_PATH_PRIORITY',
|
|
65
|
+
PREFS_PUSH: 'prefs/PREFS_PUSH',
|
|
66
|
+
PREFS_REQ_SCANNER_START: 'prefs/REQ_SCANNER_START',
|
|
67
|
+
PREFS_REQ_SCANNER_STOP: 'prefs/REQ_SCANNER_STOP',
|
|
68
|
+
// user management
|
|
69
|
+
USERS_CREATE: 'users/CREATE',
|
|
70
|
+
USERS_EDITOR_OPEN: 'users/EDITOR_OPEN',
|
|
71
|
+
USERS_EDITOR_CLOSE: 'users/EDITOR_CLOSE',
|
|
72
|
+
USERS_FILTER_ONLINE: 'users/FILTER_ONLINE',
|
|
73
|
+
USERS_FILTER_ROOM_ID: 'users/FILTER_ROOM_ID',
|
|
74
|
+
USERS_RECEIVE: 'users/RECEIVE',
|
|
75
|
+
USERS_REMOVE: 'users/REMOVE',
|
|
76
|
+
USERS_REQUEST: 'users/REQUEST',
|
|
77
|
+
USERS_UPDATE: 'users/UPDATE',
|
|
78
|
+
// ui
|
|
79
|
+
HEADER_HEIGHT_CHANGE: 'ui/HEADER_HEIGHT_CHANGE',
|
|
80
|
+
FOOTER_HEIGHT_CHANGE: 'ui/FOOTER_HEIGHT_CHANGE',
|
|
81
|
+
SHOW_ERROR_MESSAGE: 'ui/SHOW_ERROR_MESSAGE',
|
|
82
|
+
CLEAR_ERROR_MESSAGE: 'ui/CLEAR_ERROR_MESSAGE',
|
|
83
|
+
UI_WINDOW_RESIZE: 'ui/WINDOW_RESIZE',
|
|
84
|
+
// songInfo
|
|
85
|
+
SONG_INFO_REQUEST: 'songInfo/SONG_INFO_REQUEST',
|
|
86
|
+
SONG_INFO_SET_PREFERRED: 'songInfo/SET_PREFERRED',
|
|
87
|
+
SONG_INFO_CLOSE: 'songInfo/SONG_INFO_CLOSE',
|
|
88
|
+
// IPC messages
|
|
89
|
+
SCANNER_CMD_START: 'scannerWorker/CMD_START',
|
|
90
|
+
SCANNER_CMD_STOP: 'scannerWorker/CMD_STOP',
|
|
91
|
+
SCANNER_WORKER_LOG: 'scannerWorker/LOG',
|
|
92
|
+
SCANNER_WORKER_STATUS: 'scannerWorker/STATUS',
|
|
93
|
+
SERVER_WORKER_STATUS: 'serverWorker/STATUS',
|
|
94
|
+
SERVER_WORKER_ERROR: 'serverWorker/ERROR',
|
|
95
|
+
LIBRARY_MATCH_SONG: 'scannerWorker/LIBRARY_MATCH_SONG',
|
|
96
|
+
MEDIA_ADD: 'scannerWorker/MEDIA_ADD',
|
|
97
|
+
MEDIA_CLEANUP: 'scannerWorker/MEDIA_CLEANUP',
|
|
98
|
+
MEDIA_REMOVE: 'scannerWorker/MEDIA_REMOVE',
|
|
99
|
+
MEDIA_UPDATE: 'scannerWorker/MEDIA_UPDATE',
|
|
100
|
+
// misc
|
|
101
|
+
_SUCCESS: '_SUCCESS',
|
|
102
|
+
_ERROR: '_ERROR',
|
|
103
|
+
}
|