AzuraCast/frontend/vue/components/Public/WebDJ/SettingsPanel.vue

289 lines
13 KiB
Vue

<template>
<div class="card settings">
<div class="card-header bg-primary-dark">
<h5 class="card-title">
{{ $gettext('WebDJ') }}
<br>
<small>{{ stationName }}</small>
</h5>
</div>
<div class="card-body pt-0">
<div class="form-row pb-4">
<div class="col-sm-12">
<ul class="nav nav-tabs card-header-tabs mt-0">
<li class="nav-item">
<a class="nav-link active" href="#settings" data-toggle="tab">
{{ $gettext('Settings') }}
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#metadata" data-toggle="tab">
{{ $gettext('Metadata') }}
</a>
</li>
</ul>
</div>
</div>
<div class="form-row">
<div class="col-sm-12">
<div class="tab-content mt-1">
<div class="tab-pane active" id="settings">
<div class="form-group">
<label class="mb-2">
{{ $gettext('Encoder') }}
</label>
<div class="controls">
<div class="custom-control custom-radio custom-control-inline">
<input id="encoder_mp3" type="radio" v-model="encoder" value="mp3"
class="custom-control-input">
<label for="encoder_mp3" class="custom-control-label">
{{ $gettext('MP3') }}
</label>
</div>
<div class="custom-control custom-radio custom-control-inline">
<input id="encoder_raw" type="radio" v-model="encoder" value="raw"
class="custom-control-input">
<label for="encoder_raw" class="custom-control-label">
{{ $gettext('Raw') }}
</label>
</div>
</div>
</div>
<div class="form-group">
<label for="select_samplerate" class="mb-2">
{{ $gettext('Sample Rate') }}
</label>
<div class="controls">
<select id="select_samplerate" class="form-control" v-model.number="samplerate">
<option value="8000">8 kHz</option>
<option value="11025">11.025 kHz</option>
<option value="12000">12 kHz</option>
<option value="16000">16 kHz</option>
<option value="22050">22.05 kHz</option>
<option value="24000">24 kHz</option>
<option value="32000">32 kHz</option>
<option value="44100">44.1 kHz</option>
<option value="48000">48 kHz</option>
</select>
</div>
</div>
<div class="form-group">
<label for="select_bitrate" class="mb-2">
{{ $gettext('Bit Rate') }}
</label>
<div class="controls">
<select id="select_bitrate" class="form-control" v-model.number="bitrate">
<option value="8">8 kbps</option>
<option value="16">16 kbps</option>
<option value="24">24 kbps</option>
<option value="32">32 kbps</option>
<option value="40">40 kbps</option>
<option value="48">48 kbps</option>
<option value="56">56 kbps</option>
<option value="64">64 kbps</option>
<option value="80">80 kbps</option>
<option value="96">96 kbps</option>
<option value="112">112 kbps</option>
<option value="128">128 kbps</option>
<option value="144">144 kbps</option>
<option value="160">160 kbps</option>
<option value="192">192 kbps</option>
<option value="224">224 kbps</option>
<option value="256">256 kbps</option>
<option value="320">320 kbps</option>
</select>
</div>
</div>
<div class="form-group">
<label class="mb-2">
{{ $gettext('DJ Credentials') }}
</label>
<div class="form-row">
<div class="col-6">
<input type="text" v-model="djUsername" class="form-control"
v-bind:placeholder="langDjUsername">
</div>
<div class="col-6">
<input type="password" v-model="djPassword" class="form-control"
v-bind:placeholder="langDjPassword">
</div>
</div>
</div>
<div class="form-group mb-0">
<div class="custom-control custom-checkbox">
<input id="use_async_worker" type="checkbox" v-model="asynchronous"
class="custom-control-input">
<label for="use_async_worker" class="custom-control-label">
{{ $gettext('Use Asynchronous Worker') }}
</label>
</div>
</div>
</div>
<div class="tab-pane" id="metadata">
<div class="form-group">
<label for="metadata_title" class="mb-2">
{{ $gettext('Title') }}
</label>
<div class="controls">
<input id="metadata_title" class="form-control" type="text" v-model="metadata.title"
v-bind:disabled="!isStreaming">
</div>
</div>
<div class="form-group">
<label for="metadata_artist" class="mb-2">
{{ $gettext('Artist') }}
</label>
<div class="controls">
<input id="metadata_artist" class="form-control" type="text"
v-model="metadata.artist" v-bind:disabled="!isStreaming">
</div>
</div>
<div class="form-group">
<button class="btn btn-primary" v-on:click="updateMetadata"
v-bind:disabled="!isStreaming">
{{ $gettext('Update Metadata') }}
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card-actions">
<button class="btn btn-success" v-on:click="startStreaming" v-if="!isStreaming">
{{ langStreamButton }}
</button>
<button class="btn btn-danger" v-on:click="stopStreaming" v-if="isStreaming">
{{ langStreamButton }}
</button>
<button class="btn" v-on:click="cue" v-bind:class="{ 'btn-primary': passThrough }">
{{ $gettext('Cue') }}
</button>
</div>
</div>
</template>
<script>
export default {
inject: ['getStream', 'resumeStream'],
data () {
return {
'isStreaming': false,
'djUsername': '',
'djPassword': '',
'bitrate': 256,
'samplerate': 44100,
'encoder': 'mp3',
'asynchronous': true,
'passThrough': false,
'metadata': {
'title': '',
'artist': ''
}
};
},
computed: {
langDjUsername () {
return this.$gettext('Username');
},
langDjPassword () {
return this.$gettext('Password');
},
langStreamButton () {
return (this.isStreaming)
? this.$gettext('Stop Streaming')
: this.$gettext('Start Streaming');
},
uri () {
return 'wss://' + this.djUsername + ':' + this.djPassword + '@' + this.baseUri;
}
},
props: {
stationName: String,
libUrls: Array,
baseUri: String
},
mounted () {
this.$root.$on('new-cue', this.onNewCue);
this.$root.$on('metadata-update', this.onMetadataUpdate);
},
methods: {
cue () {
this.resumeStream();
this.$root.$emit('new-cue', (this.passThrough) ? 'off' : 'master');
},
onNewCue (new_cue) {
this.passThrough = (new_cue === 'master');
this.getStream().webcast.setPassThrough(this.passThrough);
},
startStreaming () {
this.resumeStream();
let encoderClass;
switch (this.encoder) {
case 'mp3':
encoderClass = Webcast.Encoder.Mp3;
break;
case 'raw':
encoderClass = Webcast.Encoder.Raw;
}
let encoder = new encoderClass({
channels: 2,
samplerate: this.samplerate,
bitrate: this.bitrate
});
if (this.samplerate !== this.getStream().context.sampleRate) {
encoder = new Webcast.Encoder.Resample({
encoder: encoder,
type: Samplerate.LINEAR,
samplerate: this.getStream().context.sampleRate
});
}
if (this.asynchronous) {
encoder = new Webcast.Encoder.Asynchronous({
encoder: encoder,
scripts: this.libUrls
});
}
let socket = this.getStream().webcast.connectSocket(encoder, this.uri);
socket.addEventListener("open", () => {
this.$notifySuccess(this.$gettext('Live stream connected.'));
this.isStreaming = true;
this.updateMetadata(false);
});
socket.addEventListener("close", () => {
this.$notifyError(this.$gettext('Live stream disconnected.'));
this.isStreaming = false;
});
},
stopStreaming () {
this.getStream().webcast.close();
this.isStreaming = false;
},
updateMetadata(alert = true) {
this.$root.$emit('metadata-update', {
title: this.metadata.title,
artist: this.metadata.artist
});
if (alert) {
this.$notifySuccess(this.$gettext('Metadata updated!'));
}
},
onMetadataUpdate (new_metadata) {
this.metadata.title = new_metadata.title;
this.metadata.artist = new_metadata.artist;
return this.getStream().webcast.sendMetadata(new_metadata);
}
}
};
</script>