Browse Source

Merge branch 'polishing' into kris-song-merging

Kristian Vos 4 years ago
parent
commit
ba7b0f10e2

+ 8 - 6
.env.example

@@ -1,17 +1,19 @@
-REDIS_PASSWORD=PASSWORD
+COMPOSE_PROJECT_NAME=musare
 
+BACKEND_HOST=127.0.0.1
 BACKEND_PORT=8080
+
+FRONTEND_HOST=127.0.0.1
 FRONTEND_PORT=80
+FRONTEND_MODE=dev
 
+MONGO_HOST=127.0.0.1
 MONGO_PORT=27017
 MONGO_ROOT_PASSWORD=PASSWORD_HERE
 MONGO_USER_USERNAME=musare
 MONGO_USER_PASSWORD=OTHER_PASSWORD_HERE
 
-MONGOCLIENT_PORT=3000
-
+REDIS_HOST=127.0.0.1
 REDIS_PORT=6379
+REDIS_PASSWORD=PASSWORD
 
-COMPOSE_PROJECT_NAME=musare
-
-FRONTEND_MODE=dev

+ 7 - 4
.travis.yml

@@ -8,17 +8,20 @@ services:
 
 env:
   global:
-    - REDIS_PASSWORD=PASSWORD
+    - COMPOSE_PROJECT_NAME=musare
+    - BACKEND_HOST=127.0.0.1
     - BACKEND_PORT=8080
+    - FRONTEND_HOST=127.0.0.1
     - FRONTEND_PORT=80
+    - FRONTEND_MODE=dev
+    - MONGO_HOST=127.0.0.1
     - MONGO_PORT=27017
     - MONGO_ROOT_PASSWORD=PASSWORD_HERE
     - MONGO_USER_USERNAME=musare
     - MONGO_USER_PASSWORD=OTHER_PASSWORD_HERE
-    - MONGOCLIENT_PORT=3000
+    - REDIS_HOST=127.0.0.1
     - REDIS_PORT=6379
-    - COMPOSE_PROJECT_NAME=musare
-    - FRONTEND_MODE=prod
+    - REDIS_PASSWORD=PASSWORD
 
 before_install:
   # create config files from template

+ 16 - 0
backend/logic/ws.js

@@ -68,8 +68,24 @@ class _WSModule extends CoreClass {
 				WSModule.runJob("HANDLE_WS_USE", { socket, req }).then(socket =>
 					WSModule.runJob("HANDLE_WS_CONNECTION", { socket })
 				);
+
+				socket.isAlive = true;
+				socket.on("pong", function heartbeat() {
+					this.isAlive = true;
+				});
 			});
 
+			const keepAliveInterval = setInterval(() => {
+				this._io.clients.forEach(socket => {
+					if (socket.isAlive === false) return socket.terminate();
+
+					socket.isAlive = false;
+					return socket.ping(() => {});
+				});
+			}, 45000);
+
+			this._io.on("close", () => clearInterval(keepAliveInterval));
+
 			this.setStage(4);
 
 			return resolve();

+ 7 - 5
docker-compose.yml

@@ -4,7 +4,7 @@ services:
   backend:
     build: ./backend
     ports:
-      - "${BACKEND_PORT}:8080"
+      - "${BACKEND_HOST}:${BACKEND_PORT}:8080"
     volumes:
       - ./backend:/opt/app
       - ./log:/opt/log
@@ -17,7 +17,7 @@ services:
   frontend:
     build: ./frontend
     ports:
-      - "${FRONTEND_PORT}:80"
+      - "${FRONTEND_HOST}:${FRONTEND_PORT}:80"
     volumes:
       - ./frontend:/opt/app
       - /opt/app/node_modules/
@@ -27,7 +27,7 @@ services:
   mongo:
     image: mongo:4.0
     ports:
-      - "${MONGO_PORT}:27017"
+      - "${MONGO_HOST}:${MONGO_PORT}:${MONGO_PORT}"
     environment:
       - MONGO_INITDB_ROOT_USERNAME=admin
       - MONGO_INITDB_ROOT_PASSWORD=${MONGO_ROOT_PASSWORD}
@@ -38,11 +38,13 @@ services:
       - MONGO_USER_PASSWORD=${MONGO_USER_PASSWORD}
     volumes:
       - ./tools/docker/setup-mongo.sh:/docker-entrypoint-initdb.d/setup-mongo.sh
+      - ./.db:/data/db
 
   redis:
     image: redis
+    ports:
+      - "${REDIS_HOST}:${REDIS_PORT}:6379"
     command: "--notify-keyspace-events Ex --requirepass ${REDIS_PASSWORD} --appendonly yes"
     volumes:
       - .redis:/data
-    ports:
-      - "${REDIS_PORT}:6379"
+

+ 11 - 29
frontend/package-lock.json

@@ -2756,8 +2756,7 @@
     "@polka/url": {
       "version": "1.0.0-next.11",
       "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.11.tgz",
-      "integrity": "sha512-3NsZsJIA/22P3QUyrEDNA2D133H4j224twJrdipXN38dpnIOzAbUDtOwkcJ5pXmn75w7LSQDjA4tO9dm1XlqlA==",
-      "dev": true
+      "integrity": "sha512-3NsZsJIA/22P3QUyrEDNA2D133H4j224twJrdipXN38dpnIOzAbUDtOwkcJ5pXmn75w7LSQDjA4tO9dm1XlqlA=="
     },
     "@types/color-name": {
       "version": "1.1.1",
@@ -3034,8 +3033,7 @@
     "acorn-walk": {
       "version": "8.0.2",
       "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.0.2.tgz",
-      "integrity": "sha512-+bpA9MJsHdZ4bgfDcpk0ozQyhhVct7rzOmO0s1IIr0AGGgKBljss8n2zp11rRP2wid5VGeh04CgeKzgat5/25A==",
-      "dev": true
+      "integrity": "sha512-+bpA9MJsHdZ4bgfDcpk0ozQyhhVct7rzOmO0s1IIr0AGGgKBljss8n2zp11rRP2wid5VGeh04CgeKzgat5/25A=="
     },
     "ajv": {
       "version": "6.12.2",
@@ -4678,8 +4676,7 @@
     "color-name": {
       "version": "1.1.4",
       "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-      "dev": true
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
     },
     "colorette": {
       "version": "1.2.2",
@@ -5228,8 +5225,7 @@
     "duplexer": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
-      "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
-      "dev": true
+      "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg=="
     },
     "ecc-jsbn": {
       "version": "0.1.2",
@@ -6535,7 +6531,6 @@
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz",
       "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==",
-      "dev": true,
       "requires": {
         "duplexer": "^0.1.2"
       }
@@ -8430,8 +8425,7 @@
     "opener": {
       "version": "1.5.2",
       "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
-      "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==",
-      "dev": true
+      "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A=="
     },
     "opn": {
       "version": "5.5.0",
@@ -9700,7 +9694,6 @@
       "version": "1.0.11",
       "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.11.tgz",
       "integrity": "sha512-SR36i3/LSWja7AJNRBz4fF/Xjpn7lQFI30tZ434dIy+bitLYSP+ZEenHg36i23V2SGEz+kqjksg0uOGZ5LPiqg==",
-      "dev": true,
       "requires": {
         "@polka/url": "^1.0.0-next.9",
         "mime": "^2.3.1",
@@ -9710,8 +9703,7 @@
         "mime": {
           "version": "2.5.2",
           "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz",
-          "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==",
-          "dev": true
+          "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg=="
         }
       }
     },
@@ -10476,8 +10468,7 @@
     "totalist": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz",
-      "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==",
-      "dev": true
+      "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g=="
     },
     "tough-cookie": {
       "version": "2.5.0",
@@ -11006,7 +10997,6 @@
       "version": "4.4.0",
       "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.4.0.tgz",
       "integrity": "sha512-9DhNa+aXpqdHk8LkLPTBU/dMfl84Y+WE2+KnfI6rSpNRNVKa0VGLjPd2pjFubDeqnWmulFggxmWBxhfJXZnR0g==",
-      "dev": true,
       "requires": {
         "acorn": "^8.0.4",
         "acorn-walk": "^8.0.0",
@@ -11022,14 +11012,12 @@
         "acorn": {
           "version": "8.1.0",
           "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz",
-          "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==",
-          "dev": true
+          "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA=="
         },
         "ansi-styles": {
           "version": "4.3.0",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
           "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-          "dev": true,
           "requires": {
             "color-convert": "^2.0.1"
           }
@@ -11038,7 +11026,6 @@
           "version": "4.1.0",
           "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
           "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
-          "dev": true,
           "requires": {
             "ansi-styles": "^4.1.0",
             "supports-color": "^7.1.0"
@@ -11048,7 +11035,6 @@
           "version": "2.0.1",
           "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
           "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-          "dev": true,
           "requires": {
             "color-name": "~1.1.4"
           }
@@ -11056,20 +11042,17 @@
         "commander": {
           "version": "6.2.1",
           "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
-          "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
-          "dev": true
+          "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA=="
         },
         "has-flag": {
           "version": "4.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
         },
         "supports-color": {
           "version": "7.2.0",
           "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
           "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-          "dev": true,
           "requires": {
             "has-flag": "^4.0.0"
           }
@@ -11077,8 +11060,7 @@
         "ws": {
           "version": "7.4.4",
           "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz",
-          "integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==",
-          "dev": true
+          "integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw=="
         }
       }
     },

+ 1 - 1
frontend/package.json

@@ -38,7 +38,6 @@
     "vue-hot-reload-api": "^2.3.3",
     "vue-style-loader": "^4.1.3",
     "vue-template-compiler": "^2.6.12",
-    "webpack-bundle-analyzer": "^4.4.0",
     "webpack-cli": "4.5.0",
     "webpack-dev-server": "^3.11.2"
   },
@@ -57,6 +56,7 @@
     "vuedraggable": "^2.24.3",
     "vuex": "^3.6.2",
     "webpack": "5.27.2",
+    "webpack-bundle-analyzer": "^4.4.0",
     "webpack-merge": "^5.7.3"
   }
 }

+ 4 - 8
frontend/src/App.vue

@@ -14,19 +14,15 @@
 import { mapState, mapActions, mapGetters } from "vuex";
 import Toast from "toasters";
 
-import Banned from "./pages/Banned.vue";
-import WhatIsNew from "./components/modals/WhatIsNew.vue";
-import LoginModal from "./components/modals/Login.vue";
-import RegisterModal from "./components/modals/Register.vue";
 import ws from "./ws";
 import keyboardShortcuts from "./keyboardShortcuts";
 
 export default {
 	components: {
-		WhatIsNew,
-		LoginModal,
-		RegisterModal,
-		Banned
+		WhatIsNew: () => import("./components/modals/WhatIsNew.vue"),
+		LoginModal: () => import("./components/modals/Login.vue"),
+		RegisterModal: () => import("./components/modals/Register.vue"),
+		Banned: () => import("./pages/Banned.vue")
 	},
 	replace: false,
 	data() {

+ 3 - 2
frontend/src/components/modals/EditPlaylist/components/PlaylistSongItem.vue

@@ -80,9 +80,10 @@ export default {
 	height: 0;
 
 	.nav-dropdown-items {
-		width: max-content;
+		width: 250px;
+		max-width: 100vw;
 		position: relative;
-		right: 200px;
+		right: 250px;
 	}
 }
 

+ 7 - 3
frontend/src/components/modals/EditPlaylist/index.vue

@@ -15,6 +15,7 @@
 			<div id="first-column">
 				<div id="playlist-info-section" class="section">
 					<h3>{{ playlist.displayName }}</h3>
+					<h5>Song Count: {{ playlist.songs.length }}</h5>
 					<h5>Duration: {{ totalLength() }}</h5>
 				</div>
 
@@ -309,7 +310,8 @@
 											<i
 												v-if="
 													userId ===
-														playlist.createdBy
+														playlist.createdBy ||
+														isEditable()
 												"
 												@click="
 													removeSongFromPlaylist(
@@ -349,6 +351,7 @@
 				class="button is-default"
 				v-if="
 					this.userId === this.playlist.createdBy ||
+						isEditable() ||
 						this.playlist.privacy === 'public'
 				"
 				@click="downloadPlaylist()"
@@ -541,7 +544,8 @@ export default {
 		isEditable() {
 			return (
 				this.playlist.isUserModifiable &&
-				this.userId === this.playlist.createdBy
+				(this.userId === this.playlist.createdBy ||
+					this.userRole === "admin")
 			);
 		},
 		updateSongPositioning({ moved }) {
@@ -802,7 +806,7 @@ export default {
 			height: auto !important;
 
 			#first-column {
-				break-after: always;
+				flex-basis: 100%;
 			}
 
 			.section {

+ 10 - 4
frontend/src/components/modals/EditStation.vue

@@ -228,7 +228,7 @@
 						</div>
 					</div>
 					<!--  Buttons changing the mode of the station -->
-					<div v-if="station.type === 'community'">
+					<div>
 						<label class="label">Station Mode</label>
 						<div
 							@mouseenter="modeDropdownActive = true"
@@ -265,7 +265,10 @@
 									Playlist
 								</button>
 							</transition>
-							<transition name="slide-down">
+							<transition
+								v-if="station.type === 'community'"
+								name="slide-down"
+							>
 								<button
 									class="yellow"
 									v-if="
@@ -318,7 +321,10 @@
 									Random
 								</button>
 							</transition>
-							<transition name="slide-down">
+							<transition
+								v-if="station.type === 'community'"
+								name="slide-down"
+							>
 								<button
 									class="blue"
 									v-if="
@@ -1317,7 +1323,7 @@ export default {
 			}
 
 			&.blue {
-				background-color: var(--primary-color);
+				background-color: var(--blue);
 			}
 
 			&.orange {

+ 6 - 1
frontend/src/components/ui/AddToPlaylistDropdown.vue

@@ -206,6 +206,7 @@ export default {
 			display: flex;
 			align-items: center;
 			margin-bottom: 0 !important;
+			width: inherit;
 
 			input {
 				margin-right: 5px;
@@ -220,10 +221,11 @@ export default {
 				display: flex;
 				flex-direction: row;
 				align-items: center;
+				width: inherit;
 
 				span {
 					cursor: pointer;
-					width: 24px;
+					min-width: 24px;
 					height: 24px;
 					background-color: var(--white);
 					display: inline-block;
@@ -236,6 +238,9 @@ export default {
 					margin-left: 10px;
 					cursor: pointer;
 					color: var(--black);
+					overflow: hidden;
+					text-overflow: ellipsis;
+					white-space: nowrap;
 				}
 			}
 

+ 5 - 1
frontend/src/pages/Profile/index.vue

@@ -78,7 +78,11 @@
 						Playlists
 					</button>
 				</div>
-				<playlists :user-id="userId" v-show="tab === 'playlists'" />
+				<playlists
+					:user-id="userId"
+					:username="user.name"
+					v-show="tab === 'playlists'"
+				/>
 				<recent-activity
 					:user-id="userId"
 					v-show="tab === 'recent-activity'"

+ 5 - 2
frontend/src/pages/Profile/tabs/Playlists.vue

@@ -109,6 +109,10 @@ export default {
 		userId: {
 			type: String,
 			default: ""
+		},
+		username: {
+			type: String,
+			default: ""
 		}
 	},
 	computed: {
@@ -116,8 +120,7 @@ export default {
 			...mapState("modalVisibility", {
 				modals: state => state.modals.station
 			}),
-			myUserId: state => state.user.auth.userId,
-			username: state => state.user.auth.username
+			myUserId: state => state.user.auth.userId
 		}),
 		playlists: {
 			get() {

+ 16 - 3
frontend/src/pages/Station/components/CurrentlyPlaying.vue

@@ -26,10 +26,15 @@
 				<h4
 					id="song-title"
 					:style="!song.artists ? { fontSize: '17px' } : null"
+					:title="song.title"
 				>
 					{{ song.title }}
 				</h4>
-				<h5 id="song-artists" v-if="song.artists">
+				<h5
+					id="song-artists"
+					v-if="song.artists"
+					:title="song.artists.join(', ')"
+				>
 					{{ song.artists.join(", ") }}
 				</h5>
 				<p
@@ -157,10 +162,10 @@ export default {
 
 	#song-info {
 		display: flex;
-		flex-direction: row;
+		flex-direction: column;
 		flex-wrap: wrap;
 		margin-left: 20px;
-		width: 100%;
+		width: calc(100% - 130px - 20px);
 		height: 100%;
 
 		*:not(i) {
@@ -173,6 +178,8 @@ export default {
 			justify-content: center;
 			flex-direction: column;
 			flex-grow: 1;
+			width: 100%;
+
 			h6 {
 				color: var(--primary-color) !important;
 				font-weight: bold;
@@ -182,11 +189,17 @@ export default {
 			#song-title {
 				margin-top: 7px;
 				font-size: 22px;
+				overflow: hidden;
+				text-overflow: ellipsis;
+				white-space: nowrap;
 			}
 
 			#song-artists {
 				font-size: 16px;
 				margin-bottom: 5px;
+				overflow: hidden;
+				text-overflow: ellipsis;
+				white-space: nowrap;
 			}
 
 			#song-request-time {

+ 3 - 2
frontend/src/pages/Station/components/Sidebar/Queue/QueueItem.vue

@@ -149,9 +149,10 @@ export default {
 	height: 0;
 
 	.nav-dropdown-items {
-		width: max-content;
+		width: 250px;
+		max-width: 100vw;
 		position: relative;
-		right: 125px;
+		right: 175px;
 	}
 }
 

+ 8 - 6
frontend/src/pages/Station/index.vue

@@ -1891,11 +1891,8 @@ export default {
 			border: 1px solid var(--light-grey-3);
 		}
 
-		#station-left-column {
-			padding: 0;
-		}
+		#station-left-column,
 		#station-right-column {
-			max-width: 650px;
 			padding: 0;
 		}
 
@@ -1945,6 +1942,7 @@ export default {
 		#current-next-row {
 			display: flex;
 			flex-direction: row;
+			max-width: calc(100vw - 40px);
 
 			#currently-playing-container,
 			#next-up-container {
@@ -2228,6 +2226,12 @@ export default {
 	justify-content: center;
 }
 
+@media (min-width: 1500px) {
+	#station-right-column {
+		max-width: 650px;
+	}
+}
+
 @media (max-width: 950px) {
 	#mobile-progress-animation {
 		display: block;
@@ -2285,8 +2289,6 @@ export default {
 			}
 
 			#station-right-column {
-				max-width: unset;
-
 				#about-station-container #admin-buttons {
 					flex-wrap: wrap;
 				}

+ 1 - 1
frontend/src/ws.js

@@ -122,7 +122,7 @@ export default {
 		store.dispatch("websockets/createSocket", this.socket);
 
 		this.socket.onopen = () => {
-			console.log("IO: SOCKET CONNECTED");
+			console.log("WS: SOCKET CONNECTED");
 
 			setTimeout(() => {
 				onConnect.temp.forEach(cb => cb());

+ 29 - 3
frontend/webpack.prod.js

@@ -1,5 +1,5 @@
 const { merge } = require("webpack-merge");
-const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
+const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
 
 const common = require("./webpack.common.js");
 
@@ -11,7 +11,7 @@ module.exports = merge(common, {
 	},
 	resolve: {
 		alias: {
-			vue: "vue/dist/vue.min.js",
+			vue: "vue/dist/vue.esm.js",
 			styles: "src/styles"
 		}
 	},
@@ -19,5 +19,31 @@ module.exports = merge(common, {
 		new BundleAnalyzerPlugin({
 			analyzerMode: "static"
 		})
-	]
+	],
+	optimization: {
+		runtimeChunk: "single",
+		splitChunks: {
+			cacheGroups: {
+				commons: {
+					name: "vendors",
+					test: /[\\/]node_modules[\\/](vue|vuex|vue-router)[\\/]/,
+					chunks: "all"
+				},
+				ui: {
+					name: false,
+					test(module) {
+						return (
+							module.resource.includes("Modal.vue") ||
+							module.resource.includes(
+								"AddToPlaylistDropdown.vue"
+							) ||
+							module.resource.includes("MainHeader.vue") ||
+							module.resource.includes("MainFooter.vue")
+						);
+					},
+					enforce: true
+				}
+			}
+		}
+	}
 });