Fixes, theming & deploy files

This commit is contained in:
Thomas
2020-08-01 18:19:39 +02:00
parent 76c6b45e2b
commit 1990ff0f04
23 changed files with 552 additions and 403 deletions

6
Dockerfile Normal file
View File

@@ -0,0 +1,6 @@
FROM alpine:edge
MAINTAINER gltron
RUN apk --update add openjdk8-jre
COPY cloud32.jar /home/cloud32.jar
CMD ["java","-jar","/home/cloud32.jar"]
EXPOSE 8181

1
buildDocker.sh Normal file
View File

@@ -0,0 +1 @@
docker build . -t thomsb/c32java

8
buildJar.sh Normal file
View File

@@ -0,0 +1,8 @@
cd client
npm run build
cp -r dist/* ../server/src/main/resources/public
cd ../server
mvn package
cp target/cloud32-0.0.1-SNAPSHOT.jar ../cloud32.jar
rm -rf ../client/dist
rm -rf src/main/resources/public/*

View File

@@ -7313,6 +7313,11 @@
"object-visit": "^1.0.0" "object-visit": "^1.0.0"
} }
}, },
"material-design-icons": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/material-design-icons/-/material-design-icons-3.0.1.tgz",
"integrity": "sha1-mnHEh0chjrylHlGmbaaCA4zct78="
},
"md5.js": { "md5.js": {
"version": "1.3.5", "version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",

View File

@@ -11,6 +11,7 @@
"@chenfengyuan/vue-qrcode": "^1.0.2", "@chenfengyuan/vue-qrcode": "^1.0.2",
"buefy": "^0.8.20", "buefy": "^0.8.20",
"core-js": "^3.6.5", "core-js": "^3.6.5",
"material-design-icons": "^3.0.1",
"register-service-worker": "^1.7.1", "register-service-worker": "^1.7.1",
"vue": "^2.6.11", "vue": "^2.6.11",
"vue-qrcode-reader": "^2.3.11", "vue-qrcode-reader": "^2.3.11",

View File

@@ -4,7 +4,7 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0"> <meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.materialdesignicons.com/2.5.94/css/materialdesignicons.min.css"> <link rel="stylesheet" href="//cdn.materialdesignicons.com/5.4.55/css/materialdesignicons.min.css">
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> <link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title> <title><%= htmlWebpackPlugin.options.title %></title>
</head> </head>

View File

@@ -3,17 +3,3 @@
<router-view/> <router-view/>
</div> </div>
</template> </template>
<style lang="scss">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
#nav {
padding: 30px;
}
</style>

Binary file not shown.

View File

@@ -0,0 +1,289 @@
// Overrides
@import url("https://fonts.googleapis.com/css?family=Lato:400,700,400italic&display=swap");
@font-face {
font-family: 'Gravity Regular';
src: url('Gravity-Regular.otf') format('opentype');
}
hr {
height: $border-width;
}
h6 {
text-transform: uppercase;
letter-spacing: 0.5px;
}
.hero {
background-color: $grey-dark;
}
a {
transition: all 200ms ease;
}
.button {
transition: all 200ms ease;
border-width: $border-width;
color: $white;
&.is-active,
&.is-focused,
&:active,
&:focus {
box-shadow: 0 0 0 2px rgba($button-focus-border-color, 0.5);
}
@each $name, $pair in $colors {
$color: nth($pair, 1);
$color-invert: nth($pair, 2);
&.is-#{$name} {
&.is-hovered,
&:hover {
background-color: lighten($color, 7.5%);
}
&.is-active,
&.is-focused,
&:active,
&:focus {
border-color: $color;
box-shadow: 0 0 0 2px rgba($color, 0.5);
}
}
}
}
.label {
color: $grey-lighter;
}
.input,
.textarea {
transition: all 200ms ease;
box-shadow: none;
border-width: $border-width;
padding-left: 1em;
padding-right: 1em;
}
.select {
&:after,
select {
border-width: $border-width;
}
}
.control {
&.has-addons {
.button,
.input,
.select {
margin-right: -$border-width;
}
}
}
.notification {
background-color: $grey-dark;
}
.card {
$card-border-color: lighten($grey-darker, 5);
box-shadow: none;
border: $border-width solid $card-border-color;
background-color: $grey-darker;
border-radius: $radius;
.card-image {
img {
border-radius: $radius $radius 0 0;
}
}
.card-header {
box-shadow: none;
background-color: rgba($black-bis, 0.2);
border-radius: $radius $radius 0 0;
}
.card-footer {
background-color: rgba($black-bis, 0.2);
}
.card-footer,
.card-footer-item {
border-width: $border-width;
border-color: $card-border-color;
}
}
.notification {
@each $name, $pair in $colors {
$color: nth($pair, 1);
$color-invert: nth($pair, 2);
&.is-#{$name} {
a:not(.button) {
color: $color-invert;
text-decoration: underline;
}
}
}
}
.tag {
border-radius: $radius;
}
.menu-list {
a {
transition: all 300ms ease;
}
}
.modal-card-body {
background-color: $grey-darker;
}
.modal-card-foot,
.modal-card-head {
border-color: $grey-dark;
}
.message-header {
font-weight: $weight-bold;
background-color: $grey-dark;
color: $white;
}
.message-body {
border-width: $border-width;
border-color: $grey-dark;
}
.navbar {
border-radius: $radius;
&.is-transparent {
background: none;
}
&.is-primary {
.navbar-dropdown {
a.navbar-item.is-active {
background-color: $link;
}
}
}
@include touch {
.navbar-menu {
background-color: $navbar-background-color;
border-radius: 0 0 $radius $radius;
}
}
}
.hero .navbar,
body > .navbar {
border-radius: 0;
}
.pagination-link,
.pagination-next,
.pagination-previous {
border-width: $border-width;
}
.panel-block,
.panel-heading,
.panel-tabs {
border-width: $border-width;
&:first-child {
border-top-width: $border-width;
}
}
.panel-heading {
font-weight: $weight-bold;
}
.panel-tabs {
a {
border-width: $border-width;
margin-bottom: -$border-width;
&.is-active {
border-bottom-color: $link-active;
}
}
}
.panel-block {
&:hover {
color: $link-hover;
.panel-icon {
color: $link-hover;
}
}
&.is-active {
.panel-icon {
color: $link-active;
}
}
}
.tabs {
a {
border-bottom-width: $border-width;
margin-bottom: -$border-width;
}
ul {
border-bottom-width: $border-width;
}
&.is-boxed {
a {
border-width: $border-width;
}
li.is-active a {
background-color: darken($grey-darker, 4);
}
}
&.is-toggle {
li a {
border-width: $border-width;
margin-bottom: 0;
}
li + li {
margin-left: -$border-width;
}
}
}
.hero {
// Colors
@each $name, $pair in $colors {
$color: nth($pair, 1);
$color-invert: nth($pair, 2);
&.is-#{$name} {
.navbar {
.navbar-dropdown {
.navbar-item:hover {
background-color: $navbar-dropdown-item-hover-background-color;
}
}
}
}
}
}

View File

@@ -0,0 +1,114 @@
$grey-lighter: #dbdee0;
$grey-light: #8c9b9d;
$grey: darken($grey-light, 18);
$grey-dark: darken($grey, 18);
$grey-darker: darken($grey, 23);
$orange: #e67e22;
$yellow: #f1b70e;
$green: #2ecc71;
$turquoise: #26a8a2;
$blue: #3498db;
$purple: #8e44ad;
$red: #e74c3c;
$white-ter: #ecf0f1;
$primary: $turquoise;
$yellow-invert: #fff;
$family-sans-serif: "Gravity Regular", "Lato", -apple-system, BlinkMacSystemFont, "Segoe UI",
"Helvetica Neue", "Helvetica", "Arial", sans-serif;
$family-monospace: "Inconsolata", "Consolas", "Monaco", monospace;
$radius-small: 3px;
$radius: 0.4em;
$radius-large: 8px;
$size-6: 15px;
$size-7: 0.85em;
$title-weight: 500;
$subtitle-weight: 400;
$subtitle-color: $grey-dark;
$border-width: 2px;
$border: $grey;
$body-background-color: darken($grey-darker, 4);
$body-size: 15px;
$background: $grey-darker;
$footer-background-color: $background;
$button-background-color: $background;
$button-border-color: lighten($button-background-color, 15);
$title-color: #fff;
$subtitle-color: $grey-light;
$subtitle-strong-color: $grey-light;
$text: #fff;
$text-light: lighten($text, 10);
$text-strong: darken($text, 5);
$box-color: $text;
$box-background-color: $grey-dark;
$box-shadow: none;
$link: $turquoise;
$link-hover: lighten($link, 5);
$link-focus: darken($link, 5);
$link-active: darken($link, 5);
$link-focus-border: $grey-light;
$button-color: $primary;
$button-hover-color: darken($text, 5); // text-dark
$button-focus: darken($text, 5); // text-dark
$button-active-color: darken($text, 5); // text-dark
$button-disabled-background-color: $grey-light;
$control-height: 2.5em;
$input-color: $grey-darker;
$input-icon-color: $grey;
$input-icon-active-color: $input-color;
$input-hover-color: $grey-light;
$input-disabled-background-color: $grey-light;
$input-disabled-border: $grey-lighter;
$table-color: $text;
$table-head: $grey-lighter;
$table-background-color: $grey-dark;
$table-cell-border: 1px solid $grey;
$table-row-hover-background-color: $grey-darker;
$table-striped-row-even-background-color: $grey-darker;
$table-striped-row-even-hover-background-color: lighten($grey-darker, 2);
$pagination-color: $link;
$pagination-border-color: $border;
$navbar-height: 4rem;
$navbar-background-color: $primary;
$navbar-item-color: $text;
$navbar-item-hover-color: $link;
$navbar-item-hover-background-color: transparent;
$navbar-item-active-color: $link;
$navbar-dropdown-arrow: #fff;
$navbar-divider-background-color: rgba(0, 0, 0, 0.2);
$navbar-dropdown-border-top: 1px solid $navbar-divider-background-color;
$navbar-dropdown-background-color: $primary;
$navbar-dropdown-item-hover-color: $grey-lighter;
$navbar-dropdown-item-hover-background-color: transparent;
$navbar-dropdown-item-active-background-color: transparent;
$navbar-dropdown-item-active-color: $link;
$dropdown-content-background-color: $background;
$dropdown-item-color: $text;
$progress-value-background-color: $grey-lighter;
$file-cta-background-color: $grey-darker;
$progress-bar-background-color: $grey-dark;
$panel-heading-background-color: $grey-dark;
$control-label: $grey-lighter;

View File

@@ -0,0 +1,6 @@
@import "~bulma/sass/utilities/_all";
@import "variables";
@import "~bulma";
@import "~buefy/src/scss/buefy";
@import "overrides";
// @import "~/node_modules/material-design-icons/iconfont/material-icons.css";

View File

@@ -1,6 +1,7 @@
<template> <template>
<div> <div>
<b-button @click="broadcastStatus">Force status update</b-button> <b-button @click="broadcastStatus" icon-left="sync">Force status update</b-button>
<hr>
<b-table :data="usersList" striped hoverable> <b-table :data="usersList" striped hoverable>
<template slot-scope="props"> <template slot-scope="props">
<b-table-column field="name" label="Name"> <b-table-column field="name" label="Name">
@@ -16,7 +17,7 @@
</b-table-column> </b-table-column>
<b-table-column> <b-table-column>
<b-button @click="kickUser" icon-left="karate" type="is-dark"/> <b-button @click="kickUser(props.row.name)" icon-left="karate" type="is-dark"/>
</b-table-column> </b-table-column>
</template> </template>
</b-table> </b-table>
@@ -35,8 +36,8 @@ export default {
broadcastStatus () { broadcastStatus () {
this.$store.dispatch('rtc/broadcast', { message: this.$store.state.room.roomStatus, type: 'status' }) this.$store.dispatch('rtc/broadcast', { message: this.$store.state.room.roomStatus, type: 'status' })
}, },
kickUser () { kickUser (target) {
this.$store.dispatch('rtc/kick', target)
} }
} }
} }

View File

@@ -1,5 +1,5 @@
<template> <template>
<div> <div class="invite">
<h1 class="subtitle">{{roomCode}}</h1> <h1 class="subtitle">{{roomCode}}</h1>
<qrcode :value="roomCode" :options="{ width: 200 }"/> <qrcode :value="roomCode" :options="{ width: 200 }"/>
</div> </div>
@@ -21,3 +21,9 @@ export default {
} }
} }
</script> </script>
<style local>
.invite {
text-align: center;
}
</style>

View File

@@ -2,12 +2,14 @@
<div> <div>
<youtube <youtube
ref="youtube" ref="youtube"
v-bind:fitParent="true"
:video-id="roomStatus.current.linkID" :video-id="roomStatus.current.linkID"
:player-vars="playerVars" :player-vars="playerVars"
@playing="roomStatus.player.playing"> @playing="roomStatus.player.playing">
</youtube> </youtube>
<hr>
<b-field position="is-centered"> <b-field position="is-centered">
<b-button class="playerButton" @click="play" icon-right="play"/> <b-button class="playerButton" @click="play" :icon-right="roomStatus.player.playing ? 'pause' : 'play'"/>
<b-button class="playerButton" @click="mute" icon-right="volume-mute"/> <b-button class="playerButton" @click="mute" icon-right="volume-mute"/>
<b-button class="playerButton" @click="skip" icon-right="skip-next" v-if="isAdmin"/> <b-button class="playerButton" @click="skip" icon-right="skip-next" v-if="isAdmin"/>
<b-slider class="playerVolume" :min="0" :max="100" :value="100" @change="volume"/> <b-slider class="playerVolume" :min="0" :max="100" :value="100" @change="volume"/>
@@ -22,7 +24,7 @@
:disabled="!isAdmin" :disabled="!isAdmin"
@change="seek"/> @change="seek"/>
</b-field> </b-field>
<h2 class="subtitle is-6">{{convertTimeCode(roomStatus.player.timeCode)}} / {{convertTimeCode(roomStatus.player.timeLength)}}</h2> <h2 class="subtitle is-6 time">{{convertTimeCode(roomStatus.player.timeCode)}} / {{convertTimeCode(roomStatus.player.timeLength)}}</h2>
</div> </div>
</template> </template>
@@ -43,14 +45,14 @@ export default {
playerVars () { playerVars () {
const adminVars = { const adminVars = {
autoplay: 1, autoplay: 1,
controls: 1, controls: 0,
disablekb: 0, disablekb: 0,
modestbranding: 1, modestbranding: 1,
rel: 0 rel: 0
} }
const userVars = { const userVars = {
autoplay: 1, autoplay: 1,
controls: 1, controls: 0,
disablekb: 1, disablekb: 1,
modestbranding: 1, modestbranding: 1,
rel: 0 rel: 0
@@ -60,7 +62,7 @@ export default {
}, },
mounted () { mounted () {
this.player.addEventListener('onStateChange', this.playerStateChange) this.player.addEventListener('onStateChange', this.playerStateChange)
setInterval(this.updateTimeCode, 1000) // setInterval(this.updateTimeCode, 1000)
}, },
watch: { watch: {
roomStatus: function (status) { roomStatus: function (status) {
@@ -108,8 +110,10 @@ export default {
if (this.settings.playLink) this.$store.dispatch('room/setTimeCode', await this.player.getCurrentTime()) if (this.settings.playLink) this.$store.dispatch('room/setTimeCode', await this.player.getCurrentTime())
}, },
convertTimeCode (timeCode) { convertTimeCode (timeCode) {
const minutes = Math.round(timeCode / 60) var minutes = Math.round(timeCode / 60)
const seconds = Math.round(timeCode % 60) var seconds = Math.round(timeCode % 60)
if (minutes < 10) minutes = '0' + minutes
if (seconds < 10) seconds = '0' + seconds
return minutes + ':' + seconds return minutes + ':' + seconds
} }
} }
@@ -131,4 +135,8 @@ export default {
margin-right: 30px; margin-right: 30px;
max-width: 150px; max-width: 150px;
} }
.time {
text-align: center;
}
</style> </style>

View File

@@ -1,6 +1,7 @@
<template> <template>
<div> <div>
<b-button icon-left="plus" @click="addLinkPrompt">Add link</b-button> <b-button icon-left="plus" @click="addLinkPrompt">Add link</b-button>
<hr>
<b-table :data="roomStatus.playlist" striped hoverable default-sort="vote"> <b-table :data="roomStatus.playlist" striped hoverable default-sort="vote">
<template slot-scope="props"> <template slot-scope="props">
<b-table-column field="title" label="Title"> <b-table-column field="title" label="Title">
@@ -20,8 +21,9 @@
</b-table-column> </b-table-column>
<b-table-column> <b-table-column>
<b-button v-if="hasVoted(props.row)" icon-left="arrow-down-bold-outline" type="is-dark" @click="vote (props.row.link, props.row.linkID, false)"/> <b-button v-if="hasVoted(props.row)" icon-left="arrow-down-bold-outline" type="is-primary" @click="vote (props.row.link, props.row.linkID, false)"/>
<b-button v-else icon-left="arrow-up-bold-outline" type="is-dark" @click="vote (props.row.link, props.row.linkID, true)"/> <b-button v-else icon-left="arrow-up-bold-outline" type="is-primary" @click="vote (props.row.link, props.row.linkID, true)"/>
<b-button v-if="isAdmin" class="actionButton" icon-left="delete-forever" type="is-danger" @click="removePlay (props.row.linkID)"/>
</b-table-column> </b-table-column>
</template> </template>
</b-table> </b-table>
@@ -45,25 +47,27 @@ export default {
message: 'Add a youtube link', message: 'Add a youtube link',
trapFocus: true, trapFocus: true,
inputAttrs: { inputAttrs: {
placeholder: 'https://www.youtube.com/watch?v=YItIK09bpKk', placeholder: 'https://www.youtube.com/watch?v=YItIK09bpKk'
minlength: 10
}, },
cancelText: 'Nah', cancelText: 'Nah',
confirmText: 'Add', confirmText: 'Add',
onConfirm: (link) => this.addLink(link) onConfirm: (link) => this.addLink(link)
}) })
}, },
addLink (link) { async addLink (link) {
const linkID = this.$youtube.getIdFromUrl(link) const linkID = this.$youtube.getIdFromUrl(link)
if (linkID === null) { if (linkID === null) {
this.$buefy.toast.open('Invalid youtube link') this.$buefy.toast.open('Invalid youtube link')
return return
} }
this.vote(link, linkID, true) const infos = await this.getInfos(linkID)
console.log(infos)
console.log(infos.title)
this.vote(infos.title, link, linkID, true)
}, },
vote (link, linkID, isPositive) { vote (title, link, linkID, isPositive) {
if (this.isAdmin) { if (this.isAdmin) {
this.$store.dispatch('room/vote', { link: link, linkID: linkID, isPositive: isPositive, voterName: this.$store.state.rtc.name }) this.$store.dispatch('room/vote', { title: title, link: link, linkID: linkID, isPositive: isPositive, voterName: this.$store.state.rtc.name })
} else { } else {
this.sendVote(link, linkID, isPositive) this.sendVote(link, linkID, isPositive)
} }
@@ -80,7 +84,20 @@ export default {
}, },
hasVoted (play) { hasVoted (play) {
return play.voters.includes(this.$store.state.rtc.name) return play.voters.includes(this.$store.state.rtc.name)
},
removePlay (linkID) {
this.$store.dispatch('room/removePlay', linkID)
},
async getInfos (linkID) {
const response = await fetch('http://noembed.com/embed?format=json&' + 'url=https://www.youtube.com/watch?v=' + linkID)
return await response.json()
} }
} }
} }
</script> </script>
<style local>
.actionButton {
margin-left: 10px;
}
</style>

View File

@@ -0,0 +1,21 @@
<template>
<div>
</div>
</template>
<script>
export default {
name: 'YTSearch',
methods: {
async search (query) {
const response = await fetch('https://www.googleapis.com/youtube/v3/search?q=' + query)
console.log(response)
}
}
}
</script>
<style>
</style>

View File

@@ -6,8 +6,8 @@ import store from './store'
import Buefy from 'buefy' import Buefy from 'buefy'
import VueYoutube from 'vue-youtube' import VueYoutube from 'vue-youtube'
import 'buefy/dist/buefy.css' // import 'buefy/dist/buefy.css'
// import './assets/style.scss' import './assets/style.scss'
Vue.use(Buefy) Vue.use(Buefy)
Vue.use(VueYoutube) Vue.use(VueYoutube)

View File

@@ -1,205 +0,0 @@
var name
var connections = new Map()
const configuration = {
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
}
const offerOptions = {
offerToReceiveAudio: 1,
offerToReceiveVideo: 1
}
function handleLogin (success) {
if (success === false) {
alert('try a different username')
} else {
loginDiv.style.display = 'none'
connectDiv.style.display = 'block'
}
}
async function createPeerConnection (target) {
console.log('CREATED PEER CONNECTION')
var connection = new RTCPeerConnection(configuration)
connections[target] = connection
connection.onicecandidate = function (event) {
if (event.candidate) {
send({
type: 'candidate',
name: name,
target: target,
candidate: event.candidate
})
}
}
connection.onnegotiationneeded = function () { handleNegotiationNeededEvent(target) }
connection.ontrack = function (event) { handleTrackEvent(event) }
connection.onsignalingstatechange = function () { handleSignalingStateChangeEvent(connection) }
connection.oniceconnectionstatechange = function () { handleICEConnectionStateChangeEvent(connection) }
connection.onicegatheringstatechange = function () { handleICEGatheringStateChangeEvent(connection) }
// window.setInterval(getConnectionStats, 1000)
}
function handleICEConnectionStateChangeEvent (connection) {
console.log('ICE CONNECTION CHANGE ' + connection.iceConnectionState)
}
function handleICEGatheringStateChangeEvent (connection) {
console.log('ICE GATHERING CHANGE ' + connection.iceGatheringState)
}
async function makeOffer (target) {
createPeerConnection(target)
var connection = connections[target]
var offer = await connection.createOffer()
send({
type: 'offer',
name: name,
target: target,
offer: offer
})
await connection.setLocalDescription(offer)
}
async function handleOffer (offer, target) {
console.log('GOT OFFER FROM ' + target)
await createPeerConnection(target)
var connection = connections[target]
await connection.setRemoteDescription(new RTCSessionDescription(offer))
if (stream) {
console.log('STREAM DETECTED')
stream.getTracks().forEach((track) => {
console.log('ADDED TRACK')
connection.addTrack(track, stream)
})
}
var answer = await connection.createAnswer()
await connection.setLocalDescription(answer)
send({
type: 'answer',
name: name,
target: target,
answer: answer
})
for (let user of connections.keys()) {
console.log(user)
}
console.log('CONNECTION SIZE ' + connections.size)
videoTitle.innerHTML = name + ' | ' + connections.size + ' users connected'
}
async function handleAnswer (answer, target) {
console.log('GOT ANSWER FROM ' + target)
var connection = connections[target]
await connection.setRemoteDescription(new RTCSessionDescription(answer))
}
async function handleCandidate (candidate, target) {
console.log('GOT CANDIDATE FROM ' + target)
var connection = connections[target]
await connection.addIceCandidate(new RTCIceCandidate(candidate))
}
async function handleNegotiationNeededEvent (target) {
console.log('NEGOTIATION NEEDED FROM ' + target)
var connection = connections[target]
var offer = await connection.createOffer(offerOptions)
await connection.setLocalDescription(offer)
send({
type: 'video-offer',
name: name,
target: target,
sdp: connection.localDescription
})
}
function handleLeave () {
connections.forEach((connection) => {
connection.close()
connection = null
})
connections = new Map()
remoteVideo.pause()
remoteVideo.src = null
}
async function handleVideoOffer (sdp, target) {
console.log('GOT VIDEO OFFER FROM ' + target)
await createPeerConnection(target)
var connection = connections[target]
await connection.setRemoteDescription(new RTCSessionDescription(sdp))
if (stream) {
console.log('STREAM DETECTED')
stream.getTracks().forEach((track) => {
console.log('ADDED TRACK')
connection.addTrack(track, stream)
})
}
var answer = await connection.createAnswer()
await connection.setLocalDescription(answer)
send({
type: 'video-answer',
name: name,
target: target,
sdp: answer
})
// var keys = connections.keys().next().value
videoTitle.innerHTML = name + ' | connected to ' + target
}
async function handleVideoAnswer(sdp, target) {
console.log('GOT VIDEO ANSWER FROM ' + target)
var connection = connections[target]
await connection.setRemoteDescription(new RTCSessionDescription(sdp))
}
async function handleSignalingStateChangeEvent (connection) {
console.log('STATE CHANGED TO : ' + connection.signalingState)
switch(connection.signalingState) {
case 'closed':
await connection.close()
break
}
}
function handleTrackEvent (event) {
console.log('GOT TRACK')
remoteVideo.srcObject = event.streams[0]
videoDiv.style.display = 'block'
loadDiv.style.display = 'none'
}
function getConnectionStats () {
connections.forEach((connection, target) => {
console.log('[' + target + '] ' + connection.connectionState)
})
}
export const rtc = {
send
}

View File

@@ -1,92 +0,0 @@
/*
const loginDiv = document.querySelector('#loginDiv')
const loginInput = document.querySelector('#loginInput')
const loginBt = document.querySelector('#loginBt')
const connectDiv = document.querySelector('#connectDiv')
const callInput = document.querySelector('#callInput')
const callDatalist = document.querySelector('#callDatalist')
const callBt = document.querySelector('#callBt')
const videoInput = document.querySelector('#videoInput')
const videoDiv = document.querySelector('#videoDiv')
const videoTitle = document.querySelector('#videoTitle')
const remoteVideo = document.querySelector('#video')
const disconnectBt = document.querySelector('#disconnectBt')
const loadDiv = document.querySelector('#loadDiv')
const titleDiv = document.querySelector('#titleDiv')
var stream
var users
loginDiv.style.display = 'block'
loginBt.addEventListener('click', function (event) {
name = loginInput.value
if (name.length > 0) {
send({
type: 'login',
name: name
})
}
})
callBt.addEventListener('click', function () {
var callToUsername = callInput.value;
if (callToUsername.length > 0) {
makeOffer(callToUsername)
loadDiv.style.display = 'block'
titleDiv.style.display = 'none'
connectDiv.style.display = 'none'
}
})
disconnectBt.addEventListener('click', function () {
send({
type: 'leave',
name: name
})
handleLeave()
videoDiv.style.display = 'none'
loginDiv.style.display = 'block'
titleDiv.style.display = 'block'
})
videoInput.addEventListener('change', function (event) {
remoteVideo.src = URL.createObjectURL(this.files[0])
videoDiv.style.display = 'block'
connectDiv.style.display = 'none'
titleDiv.style.display = 'none'
videoTitle.innerHTML = name + ' | ' + connections.size + ' users connected'
})
remoteVideo.onplay = function () {
console.log('ADD STREAM')
if (remoteVideo.mozCaptureStream()) stream = remoteVideo.mozCaptureStream()
else stream = remoteVideo.captureStream()
}
function handleUserlist(list) {
console.log('GOT USER LIST '+list)
users = Array.from(list)
console.log(' users '+users)
console.log(typeof users)
console.log(' users '+users)
callDatalist.innerHTML = ''
users.forEach(user => {
if(user != name) callDatalist.innerHTML += '<option value="'+user+'"/>'
})
}
function handleError(message) {
console.log('Error '+message)
alert(
'AWWW FUCK \n\n'
+message
+'\n\nYou should probably reload the page')
}
*/

View File

@@ -1,66 +0,0 @@
// const conn = new WebSocket('wss://oozik.gltronic.ovh/')
const conn = new WebSocket('wss://localhost:8080')
conn.onopen = function () {
console.log('Connected to the signaling server')
}
conn.onmessage = function (msg) {
console.log('Got message', msg.data)
var data = JSON.parse(msg.data)
switch (data.type) {
case 'login':
handleLogin(data.success)
break
case 'offer':
handleOffer(data.offer, data.name)
break
case 'answer':
handleAnswer(data.answer, data.name)
break
case 'candidate':
handleCandidate(data.candidate, data.name)
break
case 'userlist':
handleUserlist(data.users)
break
case 'leave':
handleLeave()
break
case 'video-offer':
handleVideoOffer(data.sdp, data.name)
break
case 'video-answer':
handleVideoAnswer(data.sdp, data.name)
break
case 'error':
handleError(data.message)
break
default:
break
}
}
conn.onerror = function (err) {
console.log('Got error', err)
}
function send (message) {
console.log('Sended message', message)
conn.send(JSON.stringify(message))
}
export const signal = {
send
}

View File

@@ -38,10 +38,11 @@ const actions = {
setTimeCode ({ commit }, timeCode) { setTimeCode ({ commit }, timeCode) {
commit('SET_TIMECODE', timeCode) commit('SET_TIMECODE', timeCode)
}, },
vote ({ commit, dispatch, state }, { link, linkID, isPositive, voterName }) { vote ({ commit, dispatch, state }, { title, link, linkID, isPositive, voterName }) {
console.log('vote on ' + link + ' | ' + linkID + ' (' + isPositive + ') by ' + voterName) console.log('vote on ' + link + ' | ' + linkID + ' (' + isPositive + ') by ' + voterName)
if (isPositive) { if (isPositive) {
commit('ADD_VOTE', { commit('ADD_VOTE', {
title: title,
linkID: linkID, linkID: linkID,
link: link, link: link,
voterName: voterName voterName: voterName
@@ -54,6 +55,10 @@ const actions = {
} }
dispatch('rtc/broadcast', { message: state.roomStatus, type: 'status' }, { root: true }) dispatch('rtc/broadcast', { message: state.roomStatus, type: 'status' }, { root: true })
}, },
removePlay ({ commit, dispatch, state }, linkID) {
commit('REMOVE_PLAY', linkID)
dispatch('rtc/broadcast', { message: state.roomStatus, type: 'status' }, { root: true })
},
setCurrent ({ commit, dispatch }, { playerStatus, timeCode, timeLength, title }) { setCurrent ({ commit, dispatch }, { playerStatus, timeCode, timeLength, title }) {
switch (playerStatus) { switch (playerStatus) {
case 0: case 0:
@@ -114,10 +119,11 @@ const mutations = {
SET_CURRENTTITLE (state, title) { SET_CURRENTTITLE (state, title) {
state.roomStatus.current.title = title state.roomStatus.current.title = title
}, },
ADD_VOTE (state, { link, linkID, voterName }) { ADD_VOTE (state, { title, link, linkID, voterName }) {
var play = state.roomStatus.playlist.find(play => play.linkID === linkID) var play = state.roomStatus.playlist.find(play => play.linkID === linkID)
if (play === undefined) { if (play === undefined) {
play = { play = {
title: title,
link: link, link: link,
linkID: linkID, linkID: linkID,
votes: 1, votes: 1,
@@ -131,6 +137,10 @@ const mutations = {
play.votes++ play.votes++
play.voters.push(voterName) play.voters.push(voterName)
} }
state.roomStatus.playlist.sort((a, b) => {
return b.votes - a.votes
})
}, },
REMOVE_VOTE (state, { linkID, voterName }) { REMOVE_VOTE (state, { linkID, voterName }) {
var play = state.roomStatus.playlist.find(play => play.linkID === linkID) var play = state.roomStatus.playlist.find(play => play.linkID === linkID)
@@ -140,12 +150,23 @@ const mutations = {
play.voters.splice(index, 1) play.voters.splice(index, 1)
} }
if (play.vote === 0) { if (play.votes === 0) {
const index = state.roomStatus.playlist.indexOf(play) const index = state.roomStatus.playlist.indexOf(play)
if (index > -1) { if (index > -1) {
state.roomStatus.playlist.splice(index, 1) state.roomStatus.playlist.splice(index, 1)
} }
} }
state.roomStatus.playlist.sort((a, b) => {
return b.votes - a.votes
})
},
REMOVE_PLAY (state, linkID) {
var play = state.roomStatus.playlist.find(play => play.linkID === linkID)
const index = state.roomStatus.playlist.indexOf(play)
if (index > -1) {
state.roomStatus.playlist.splice(index, 1)
}
}, },
CURRENT_END (state) { CURRENT_END (state) {
if (state.roomStatus.playlist.length === 0) { if (state.roomStatus.playlist.length === 0) {

View File

@@ -39,6 +39,9 @@ const actions = {
leave ({ commit }) { leave ({ commit }) {
commit('LEAVE') commit('LEAVE')
}, },
kick ({ commit }, target) {
commit('KICK', target)
},
broadcast ({ commit }, { message, type }) { broadcast ({ commit }, { message, type }) {
commit('BROADCAST', { message: message, type: type }) commit('BROADCAST', { message: message, type: type })
} }
@@ -129,6 +132,15 @@ const mutations = {
}) })
state.peers = [] state.peers = []
}, },
KICK (state, target) {
var peer = state.peers.find(peer => peer.name === target)
peer.dataChannel.close()
peer.connection.close()
const index = state.peers.indexOf(peer)
if (index > -1) {
state.peers.splice(index, 1)
}
},
BROADCAST (state, { message, type }) { BROADCAST (state, { message, type }) {
const data = JSON.stringify({ const data = JSON.stringify({
type: type, type: type,

10
docker-compose.yml Normal file
View File

@@ -0,0 +1,10 @@
version: '3'
services:
cloud32:
image: gltron/c32java
container_name: cloud32
ports:
- 8004:8181
volumes:
- /data/c32_data/:/data
restart: unless-stopped